From 49044d0d4044960fbb96d47f51640bc5fa8004af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Jan 2025 16:57:30 +0100 Subject: [PATCH 001/537] Add support for trait associated items --- src/librustdoc/html/render/span_map.rs | 61 ++++++++++++------------ tests/rustdoc/jump-to-def-assoc-items.rs | 15 ++++++ 2 files changed, 46 insertions(+), 30 deletions(-) create mode 100644 tests/rustdoc/jump-to-def-assoc-items.rs diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 846d3ad310ce..ebbc61db688f 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -4,9 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ - ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, -}; +use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; @@ -189,31 +187,6 @@ impl SpanMapVisitor<'_> { self.matches.insert(span, link); } } - - fn handle_pat(&mut self, p: &Pat<'_>) { - let mut check_qpath = |qpath, hir_id| match qpath { - QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => { - self.infer_id(path.hir_id, Some(hir_id), qpath.span()); - } - QPath::Resolved(_, path) => self.handle_path(path), - _ => {} - }; - match p.kind { - PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p), - PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => { - check_qpath(qpath, p.hir_id) - } - PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => { - check_qpath(*qpath, *hir_id) - } - PatKind::Or(pats) => { - for pat in pats { - self.handle_pat(pat); - } - } - _ => {} - } - } } impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { @@ -231,8 +204,36 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } - fn visit_pat(&mut self, p: &Pat<'tcx>) { - self.handle_pat(p); + fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, span: Span) { + match *qpath { + QPath::TypeRelative(qself, path) => { + if matches!(path.res, Res::Err) { + let tcx = self.tcx; + let hir = tcx.hir(); + let body_id = hir.enclosing_body_owner(id); + let typeck_results = tcx.typeck_body(hir.body_owned_by(body_id).id()); + let path = rustc_hir::Path { + // We change the span to not include parens. + span: span.with_hi(path.ident.span.hi()), + res: typeck_results.qpath_res(qpath, id), + segments: &[], + }; + self.handle_path(&path); + } else { + self.infer_id(path.hir_id, Some(id), span); + } + + rustc_ast::visit::try_visit!(self.visit_ty(qself)); + self.visit_path_segment(path); + } + QPath::Resolved(maybe_qself, path) => { + self.handle_path(path); + + rustc_ast::visit::visit_opt!(self, visit_ty, maybe_qself); + self.visit_path(path, id) + } + _ => {} + } } fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { diff --git a/tests/rustdoc/jump-to-def-assoc-items.rs b/tests/rustdoc/jump-to-def-assoc-items.rs new file mode 100644 index 000000000000..1229c3631725 --- /dev/null +++ b/tests/rustdoc/jump-to-def-assoc-items.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +pub enum Ty { + Var, +} + +//@ has 'src/foo/jump-to-def-assoc-items.rs.html' +//@ has - '//a[@href="#6"]' 'Self::Var' +impl Ty { + fn f() { + let _ = Self::Var; + } +} From f1649a4e4379aa0f5eb1181ca8e04c7790c21e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2025 21:24:36 +0100 Subject: [PATCH 002/537] Better handling of paths in link to def feature --- src/librustdoc/html/highlight.rs | 120 +++++++++++------- src/librustdoc/html/render/span_map.rs | 70 ++++++---- tests/rustdoc/jump-to-def-assoc-items.rs | 53 +++++++- .../jump-to-def-doc-links-calls.rs | 4 +- tests/rustdoc/jump-to-def/jump-to-def-pats.rs | 10 +- .../jump-to-def/jump-to-non-local-method.rs | 7 +- .../check-source-code-urls-to-def.rs | 2 +- 7 files changed, 175 insertions(+), 91 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 272180fb9904..c88db697be1f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -1059,6 +1059,64 @@ fn string( } } +fn generate_link_to_def( + out: &mut impl Write, + text_s: &str, + klass: Class, + href_context: &Option>, + def_span: Span, + open_tag: bool, +) -> bool { + if let Some(href_context) = href_context + && let Some(href) = + href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| { + let context = href_context.context; + // FIXME: later on, it'd be nice to provide two links (if possible) for all items: + // one to the documentation page and one to the source definition. + // FIXME: currently, external items only generate a link to their documentation, + // a link to their definition can be generated using this: + // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 + match href { + LinkFromSrc::Local(span) => { + context.href_from_span_relative(*span, &href_context.current_href) + } + LinkFromSrc::External(def_id) => { + format::href_with_root_path(*def_id, context, Some(href_context.root_path)) + .ok() + .map(|(url, _, _)| url) + } + LinkFromSrc::Primitive(prim) => format::href_with_root_path( + PrimitiveType::primitive_locations(context.tcx())[prim], + context, + Some(href_context.root_path), + ) + .ok() + .map(|(url, _, _)| url), + LinkFromSrc::Doc(def_id) => { + format::href_with_root_path(*def_id, context, Some(href_context.root_path)) + .ok() + .map(|(doc_link, _, _)| doc_link) + } + } + }) + { + if !open_tag { + // We're already inside an element which has the same klass, no need to give it + // again. + write!(out, "{text_s}").unwrap(); + } else { + let klass_s = klass.as_html(); + if klass_s.is_empty() { + write!(out, "{text_s}").unwrap(); + } else { + write!(out, "{text_s}").unwrap(); + } + } + return true; + } + false +} + /// This function writes `text` into `out` with some modifications depending on `klass`: /// /// * If `klass` is `None`, `text` is written into `out` with no modification. @@ -1088,10 +1146,14 @@ fn string_without_closing_tag( return Some(""); }; + let mut added_links = false; let mut text_s = text.to_string(); if text_s.contains("::") { + let mut span = def_span.with_hi(def_span.lo()); text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| { + span = span.with_hi(span.hi() + BytePos(t.len() as _)); match t { + "::" => write!(&mut path, "::"), "self" | "Self" => write!( &mut path, "{t}", @@ -1104,58 +1166,24 @@ fn string_without_closing_tag( klass = Class::KeyWord.as_html(), ) } - t => write!(&mut path, "{t}"), + t => { + if !t.is_empty() + && generate_link_to_def(&mut path, t, klass, href_context, span, open_tag) + { + added_links = true; + write!(&mut path, "") + } else { + write!(&mut path, "{t}") + } + } } .expect("Failed to build source HTML path"); + span = span.with_lo(span.lo() + BytePos(t.len() as _)); path }); } - if let Some(href_context) = href_context - && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span) - && let Some(href) = { - let context = href_context.context; - // FIXME: later on, it'd be nice to provide two links (if possible) for all items: - // one to the documentation page and one to the source definition. - // FIXME: currently, external items only generate a link to their documentation, - // a link to their definition can be generated using this: - // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 - match href { - LinkFromSrc::Local(span) => { - context.href_from_span_relative(*span, &href_context.current_href) - } - LinkFromSrc::External(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|(url, _, _)| url) - } - LinkFromSrc::Primitive(prim) => format::href_with_root_path( - PrimitiveType::primitive_locations(context.tcx())[prim], - context, - Some(href_context.root_path), - ) - .ok() - .map(|(url, _, _)| url), - LinkFromSrc::Doc(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|(doc_link, _, _)| doc_link) - } - } - } - { - if !open_tag { - // We're already inside an element which has the same klass, no need to give it - // again. - write!(out, "{text_s}").unwrap(); - } else { - let klass_s = klass.as_html(); - if klass_s.is_empty() { - write!(out, "{text_s}").unwrap(); - } else { - write!(out, "{text_s}").unwrap(); - } - } + if !added_links && generate_link_to_def(out, &text_s, klass, href_context, def_span, open_tag) { return Some(""); } if !open_tag { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index ebbc61db688f..342cf5073f71 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -65,7 +65,7 @@ struct SpanMapVisitor<'tcx> { impl SpanMapVisitor<'_> { /// This function is where we handle `hir::Path` elements and add them into the "span map". - fn handle_path(&mut self, path: &rustc_hir::Path<'_>) { + fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: bool) { match path.res { // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`. // Would be nice to support them too alongside the other `DefKind` @@ -77,24 +77,36 @@ impl SpanMapVisitor<'_> { LinkFromSrc::External(def_id) }; // In case the path ends with generics, we remove them from the span. - let span = path - .segments - .last() - .map(|last| { - // In `use` statements, the included item is not in the path segments. - // However, it doesn't matter because you can't have generics on `use` - // statements. - if path.span.contains(last.ident.span) { - path.span.with_hi(last.ident.span.hi()) - } else { - path.span - } - }) - .unwrap_or(path.span); + let span = if only_use_last_segment + && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span) + { + path_span + } else { + path.segments + .last() + .map(|last| { + // In `use` statements, the included item is not in the path segments. + // However, it doesn't matter because you can't have generics on `use` + // statements. + if path.span.contains(last.ident.span) { + path.span.with_hi(last.ident.span.hi()) + } else { + path.span + } + }) + .unwrap_or(path.span) + }; self.matches.insert(span, link); } Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => { - self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span))); + let path_span = if only_use_last_segment + && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span) + { + path_span + } else { + path.span + }; + self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span))); } Res::PrimTy(p) => { // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. @@ -200,37 +212,41 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { if self.handle_macro(path.span) { return; } - self.handle_path(path); + self.handle_path(path, false); intravisit::walk_path(self, path); } - fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, span: Span) { + fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) { match *qpath { QPath::TypeRelative(qself, path) => { if matches!(path.res, Res::Err) { let tcx = self.tcx; - let hir = tcx.hir(); - let body_id = hir.enclosing_body_owner(id); - let typeck_results = tcx.typeck_body(hir.body_owned_by(body_id).id()); + let body_id = tcx.hir_enclosing_body_owner(id); + let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id()); let path = rustc_hir::Path { // We change the span to not include parens. - span: span.with_hi(path.ident.span.hi()), + span: path.ident.span, res: typeck_results.qpath_res(qpath, id), segments: &[], }; - self.handle_path(&path); + self.handle_path(&path, false); } else { - self.infer_id(path.hir_id, Some(id), span); + self.infer_id(path.hir_id, Some(id), path.ident.span); } - rustc_ast::visit::try_visit!(self.visit_ty(qself)); + if let Some(qself) = qself.try_as_ambig_ty() { + rustc_ast::visit::try_visit!(self.visit_ty(qself)); + } self.visit_path_segment(path); } QPath::Resolved(maybe_qself, path) => { - self.handle_path(path); + self.handle_path(path, true); + let maybe_qself = maybe_qself.and_then(|maybe_qself| maybe_qself.try_as_ambig_ty()); rustc_ast::visit::visit_opt!(self, visit_ty, maybe_qself); - self.visit_path(path, id) + if !self.handle_macro(path.span) { + intravisit::walk_path(self, path); + } } _ => {} } diff --git a/tests/rustdoc/jump-to-def-assoc-items.rs b/tests/rustdoc/jump-to-def-assoc-items.rs index 1229c3631725..8cbf99062838 100644 --- a/tests/rustdoc/jump-to-def-assoc-items.rs +++ b/tests/rustdoc/jump-to-def-assoc-items.rs @@ -1,15 +1,54 @@ +// This test ensures that patterns also get a link generated. + //@ compile-flags: -Zunstable-options --generate-link-to-definition #![crate_name = "foo"] -pub enum Ty { - Var, +//@ has 'src/foo/jump-to-def-assoc-items.rs.html' + +pub trait Trait { + type T; +} +pub trait Another { + type T; + const X: u32; } -//@ has 'src/foo/jump-to-def-assoc-items.rs.html' -//@ has - '//a[@href="#6"]' 'Self::Var' -impl Ty { - fn f() { - let _ = Self::Var; +pub struct Foo; + +impl Foo { + pub fn new() -> Self { Foo } +} + +pub struct C; + +impl C { + pub fn wat() {} +} + +pub struct Bar; +impl Trait for Bar { + type T = Foo; +} +impl Another for Bar { + type T = C; + const X: u32 = 12; +} + +pub fn bar() { + //@ has - '//a[@href="#20"]' 'new' + ::T::new(); + //@ has - '//a[@href="#26"]' 'wat' + ::T::wat(); + + match 12u32 { + //@ has - '//a[@href="#14"]' 'X' + ::X => {} + _ => {} } } + +pub struct Far { + //@ has - '//a[@href="#10"]' 'T' + x: ::T, +} diff --git a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs index 618569787733..55e59f23b6f2 100644 --- a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs +++ b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs @@ -8,7 +8,7 @@ pub struct Bar; impl std::default::Default for Bar { - //@ has - '//a[@href="#20-22"]' 'Self::new' + //@ has - '//a[@href="#20-22"]' 'new' fn default() -> Self { Self::new() } @@ -16,7 +16,7 @@ impl std::default::Default for Bar { //@ has - '//a[@href="#8"]' 'Bar' impl Bar { - //@ has - '//a[@href="#24-26"]' 'Self::bar' + //@ has - '//a[@href="#24-26"]' 'bar' pub fn new()-> Self { Self::bar() } diff --git a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs index 147902b44cf5..852eba208db0 100644 --- a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs +++ b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs @@ -30,13 +30,13 @@ pub fn foo() -> Result<(), ()> { impl fmt::Display for MyEnum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - //@ has - '//a[@href="#12"]' 'Self::Ok' + //@ has - '//a[@href="#12"]' 'Ok' Self::Ok(_) => f.write_str("MyEnum::Ok"), - //@ has - '//a[@href="#13"]' 'MyEnum::Err' + //@ has - '//a[@href="#13"]' 'Err' MyEnum::Err(_) => f.write_str("MyEnum::Err"), - //@ has - '//a[@href="#14"]' 'Self::Some' + //@ has - '//a[@href="#14"]' 'Some' Self::Some(_) => f.write_str("MyEnum::Some"), - //@ has - '//a[@href="#15"]' 'Self::None' + //@ has - '//a[@href="#15"]' 'None' Self::None => f.write_str("MyEnum::None"), } } @@ -45,7 +45,7 @@ impl fmt::Display for MyEnum { impl X { fn p(&self) -> &str { match self { - //@ has - '//a[@href="#19"]' 'Self::A' + //@ has - '//a[@href="#19"]' 'A' Self::A => "X::A", } } diff --git a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs index e2f530425f0d..1d6d6b8d18fa 100644 --- a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs +++ b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs @@ -21,9 +21,10 @@ pub fn bar2(readable: T) { } pub fn bar() { - //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new' + //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html"]' 'AtomicIsize' + //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'new' let _ = AtomicIsize::new(0); - //@ has - '//a[@href="#48"]' 'local_private' + //@ has - '//a[@href="#49"]' 'local_private' local_private(); } @@ -39,7 +40,7 @@ pub fn macro_call() -> Result<(), ()> { } pub fn variant() { - //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Ordering::Less' + //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Less' let _ = Ordering::Less; //@ has - '//a[@href="{{channel}}/core/marker/struct.PhantomData.html"]' 'PhantomData' let _: PhantomData:: = PhantomData; diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs index d701b88bf9fd..a7b944fa2f6f 100644 --- a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs +++ b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs @@ -34,7 +34,7 @@ fn babar() {} // The 5 links to line 23 and the line 23 itself. //@ count - '//pre[@class="rust"]//a[@href="#23"]' 6 //@ has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' \ -// 'source_code::SourceCode' +// 'SourceCode' pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) { let x = 12; let y: Foo = Foo; From 1a6d6363d090961a1efe513d413f5b51ecd81ab8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 26 Jan 2025 21:50:50 +0100 Subject: [PATCH 003/537] Update to last rustc_hir Visitor changes --- src/librustdoc/html/render/span_map.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 342cf5073f71..505797ccc0b2 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; @@ -234,16 +234,13 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { self.infer_id(path.hir_id, Some(id), path.ident.span); } - if let Some(qself) = qself.try_as_ambig_ty() { - rustc_ast::visit::try_visit!(self.visit_ty(qself)); - } + rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself)); self.visit_path_segment(path); } QPath::Resolved(maybe_qself, path) => { self.handle_path(path, true); - let maybe_qself = maybe_qself.and_then(|maybe_qself| maybe_qself.try_as_ambig_ty()); - rustc_ast::visit::visit_opt!(self, visit_ty, maybe_qself); + rustc_ast::visit::visit_opt!(self, visit_ty_unambig, maybe_qself); if !self.handle_macro(path.span) { intravisit::walk_path(self, path); } From d528a49fd7c0447cc51406908fb13fe055d273aa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 4 May 2025 19:08:23 +0200 Subject: [PATCH 004/537] Fix panic if an item does not have a body --- src/librustdoc/html/render/span_map.rs | 32 ++++++++++++++++++-------- tests/rustdoc/jump-to-def-ice.rs | 24 +++++++++++++++++++ 2 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 tests/rustdoc/jump-to-def-ice.rs diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 505797ccc0b2..6906e6e30ff8 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; @@ -201,6 +201,17 @@ impl SpanMapVisitor<'_> { } } +// This is a reimplementation of `hir_enclosing_body_owner` which allows to fail without +// panicking. +fn hir_enclosing_body_owner(tcx: TyCtxt<'_>, hir_id: HirId) -> Option { + for (_, node) in tcx.hir_parent_iter(hir_id) { + if let Some((def_id, _)) = node.associated_body() { + return Some(def_id); + } + } + None +} + impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { type NestedFilter = nested_filter::All; @@ -221,15 +232,16 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { QPath::TypeRelative(qself, path) => { if matches!(path.res, Res::Err) { let tcx = self.tcx; - let body_id = tcx.hir_enclosing_body_owner(id); - let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id()); - let path = rustc_hir::Path { - // We change the span to not include parens. - span: path.ident.span, - res: typeck_results.qpath_res(qpath, id), - segments: &[], - }; - self.handle_path(&path, false); + if let Some(body_id) = hir_enclosing_body_owner(tcx, id) { + let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id()); + let path = rustc_hir::Path { + // We change the span to not include parens. + span: path.ident.span, + res: typeck_results.qpath_res(qpath, id), + segments: &[], + }; + self.handle_path(&path, false); + } } else { self.infer_id(path.hir_id, Some(id), path.ident.span); } diff --git a/tests/rustdoc/jump-to-def-ice.rs b/tests/rustdoc/jump-to-def-ice.rs new file mode 100644 index 000000000000..5578b9af3d74 --- /dev/null +++ b/tests/rustdoc/jump-to-def-ice.rs @@ -0,0 +1,24 @@ +// This test ensures that items with no body don't panic when generating +// jump to def links. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +//@ has 'src/foo/jump-to-def-ice.rs.html' + +pub trait A { + type T; + type U; +} + +impl A for () { + type T = Self::U; + type U = (); +} + +pub trait C { + type X; +} + +pub struct F(pub T::X); From 25e767b0ee95d21b62d2fb509809946005081d40 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 10 Aug 2025 15:49:22 +0200 Subject: [PATCH 005/537] Ignore impl associated types in jump to def feature --- src/librustdoc/html/render/span_map.rs | 8 +++++++- tests/rustdoc/jump-to-def-ice-assoc-types.rs | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc/jump-to-def-ice-assoc-types.rs diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 6906e6e30ff8..e5bdc2a941c8 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -205,7 +205,13 @@ impl SpanMapVisitor<'_> { // panicking. fn hir_enclosing_body_owner(tcx: TyCtxt<'_>, hir_id: HirId) -> Option { for (_, node) in tcx.hir_parent_iter(hir_id) { - if let Some((def_id, _)) = node.associated_body() { + // FIXME: associated type impl items don't have an associated body, so we don't handle + // them currently. + if let Node::ImplItem(impl_item) = node + && matches!(impl_item.kind, rustc_hir::ImplItemKind::Type(_)) + { + return None; + } else if let Some((def_id, _)) = node.associated_body() { return Some(def_id); } } diff --git a/tests/rustdoc/jump-to-def-ice-assoc-types.rs b/tests/rustdoc/jump-to-def-ice-assoc-types.rs new file mode 100644 index 000000000000..9915c53668f0 --- /dev/null +++ b/tests/rustdoc/jump-to-def-ice-assoc-types.rs @@ -0,0 +1,20 @@ +// This test ensures that associated types don't crash rustdoc jump to def. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition + + +#![crate_name = "foo"] + +//@ has 'src/foo/jump-to-def-ice-assoc-types.rs.html' + +pub trait Trait { + type Node; +} + +pub fn y() { + struct X(G); + + impl Trait for X { + type Node = G::Node; + } +} From 5fb947f650ef123ab91bb3456161f50f481adf9b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 26 Aug 2025 14:45:16 +0200 Subject: [PATCH 006/537] Add test. --- library/coretests/tests/fmt/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index 16f116d25901..11de632fb70c 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -12,6 +12,12 @@ fn test_lifetime() { let a = format_args!("hello {a} {a:?}"); assert_eq!(a.to_string(), "hello hello hello hello hello hello hello"); + // Check that temporaries as arguments are extended. + let b = format_args!("{}", String::new()); + let c = format_args!("{}{}", String::new(), String::new()); + assert_eq!(b.to_string(), ""); + assert_eq!(c.to_string(), ""); + // Without arguments, it should also work in consts. const A: std::fmt::Arguments<'static> = format_args!("hello"); assert_eq!(A.to_string(), "hello"); From aa9c8ceb73c88674a792719dee8bfbcbee22a360 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 26 Aug 2025 14:44:41 +0200 Subject: [PATCH 007/537] Remove 1-argument special case from format_args!(). The argument needs to be lifetime-extended, so this special case isn't actually perfectly equivalent to the general case. --- compiler/rustc_ast_lowering/src/format.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index ec9d26eb33f4..2871430030c4 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -487,26 +487,6 @@ fn expand_format_args<'hir>( // Generate: // [] (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[])))) - } else if argmap.len() == 1 && arguments.len() == 1 { - // Only one argument, so we don't need to make the `args` tuple. - // - // Generate: - // super let args = [::new_display(&arg)]; - let args = ctx.arena.alloc_from_iter(argmap.iter().map( - |(&(arg_index, ty), &placeholder_span)| { - let arg = &arguments[arg_index]; - let placeholder_span = - placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); - let arg = ctx.lower_expr(&arg.expr); - let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg)); - make_argument(ctx, placeholder_span, ref_arg, ty) - }, - )); - let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); - let args_ident = Ident::new(sym::args, macsp); - let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); - let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args)); - (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id))) } else { // Generate: // super let args = (&arg0, &arg1, &…); From bc13565de8a16c9ba0c0da51787dc60d254c6dfa Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 26 Aug 2025 14:46:03 +0200 Subject: [PATCH 008/537] Update tests. --- tests/coverage/issue-83601.cov-map | 34 ++--- tests/coverage/issue-84561.cov-map | 136 +++++++++--------- ...745-avoid-expr-from-macro-expansion.stderr | 6 +- tests/ui/issues/issue-27592.stderr | 12 +- tests/ui/suggestions/issue-97760.stderr | 7 +- tests/ui/unpretty/exhaustive.hir.stdout | 3 +- .../ui/unpretty/flattened-format-args.stdout | 3 +- 7 files changed, 96 insertions(+), 105 deletions(-) diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index d1d751ff24b8..e42b5591c0fb 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,30 +1,22 @@ Function name: issue_83601::main -Raw bytes (76): 0x[01, 01, 01, 05, 09, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 01, 00, 02] +Raw bytes (74): 0x[01, 01, 00, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-83601.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +Number of expressions: 0 Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) - = (c1 - c2) -- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (c1 - c2) -Highest counter ID seen: c1 +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 2b643ea599ed..e5bb1afdcc26 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -73,20 +73,20 @@ Number of file 0 mappings: 4 Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (409): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 02, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 00, 0c, 09, 00, 0f, 00, 15, 09, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 00, 10, 0d, 00, 13, 00, 2e, 0d, 02, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 00, 0c, 0d, 00, 0f, 00, 15, 0d, 01, 05, 00, 0f, 0d, 04, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 00, 0f, 1d, 02, 0c, 00, 13, 21, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (409): 0x[01, 01, 0a, 01, 05, 01, 09, 01, 0d, 11, 15, 1d, 21, 19, 1d, 19, 1d, 19, 1d, 27, 25, 1d, 21, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 01, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 04, 08, 00, 0f, 05, 01, 09, 00, 13, 02, 05, 09, 00, 13, 01, 05, 08, 00, 0f, 09, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 01, 03, 05, 00, 0f, 01, 01, 0c, 00, 13, 0d, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 11, 04, 05, 00, 0f, 11, 02, 0c, 00, 13, 15, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 19, 01, 0c, 00, 13, 1d, 01, 0d, 00, 17, 1d, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 21, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 25, 02, 05, 00, 0f, 25, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/issue-84561.rs Number of expressions: 10 -- expression 0 operands: lhs = Counter(3), rhs = Counter(4) -- expression 1 operands: lhs = Counter(3), rhs = Counter(5) -- expression 2 operands: lhs = Counter(3), rhs = Counter(6) -- expression 3 operands: lhs = Counter(7), rhs = Counter(8) -- expression 4 operands: lhs = Counter(10), rhs = Counter(11) -- expression 5 operands: lhs = Counter(9), rhs = Counter(10) -- expression 6 operands: lhs = Counter(9), rhs = Counter(10) -- expression 7 operands: lhs = Counter(9), rhs = Counter(10) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12) -- expression 9 operands: lhs = Counter(10), rhs = Counter(11) +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(3) +- expression 3 operands: lhs = Counter(4), rhs = Counter(5) +- expression 4 operands: lhs = Counter(7), rhs = Counter(8) +- expression 5 operands: lhs = Counter(6), rhs = Counter(7) +- expression 6 operands: lhs = Counter(6), rhs = Counter(7) +- expression 7 operands: lhs = Counter(6), rhs = Counter(7) +- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(9) +- expression 9 operands: lhs = Counter(7), rhs = Counter(8) Number of file 0 mappings: 77 - Code(Counter(0)) at (prev + 8, 1) to (start + 0, 11) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) @@ -94,85 +94,85 @@ Number of file 0 mappings: 77 - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12) -- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 48) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) -- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 36) - Code(Zero) at (prev + 0, 41) to (start + 0, 48) - Code(Zero) at (prev + 0, 51) to (start + 0, 65) - Code(Zero) at (prev + 0, 75) to (start + 0, 90) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 5, 9) to (start + 0, 13) - Code(Zero) at (prev + 3, 9) to (start + 0, 16) - Code(Zero) at (prev + 2, 13) to (start + 0, 27) - Code(Zero) at (prev + 2, 13) to (start + 0, 28) -- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 16) -- Code(Counter(3)) at (prev + 0, 19) to (start + 0, 46) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 12) -- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 21) -- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 8) to (start + 0, 15) -- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19) - = (c3 - c4) -- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15) -- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 19) + = (c0 - c1) +- Code(Counter(0)) at (prev + 5, 8) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 19) - Code(Zero) at (prev + 3, 13) to (start + 0, 29) - Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19) - = (c3 - c5) + = (c0 - c2) - Code(Zero) at (prev + 3, 13) to (start + 0, 29) -- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 19) +- Code(Counter(3)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19) - = (c3 - c6) -- Code(Counter(7)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 19) -- Code(Counter(8)) at (prev + 1, 13) to (start + 0, 19) + = (c0 - c3) +- Code(Counter(4)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(4)) at (prev + 2, 12) to (start + 0, 19) +- Code(Counter(5)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19) - = (c7 - c8) + = (c4 - c5) - Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15) - = (c10 + c11) -- Code(Counter(9)) at (prev + 1, 12) to (start + 0, 19) -- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 23) -- Code(Counter(10)) at (prev + 4, 13) to (start + 0, 19) + = (c7 + c8) +- Code(Counter(6)) at (prev + 1, 12) to (start + 0, 19) +- Code(Counter(7)) at (prev + 1, 13) to (start + 0, 23) +- Code(Counter(7)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23) - = (c9 - c10) + = (c6 - c7) - Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27) - = (c9 - c10) + = (c6 - c7) - Code(Zero) at (prev + 1, 21) to (start + 0, 27) - Code(Expression(7, Sub)) at (prev + 2, 21) to (start + 0, 27) - = (c9 - c10) -- Code(Counter(11)) at (prev + 4, 13) to (start + 0, 19) + = (c6 - c7) +- Code(Counter(8)) at (prev + 4, 13) to (start + 0, 19) - Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 25) - = ((c10 + c11) - c12) -- Code(Counter(12)) at (prev + 2, 5) to (start + 0, 15) -- Code(Counter(12)) at (prev + 3, 9) to (start + 0, 34) + = ((c7 + c8) - c9) +- Code(Counter(9)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(9)) at (prev + 3, 9) to (start + 0, 34) - Code(Zero) at (prev + 2, 5) to (start + 0, 15) - Code(Zero) at (prev + 3, 9) to (start + 0, 44) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) -Highest counter ID seen: c12 +Highest counter ID seen: c9 diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr index 3de317d2af6d..a78941f9e11b 100644 --- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr +++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr @@ -1,10 +1,10 @@ error[E0282]: type annotations needed - --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:22 + --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:5 | LL | println!("{:?}", []); - | ^^ cannot infer type + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type | - = 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) + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27592.stderr b/tests/ui/issues/issue-27592.stderr index c8649d82d745..f1de7b9e569d 100644 --- a/tests/ui/issues/issue-27592.stderr +++ b/tests/ui/issues/issue-27592.stderr @@ -1,3 +1,9 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/issue-27592.rs:16:14 + | +LL | write(|| format_args!("{}", String::from("Hello world"))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function + error[E0515]: cannot return value referencing temporary value --> $DIR/issue-27592.rs:16:14 | @@ -7,12 +13,6 @@ LL | write(|| format_args!("{}", String::from("Hello world"))); | | temporary value created here | returns a value referencing data owned by the current function -error[E0515]: cannot return reference to temporary value - --> $DIR/issue-27592.rs:16:14 - | -LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index 1084ea7c9e0e..c3cf7e13987b 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -1,11 +1,8 @@ error[E0277]: `::Item` doesn't implement `std::fmt::Display` - --> $DIR/issue-97760.rs:4:20 + --> $DIR/issue-97760.rs:4:19 | LL | println!("{x}"); - | -^- - | || - | |`::Item` cannot be formatted with the default formatter - | required by this formatting parameter + | ^^^ `::Item` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 924fb98ae18a..48dbb03b82a6 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -398,7 +398,8 @@ mod expressions { let expr; format_arguments::new_const(&[]); { - super let args = [format_argument::new_display(&expr)]; + super let args = (&expr,); + super let args = [format_argument::new_display(args.0)]; format_arguments::new_v1(&[""], &args) }; } diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index 0792dc10e946..233c9f1c91bd 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -11,7 +11,8 @@ fn main() { // Should flatten to println!("a 123 b {x} xyz\n"): { ::std::io::_print({ - super let args = [format_argument::new_display(&x)]; + super let args = (&x,); + super let args = [format_argument::new_display(args.0)]; format_arguments::new_v1(&["a 123 b ", " xyz\n"], &args) }); }; From 663ca24879a6ded2bd1dda8c6da916444f78e850 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 26 Aug 2025 15:54:59 +0200 Subject: [PATCH 009/537] Bless clippy tests. --- .../tests/ui/author/macro_in_closure.stdout | 32 ++++++++++++------- .../tests/ui/author/macro_in_loop.stdout | 28 ++++++++++------ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout index 49595e2fec25..786c61e0c018 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout @@ -10,34 +10,42 @@ if let StmtKind::Let(local) = stmt.kind && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 && let ExprKind::Block(block1, None) = args[0].kind - && block1.stmts.len() == 1 + && block1.stmts.len() == 2 && let StmtKind::Let(local1) = block1.stmts[0].kind && let Some(init1) = local1.init - && let ExprKind::Array(elements) = init1.kind + && let ExprKind::Tup(elements) = init1.kind && elements.len() == 1 - && let ExprKind::Call(func1, args1) = elements[0].kind - && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed - && args1.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind && name.as_str() == "args" + && let StmtKind::Let(local2) = block1.stmts[1].kind + && let Some(init2) = local2.init + && let ExprKind::Array(elements1) = init2.kind + && elements1.len() == 1 + && let ExprKind::Call(func1, args1) = elements1[0].kind + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed + && args1.len() == 1 + && let ExprKind::Field(object, field_name) = args1[0].kind + && field_name.as_str() == "0" + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local2.pat.kind + && name1.as_str() == "args" && let Some(trailing_expr) = block1.expr && let ExprKind::Call(func2, args2) = trailing_expr.kind && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed && args2.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind - && let ExprKind::Array(elements1) = inner1.kind - && elements1.len() == 2 - && let ExprKind::Lit(ref lit) = elements1[0].kind + && let ExprKind::Array(elements2) = inner1.kind + && elements2.len() == 2 + && let ExprKind::Lit(ref lit) = elements2[0].kind && let LitKind::Str(s, _) = lit.node && s.as_str() == "" - && let ExprKind::Lit(ref lit1) = elements1[1].kind + && let ExprKind::Lit(ref lit1) = elements2[1].kind && let LitKind::Str(s1, _) = lit1.node && s1.as_str() == "\n" && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind && block.expr.is_none() - && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind - && name1.as_str() == "print_text" + && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local.pat.kind + && name2.as_str() == "print_text" { // report your lint here } diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout index 4fc7b49464db..80717900b525 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout @@ -20,28 +20,36 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 && let ExprKind::Block(block2, None) = args[0].kind - && block2.stmts.len() == 1 + && block2.stmts.len() == 2 && let StmtKind::Let(local) = block2.stmts[0].kind && let Some(init) = local.init - && let ExprKind::Array(elements) = init.kind + && let ExprKind::Tup(elements) = init.kind && elements.len() == 1 - && let ExprKind::Call(func1, args1) = elements[0].kind - && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed - && args1.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind && name1.as_str() == "args" + && let StmtKind::Let(local1) = block2.stmts[1].kind + && let Some(init1) = local1.init + && let ExprKind::Array(elements1) = init1.kind + && elements1.len() == 1 + && let ExprKind::Call(func1, args1) = elements1[0].kind + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed + && args1.len() == 1 + && let ExprKind::Field(object, field_name) = args1[0].kind + && field_name.as_str() == "0" + && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local1.pat.kind + && name2.as_str() == "args" && let Some(trailing_expr) = block2.expr && let ExprKind::Call(func2, args2) = trailing_expr.kind && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed && args2.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind - && let ExprKind::Array(elements1) = inner1.kind - && elements1.len() == 2 - && let ExprKind::Lit(ref lit2) = elements1[0].kind + && let ExprKind::Array(elements2) = inner1.kind + && elements2.len() == 2 + && let ExprKind::Lit(ref lit2) = elements2[0].kind && let LitKind::Str(s, _) = lit2.node && s.as_str() == "" - && let ExprKind::Lit(ref lit3) = elements1[1].kind + && let ExprKind::Lit(ref lit3) = elements2[1].kind && let LitKind::Str(s1, _) = lit3.node && s1.as_str() == "\n" && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind From cee25947df4f0d3cb455810b64cd62c16d775109 Mon Sep 17 00:00:00 2001 From: sgasho Date: Wed, 27 Aug 2025 00:06:47 +0900 Subject: [PATCH 010/537] fix: Prevent invalid transformation in 'Replace match with if let' assist --- .../src/handlers/replace_if_let_with_match.rs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index dd244375dc91..3b815a467bc0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -328,7 +328,14 @@ fn pick_pattern_and_expr_order( (pat, pat2) => match (binds_name(sema, &pat), binds_name(sema, &pat2)) { (true, true) => return None, (true, false) => (pat, guard, expr, expr2), - (false, true) => (pat2, guard2, expr2, expr), + (false, true) => { + // This pattern triggers an invalid transformation. + // See issues #11373, #19443 + if let ast::Pat::IdentPat(_) = pat2 { + return None; + } + (pat2, guard2, expr2, expr) + } _ if is_sad_pat(sema, &pat) => (pat2, guard2, expr2, expr), (false, false) => (pat, guard, expr, expr2), }, @@ -1892,4 +1899,19 @@ fn main() { "#, ) } + + #[test] + fn test_replace_match_with_if_let_not_applicable_pat2_is_ident_pat() { + check_assist_not_applicable( + replace_match_with_if_let, + r" +fn test(a: i32) { + match$0 a { + 1 => code(), + other => code(other), + } +} +", + ) + } } From 23f1767c808d759ff683812581ca0e954d72c463 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 31 Aug 2025 17:03:46 +0000 Subject: [PATCH 011/537] allow taking address to union field --- .../rustc_mir_build/src/check_unsafety.rs | 15 ++++ .../miri/tests/pass/both_borrows/smallvec.rs | 2 +- tests/ui/union/union-unsafe.rs | 73 +++++++++++++++++++ tests/ui/union/union-unsafe.stderr | 54 +++++++++++--- 4 files changed, 132 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b5e165c75170..195d45c2c4c4 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -554,6 +554,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(self, &self.thir[arg]); return; } + + // Secondly, we allow raw borrows of union field accesses. Peel + // any of those off, and recurse normally on the LHS, which should + // reject any unsafe operations within. + let mut peeled = arg; + while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind + && let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind + && let ty::Adt(def, _) = &self.thir[lhs].ty.kind() + && def.is_union() + { + peeled = lhs; + } + visit::walk_expr(self, &self.thir[peeled]); + // And return so we don't recurse directly onto the union field access(es). + return; } ExprKind::Deref { arg } => { if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) = diff --git a/src/tools/miri/tests/pass/both_borrows/smallvec.rs b/src/tools/miri/tests/pass/both_borrows/smallvec.rs index f48815e37be3..fa5cfb03de2a 100644 --- a/src/tools/miri/tests/pass/both_borrows/smallvec.rs +++ b/src/tools/miri/tests/pass/both_borrows/smallvec.rs @@ -25,7 +25,7 @@ impl RawSmallVec { } const fn as_mut_ptr_inline(&mut self) -> *mut T { - (unsafe { &raw mut self.inline }) as *mut T + &raw mut self.inline as *mut T } const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T { diff --git a/tests/ui/union/union-unsafe.rs b/tests/ui/union/union-unsafe.rs index bd3946686be3..beb074f4e8eb 100644 --- a/tests/ui/union/union-unsafe.rs +++ b/tests/ui/union/union-unsafe.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::mem::ManuallyDrop; +use std::ops::Deref; union U1 { a: u8, @@ -17,6 +18,10 @@ union U4 { a: T, } +union U5 { + a: usize, +} + union URef { p: &'static mut i32, } @@ -31,6 +36,20 @@ fn deref_union_field(mut u: URef) { *(u.p) = 13; //~ ERROR access to union field is unsafe } +union A { + a: usize, + b: &'static &'static B, +} + +union B { + c: usize, +} + +fn raw_deref_union_field(mut u: URef) { + // This is unsafe because we first dereference u.p (reading uninitialized memory) + let _p = &raw const *(u.p); //~ ERROR access to union field is unsafe +} + fn assign_noncopy_union_field(mut u: URefCell) { u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop) u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop) @@ -57,6 +76,20 @@ fn main() { let a = u1.a; //~ ERROR access to union field is unsafe u1.a = 11; // OK + let mut u2 = U1 { a: 10 }; + let a = &raw mut u2.a; // OK + unsafe { *a = 3 }; + + let mut u3 = U1 { a: 10 }; + let a = std::ptr::addr_of_mut!(u3.a); // OK + unsafe { *a = 14 }; + + let u4 = U5 { a: 2 }; + let vec = vec![1, 2, 3]; + // This is unsafe because we read u4.a (potentially uninitialized memory) + // to use as an array index + let _a = &raw const vec[u4.a]; //~ ERROR access to union field is unsafe + let U1 { a } = u1; //~ ERROR access to union field is unsafe if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe if let Some(U1 { a: 13 }) = Some(u1) {} //~ ERROR access to union field is unsafe @@ -73,4 +106,44 @@ fn main() { let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop) *u3.a = String::from("new"); //~ ERROR access to union field is unsafe + + let mut unions = [U1 { a: 1 }, U1 { a: 2 }]; + + // Array indexing + union field raw borrow - should be OK + let ptr = &raw mut unions[0].a; // OK + let ptr2 = &raw const unions[1].a; // OK + + let a = A { a: 0 }; + let _p = &raw const (**a.b).c; //~ ERROR access to union field is unsafe + + arbitrary_deref(); +} + +// regression test for https://github.com/rust-lang/rust/pull/141469#discussion_r2312546218 +fn arbitrary_deref() { + use std::ops::Deref; + + union A { + a: usize, + b: B, + } + + #[derive(Copy, Clone)] + struct B(&'static str); + + impl Deref for B { + type Target = C; + + fn deref(&self) -> &C { + println!("{:?}", self.0); + &C { c: 0 } + } + } + + union C { + c: usize, + } + + let a = A { a: 0 }; + let _p = &raw const (*a.b).c; //~ ERROR access to union field is unsafe } diff --git a/tests/ui/union/union-unsafe.stderr b/tests/ui/union/union-unsafe.stderr index 82b3f897167c..01f4d95eb649 100644 --- a/tests/ui/union/union-unsafe.stderr +++ b/tests/ui/union/union-unsafe.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:31:6 + --> $DIR/union-unsafe.rs:36:6 | LL | *(u.p) = 13; | ^^^^^ access to union field @@ -7,7 +7,15 @@ LL | *(u.p) = 13; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:43:6 + --> $DIR/union-unsafe.rs:50:26 + | +LL | let _p = &raw const *(u.p); + | ^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:62:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -15,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:49:6 + --> $DIR/union-unsafe.rs:68:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -23,7 +31,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:57:13 + --> $DIR/union-unsafe.rs:76:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -31,7 +39,15 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:60:14 + --> $DIR/union-unsafe.rs:91:29 + | +LL | let _a = &raw const vec[u4.a]; + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:93:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -39,7 +55,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:61:20 + --> $DIR/union-unsafe.rs:94:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field @@ -47,7 +63,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:62:25 + --> $DIR/union-unsafe.rs:95:25 | LL | if let Some(U1 { a: 13 }) = Some(u1) {} | ^^ access to union field @@ -55,7 +71,7 @@ LL | if let Some(U1 { a: 13 }) = Some(u1) {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:67:6 + --> $DIR/union-unsafe.rs:100:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -63,7 +79,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:71:6 + --> $DIR/union-unsafe.rs:104:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -71,13 +87,29 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:75:6 + --> $DIR/union-unsafe.rs:108:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 10 previous errors +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:117:28 + | +LL | let _p = &raw const (**a.b).c; + | ^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:148:27 + | +LL | let _p = &raw const (*a.b).c; + | ^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0133`. From 4f0e9e29e344975ddf9ebaf5bb8e71a0a433023e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 3 Sep 2025 01:18:47 +0800 Subject: [PATCH 012/537] Fix closure in match not applicable for add_braces Example --- **Not applicable**: ```rust fn foo() { match () { () => { t(|n|$0 n + 100); } } } ``` --- .../ide-assists/src/handlers/add_braces.rs | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 745ae67f3095..5af622eaf28b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,3 +1,4 @@ +use either::Either; use syntax::{ AstNode, ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory}, @@ -59,7 +60,8 @@ enum ParentType { } fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> { - if let Some(match_arm) = ctx.find_node_at_offset::() { + let node = ctx.find_node_at_offset::>()?; + if let Either::Left(match_arm) = &node { let match_arm_expr = match_arm.expr()?; if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) { @@ -67,7 +69,7 @@ fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Exp } return Some((ParentType::MatchArmExpr, match_arm_expr)); - } else if let Some(closure_expr) = ctx.find_node_at_offset::() { + } else if let Either::Right(closure_expr) = &node { let body = closure_expr.body()?; if matches!(body, ast::Expr::BlockExpr(_)) { @@ -105,6 +107,33 @@ fn foo() { ); } + #[test] + fn suggest_add_braces_for_closure_in_match() { + check_assist( + add_braces, + r#" +fn foo() { + match () { + () => { + t(|n|$0 n + 100); + } + } +} +"#, + r#" +fn foo() { + match () { + () => { + t(|n| { + n + 100 + }); + } + } +} +"#, + ); + } + #[test] fn no_assist_for_closures_with_braces() { check_assist_not_applicable( From 1bf57df7d72333bb4289d8f7072e8e170ad54ce2 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 3 Sep 2025 21:14:19 +0800 Subject: [PATCH 013/537] Add applicable on bang `!` for apply_demorgan Example --- ```rust fn f() { $0!(1 || 3 && 4 || 5) } ``` -> ```rust fn f() { !1 && !(3 && 4) && !5 } ``` --- .../src/handlers/apply_demorgan.rs | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs index 753a9e56c35a..53a0a11998a0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -6,7 +6,7 @@ use ide_db::{ syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; use syntax::{ - SyntaxKind, T, + NodeOrToken, SyntaxKind, T, ast::{ self, AstNode, Expr::BinExpr, @@ -38,15 +38,27 @@ use crate::{AssistContext, AssistId, Assists, utils::invert_boolean_expression}; // } // ``` pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let mut bin_expr = ctx.find_node_at_offset::()?; + let mut bin_expr = if let Some(not) = ctx.find_token_syntax_at_offset(T![!]) + && let Some(NodeOrToken::Node(next)) = not.next_sibling_or_token() + && let Some(paren) = ast::ParenExpr::cast(next) + && let Some(ast::Expr::BinExpr(bin_expr)) = paren.expr() + { + bin_expr + } else { + let bin_expr = ctx.find_node_at_offset::()?; + let op_range = bin_expr.op_token()?.text_range(); + + // Is the cursor on the expression's logical operator? + if !op_range.contains_range(ctx.selection_trimmed()) { + return None; + } + + bin_expr + }; + let op = bin_expr.op_kind()?; let op_range = bin_expr.op_token()?.text_range(); - // Is the cursor on the expression's logical operator? - if !op_range.contains_range(ctx.selection_trimmed()) { - return None; - } - // Walk up the tree while we have the same binary operator while let Some(parent_expr) = bin_expr.syntax().parent().and_then(ast::BinExpr::cast) { match parent_expr.op_kind() { @@ -366,6 +378,15 @@ fn f() { !(S <= S || S < S) } ) } + #[test] + fn demorgan_on_not() { + check_assist( + apply_demorgan, + "fn f() { $0!(1 || 3 && 4 || 5) }", + "fn f() { !1 && !(3 && 4) && !5 }", + ) + } + #[test] fn demorgan_keep_pars_for_op_precedence() { check_assist( From 78e096015deaf67999aafd1df88f3b08fdce4e4a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 4 Sep 2025 14:57:41 +0800 Subject: [PATCH 014/537] Add cfg_attr predicate completion Example --- ```rust #[cfg_attr($0, must_use)] struct Foo; ``` --- .../src/completions/attribute.rs | 2 +- .../ide-completion/src/tests/attribute.rs | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index c542e140df54..e174b0c8922a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -70,7 +70,7 @@ pub(crate) fn complete_known_attribute_input( lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); } - ["cfg"] => cfg::complete_cfg(acc, ctx), + ["cfg"] | ["cfg_attr"] => cfg::complete_cfg(acc, ctx), ["macro_use"] => macro_use::complete_macro_use( acc, ctx, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 46a36300459d..30e1e108c6c4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -835,6 +835,58 @@ mod cfg { ); } + #[test] + fn inside_cfg_attr() { + check( + r#" +//- /main.rs cfg:test,dbg=false,opt_level=2 +#[cfg_attr($0)] +"#, + expect![[r#" + ba dbg + ba opt_level + ba test + ba true + "#]], + ); + check( + r#" +//- /main.rs cfg:test,dbg=false,opt_level=2 +#[cfg_attr(b$0)] +"#, + expect![[r#" + ba dbg + ba opt_level + ba test + ba true + "#]], + ); + check( + r#" +//- /main.rs cfg:test,dbg=false,opt_level=2 +#[cfg_attr($0, allow(deprecated))] +"#, + expect![[r#" + ba dbg + ba opt_level + ba test + ba true + "#]], + ); + check( + r#" +//- /main.rs cfg:test,dbg=false,opt_level=2 +#[cfg_attr(b$0, allow(deprecated))] +"#, + expect![[r#" + ba dbg + ba opt_level + ba test + ba true + "#]], + ); + } + #[test] fn cfg_target_endian() { check( From ec34e8e69fb2e133e6ec0ebc87443f6fa8bda092 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 5 Sep 2025 06:30:28 +0800 Subject: [PATCH 015/537] Fix precedence parenthesis for replace_arith_op Example --- ```rust fn main() { let x = 1*x $0+ 2; } ``` **Before this PR**: ```rust fn main() { let x = 1*x.wrapping_add(2); } ``` **After this PR**: ```rust fn main() { let x = (1*x).wrapping_add(2); } ``` --- .../src/handlers/replace_arith_op.rs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs index 440ab4d4604f..94ac1c342d30 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs @@ -88,7 +88,11 @@ fn replace_arith(acc: &mut Assists, ctx: &AssistContext<'_>, kind: ArithKind) -> |builder| { let method_name = kind.method_name(op); - builder.replace(range, format!("{lhs}.{method_name}({rhs})")) + if lhs.precedence().needs_parentheses_in(ast::prec::ExprPrecedence::Postfix) { + builder.replace(range, format!("({lhs}).{method_name}({rhs})")) + } else { + builder.replace(range, format!("{lhs}.{method_name}({rhs})")) + } }, ) } @@ -227,6 +231,23 @@ fn main() { ) } + #[test] + fn replace_arith_with_wrapping_add_add_parenthesis() { + check_assist( + replace_arith_with_wrapping, + r#" +fn main() { + let x = 1*x $0+ 2; +} +"#, + r#" +fn main() { + let x = (1*x).wrapping_add(2); +} +"#, + ) + } + #[test] fn replace_arith_not_applicable_with_non_empty_selection() { check_assist_not_applicable( From 7ce8e289db72471c41b53664a214ed0e00458f07 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 13 Aug 2025 12:38:11 -0400 Subject: [PATCH 016/537] Add `Path::has_trailing_sep` and related methods --- library/std/src/path.rs | 187 +++++++++++++++++++++++++++++++++++++- library/std/tests/path.rs | 38 +++++++- 2 files changed, 221 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 19663e4a9df6..943c40220b84 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1412,6 +1412,99 @@ impl PathBuf { } } + /// Sets whether the path has a trailing [separator](MAIN_SEPARATOR). + /// + /// The value returned by [`has_trailing_sep`](Path::has_trailing_sep) will be equivalent to + /// the provided value if possible. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::path::PathBuf; + /// + /// let mut p = PathBuf::from("dir"); + /// + /// assert!(!p.has_trailing_sep()); + /// p.set_trailing_sep(false); + /// assert!(!p.has_trailing_sep()); + /// p.set_trailing_sep(true); + /// assert!(p.has_trailing_sep()); + /// p.set_trailing_sep(false); + /// assert!(!p.has_trailing_sep()); + /// + /// p = PathBuf::from("/"); + /// assert!(p.has_trailing_sep()); + /// p.set_trailing_sep(false); + /// assert!(p.has_trailing_sep()); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + pub fn set_trailing_sep(&mut self, trailing_sep: bool) { + if trailing_sep { self.push_trailing_sep() } else { self.pop_trailing_sep() } + } + + /// Adds a trailing [separator](MAIN_SEPARATOR) to the path. + /// + /// This acts similarly to [`Path::with_trailing_sep`], but mutates the underlying `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::ffi::OsStr; + /// use std::path::PathBuf; + /// + /// let mut p = PathBuf::from("dir"); + /// + /// assert!(!p.has_trailing_sep()); + /// p.push_trailing_sep(); + /// assert!(p.has_trailing_sep()); + /// p.push_trailing_sep(); + /// assert!(p.has_trailing_sep()); + /// + /// p = PathBuf::from("dir/"); + /// p.push_trailing_sep(); + /// assert_eq!(p.as_os_str(), OsStr::new("dir/")); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + pub fn push_trailing_sep(&mut self) { + if !self.has_trailing_sep() { + self.push(""); + } + } + + /// Removes a trailing [separator](MAIN_SEPARATOR) from the path, if possible. + /// + /// This acts similarly to [`Path::trim_trailing_sep`], but mutates the underlying `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::ffi::OsStr; + /// use std::path::PathBuf; + /// + /// let mut p = PathBuf::from("dir//"); + /// + /// assert!(p.has_trailing_sep()); + /// assert_eq!(p.as_os_str(), OsStr::new("dir//")); + /// p.pop_trailing_sep(); + /// assert!(!p.has_trailing_sep()); + /// assert_eq!(p.as_os_str(), OsStr::new("dir")); + /// p.pop_trailing_sep(); + /// assert!(!p.has_trailing_sep()); + /// assert_eq!(p.as_os_str(), OsStr::new("dir")); + /// + /// p = PathBuf::from("/"); + /// assert!(p.has_trailing_sep()); + /// p.pop_trailing_sep(); + /// assert!(p.has_trailing_sep()); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + pub fn pop_trailing_sep(&mut self) { + self.inner.truncate(self.trim_trailing_sep().as_os_str().len()); + } + /// Updates [`self.file_name`] to `file_name`. /// /// If [`self.file_name`] was [`None`], this is equivalent to pushing @@ -1610,7 +1703,7 @@ impl PathBuf { let new = extension.as_encoded_bytes(); if !new.is_empty() { // truncate until right after the file name - // this is necessary for trimming the trailing slash + // this is necessary for trimming the trailing separator let end_file_name = file_name[file_name.len()..].as_ptr().addr(); let start = self.inner.as_encoded_bytes().as_ptr().addr(); self.inner.truncate(end_file_name.wrapping_sub(start)); @@ -2755,6 +2848,94 @@ impl Path { self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after)) } + /// Checks whether the path ends in a trailing [separator](MAIN_SEPARATOR). + /// + /// This is generally done to ensure that a path is treated as a directory, not a file, + /// although it does not actually guarantee that such a path is a directory on the underlying + /// file system. + /// + /// Despite this behavior, two paths are still considered the same in Rust whether they have a + /// trailing separator or not. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::path::Path; + /// + /// assert!(Path::new("dir/").has_trailing_sep()); + /// assert!(!Path::new("file.rs").has_trailing_sep()); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + #[must_use] + #[inline] + pub fn has_trailing_sep(&self) -> bool { + self.as_os_str().as_encoded_bytes().last().copied().is_some_and(is_sep_byte) + } + + /// Ensures that a path has a trailing [separator](MAIN_SEPARATOR), + /// allocating a [`PathBuf`] if necessary. + /// + /// The resulting path will return true for [`has_trailing_sep`](Self::has_trailing_sep). + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::ffi::OsStr; + /// use std::path::Path; + /// + /// assert_eq!(Path::new("dir//").with_trailing_sep().as_os_str(), OsStr::new("dir//")); + /// assert_eq!(Path::new("dir/").with_trailing_sep().as_os_str(), OsStr::new("dir/")); + /// assert!(!Path::new("dir").has_trailing_sep()); + /// assert!(Path::new("dir").with_trailing_sep().has_trailing_sep()); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + #[must_use] + #[inline] + pub fn with_trailing_sep(&self) -> Cow<'_, Path> { + if self.has_trailing_sep() { Cow::Borrowed(self) } else { Cow::Owned(self.join("")) } + } + + /// Trims a trailing [separator](MAIN_SEPARATOR) from a path, if possible. + /// + /// The resulting path will return false for [`has_trailing_sep`](Self::has_trailing_sep) for + /// most paths. + /// + /// Some paths, like `/`, cannot be trimmed in this way. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_trailing_sep)] + /// use std::ffi::OsStr; + /// use std::path::Path; + /// + /// assert_eq!(Path::new("dir//").trim_trailing_sep().as_os_str(), OsStr::new("dir")); + /// assert_eq!(Path::new("dir/").trim_trailing_sep().as_os_str(), OsStr::new("dir")); + /// assert_eq!(Path::new("dir").trim_trailing_sep().as_os_str(), OsStr::new("dir")); + /// assert_eq!(Path::new("/").trim_trailing_sep().as_os_str(), OsStr::new("/")); + /// assert_eq!(Path::new("//").trim_trailing_sep().as_os_str(), OsStr::new("//")); + /// ``` + #[unstable(feature = "path_trailing_sep", issue = "142503")] + #[must_use] + #[inline] + pub fn trim_trailing_sep(&self) -> &Path { + if self.has_trailing_sep() && (!self.has_root() || self.parent().is_some()) { + let mut bytes = self.inner.as_encoded_bytes(); + while let Some((last, init)) = bytes.split_last() + && is_sep_byte(*last) + { + bytes = init; + } + + // SAFETY: Trimming trailing ASCII bytes will retain the validity of the string. + Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }) + } else { + self + } + } + /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. /// /// If `path` is absolute, it replaces the current path. @@ -2907,7 +3088,7 @@ impl Path { /// `a/b` all have `a` and `b` as components, but `./a/b` starts with /// an additional [`CurDir`] component. /// - /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent. + /// * Trailing separators are normalized away, so `/a/b` and `/a/b/` are equivalent. /// /// Note that no other normalization takes place; in particular, `a/c` /// and `a/b/../c` are distinct, to account for the possibility that `b` @@ -3710,7 +3891,7 @@ impl Error for NormalizeError {} /// /// On POSIX platforms, the path is resolved using [POSIX semantics][posix-semantics], /// except that it stops short of resolving symlinks. This means it will keep `..` -/// components and trailing slashes. +/// components and trailing separators. /// /// On Windows, for verbatim paths, this will simply return the path as given. For other /// paths, this is currently equivalent to calling diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index fa76c50597b0..1d3337ff935a 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1,4 +1,9 @@ -#![feature(clone_to_uninit, maybe_uninit_slice, normalize_lexically)] +// tidy-alphabetical-start +#![feature(clone_to_uninit)] +#![feature(maybe_uninit_slice)] +#![feature(normalize_lexically)] +#![feature(path_trailing_sep)] +// tidy-alphabetical-end use std::clone::CloneToUninit; use std::ffi::OsStr; @@ -2532,3 +2537,34 @@ fn normalize_lexically() { fn compare_path_to_str() { assert!(&PathBuf::from("x") == "x"); } + +#[test] +fn test_trim_trailing_sep() { + assert_eq!(Path::new("/").trim_trailing_sep().as_os_str(), OsStr::new("/")); + assert_eq!(Path::new("//").trim_trailing_sep().as_os_str(), OsStr::new("//")); + assert_eq!(Path::new("").trim_trailing_sep().as_os_str(), OsStr::new("")); + assert_eq!(Path::new(".").trim_trailing_sep().as_os_str(), OsStr::new(".")); + assert_eq!(Path::new("./").trim_trailing_sep().as_os_str(), OsStr::new(".")); + assert_eq!(Path::new(".//").trim_trailing_sep().as_os_str(), OsStr::new(".")); + assert_eq!(Path::new("..").trim_trailing_sep().as_os_str(), OsStr::new("..")); + assert_eq!(Path::new("../").trim_trailing_sep().as_os_str(), OsStr::new("..")); + assert_eq!(Path::new("..//").trim_trailing_sep().as_os_str(), OsStr::new("..")); + + #[cfg(any(windows, target_os = "cygwin"))] + { + assert_eq!(Path::new("\\").trim_trailing_sep().as_os_str(), OsStr::new("\\")); + assert_eq!(Path::new("\\\\").trim_trailing_sep().as_os_str(), OsStr::new("\\\\")); + assert_eq!(Path::new("c:/").trim_trailing_sep().as_os_str(), OsStr::new("c:/")); + assert_eq!(Path::new("c://").trim_trailing_sep().as_os_str(), OsStr::new("c://")); + assert_eq!(Path::new("c:./").trim_trailing_sep().as_os_str(), OsStr::new("c:.")); + assert_eq!(Path::new("c:.//").trim_trailing_sep().as_os_str(), OsStr::new("c:.")); + assert_eq!(Path::new("c:../").trim_trailing_sep().as_os_str(), OsStr::new("c:..")); + assert_eq!(Path::new("c:..//").trim_trailing_sep().as_os_str(), OsStr::new("c:..")); + assert_eq!(Path::new("c:\\").trim_trailing_sep().as_os_str(), OsStr::new("c:\\")); + assert_eq!(Path::new("c:\\\\").trim_trailing_sep().as_os_str(), OsStr::new("c:\\\\")); + assert_eq!(Path::new("c:.\\").trim_trailing_sep().as_os_str(), OsStr::new("c:.")); + assert_eq!(Path::new("c:.\\\\").trim_trailing_sep().as_os_str(), OsStr::new("c:.")); + assert_eq!(Path::new("c:..\\").trim_trailing_sep().as_os_str(), OsStr::new("c:..")); + assert_eq!(Path::new("c:..\\\\").trim_trailing_sep().as_os_str(), OsStr::new("c:..")); + } +} From 96f385b20aa252629570cadeca16a9e159e6810c Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Thu, 7 Aug 2025 21:27:12 +0200 Subject: [PATCH 017/537] RawVecInner: add missing `unsafe` to unsafe fns - RawVecInner::grow_exact causes UB if called with len and additional arguments such that len + additional is less than the current capacity. Indeed, in that case it calls Allocator::grow with a new_layout that is smaller than old_layout, which violates a safety precondition. - All RawVecInner methods for resizing the buffer cause UB if called with an elem_layout different from the one used to initially allocate the buffer, because in that case Allocator::grow/shrink is called with an old_layout that does not fit the allocated block, which violates a safety precondition. - RawVecInner::current_memory might cause UB if called with an elem_layout different from the one used to initially allocate the buffer, because the unchecked_mul might overflow. - Furthermore, these methods cause UB if called with an elem_layout where the size is not a multiple of the alignment. This is because Layout::repeat is used (in layout_array) to compute the allocation's layout when allocating, which includes padding to ensure alignment of array elements, but simple multiplication is used (in current_memory) to compute the old allocation's layout when resizing or deallocating, which would cause the layout used to resize or deallocate to not fit the allocated block, which violates a safety precondition. --- library/alloc/src/raw_vec/mod.rs | 149 +++++++++++++++++++++++------ library/alloc/src/raw_vec/tests.rs | 10 +- 2 files changed, 123 insertions(+), 36 deletions(-) diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index b0027e964e46..fd8283195a38 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -177,6 +177,8 @@ impl RawVec { /// the returned `RawVec`. #[inline] pub(crate) const fn new_in(alloc: A) -> Self { + // Check assumption made in `current_memory` + const { assert!(T::LAYOUT.size() % T::LAYOUT.align() == 0) }; Self { inner: RawVecInner::new_in(alloc, Alignment::of::()), _marker: PhantomData } } @@ -328,7 +330,8 @@ impl RawVec { #[inline] #[track_caller] pub(crate) fn reserve(&mut self, len: usize, additional: usize) { - self.inner.reserve(len, additional, T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.reserve(len, additional, T::LAYOUT) } } /// A specialized version of `self.reserve(len, 1)` which requires the @@ -337,7 +340,8 @@ impl RawVec { #[inline(never)] #[track_caller] pub(crate) fn grow_one(&mut self) { - self.inner.grow_one(T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.grow_one(T::LAYOUT) } } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -346,7 +350,8 @@ impl RawVec { len: usize, additional: usize, ) -> Result<(), TryReserveError> { - self.inner.try_reserve(len, additional, T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.try_reserve(len, additional, T::LAYOUT) } } /// Ensures that the buffer contains at least enough space to hold `len + @@ -369,7 +374,8 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[track_caller] pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { - self.inner.reserve_exact(len, additional, T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.reserve_exact(len, additional, T::LAYOUT) } } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -378,7 +384,8 @@ impl RawVec { len: usize, additional: usize, ) -> Result<(), TryReserveError> { - self.inner.try_reserve_exact(len, additional, T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.try_reserve_exact(len, additional, T::LAYOUT) } } /// Shrinks the buffer down to the specified capacity. If the given amount @@ -395,7 +402,8 @@ impl RawVec { #[track_caller] #[inline] pub(crate) fn shrink_to_fit(&mut self, cap: usize) { - self.inner.shrink_to_fit(cap, T::LAYOUT) + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.shrink_to_fit(cap, T::LAYOUT) } } } @@ -518,8 +526,12 @@ impl RawVecInner { &self.alloc } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment #[inline] - fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { + unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { if elem_layout.size() == 0 || self.cap.as_inner() == 0 { None } else { @@ -535,48 +547,67 @@ impl RawVecInner { } } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { + unsafe fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { // Callers expect this function to be very cheap when there is already sufficient capacity. // Therefore, we move all the resizing and error-handling logic from grow_amortized and // handle_reserve behind a call, while making sure that this function is likely to be // inlined as just a comparison and a call if the comparison fails. #[cold] - fn do_reserve_and_handle( + unsafe fn do_reserve_and_handle( slf: &mut RawVecInner, len: usize, additional: usize, elem_layout: Layout, ) { - if let Err(err) = slf.grow_amortized(len, additional, elem_layout) { + // SAFETY: Precondition passed to caller + if let Err(err) = unsafe { slf.grow_amortized(len, additional, elem_layout) } { handle_error(err); } } if self.needs_to_grow(len, additional, elem_layout) { - do_reserve_and_handle(self, len, additional, elem_layout); + unsafe { + do_reserve_and_handle(self, len, additional, elem_layout); + } } } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - fn grow_one(&mut self, elem_layout: Layout) { - if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) { + unsafe fn grow_one(&mut self, elem_layout: Layout) { + // SAFETY: Precondition passed to caller + if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { handle_error(err); } } - fn try_reserve( + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + unsafe fn try_reserve( &mut self, len: usize, additional: usize, elem_layout: Layout, ) -> Result<(), TryReserveError> { if self.needs_to_grow(len, additional, elem_layout) { - self.grow_amortized(len, additional, elem_layout)?; + // SAFETY: Precondition passed to caller + unsafe { + self.grow_amortized(len, additional, elem_layout)?; + } } unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed @@ -585,22 +616,34 @@ impl RawVecInner { Ok(()) } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[track_caller] - fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { - if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) { + unsafe fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { + // SAFETY: Precondition passed to caller + if let Err(err) = unsafe { self.try_reserve_exact(len, additional, elem_layout) } { handle_error(err); } } - fn try_reserve_exact( + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + unsafe fn try_reserve_exact( &mut self, len: usize, additional: usize, elem_layout: Layout, ) -> Result<(), TryReserveError> { if self.needs_to_grow(len, additional, elem_layout) { - self.grow_exact(len, additional, elem_layout)?; + // SAFETY: Precondition passed to caller + unsafe { + self.grow_exact(len, additional, elem_layout)?; + } } unsafe { // Inform the optimizer that the reservation has succeeded or wasn't needed @@ -609,11 +652,16 @@ impl RawVecInner { Ok(()) } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - `cap` must be less than or equal to `self.capacity(elem_layout.size())` #[cfg(not(no_global_oom_handling))] #[inline] #[track_caller] - fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { - if let Err(err) = self.shrink(cap, elem_layout) { + unsafe fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { + if let Err(err) = unsafe { self.shrink(cap, elem_layout) } { handle_error(err); } } @@ -632,7 +680,13 @@ impl RawVecInner { self.cap = unsafe { Cap::new_unchecked(cap) }; } - fn grow_amortized( + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - The sum of `len` and `additional` must be greater than or equal to + /// `self.capacity(elem_layout.size())` + unsafe fn grow_amortized( &mut self, len: usize, additional: usize, @@ -657,14 +711,25 @@ impl RawVecInner { let new_layout = layout_array(cap, elem_layout)?; - let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; - // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items + // SAFETY: + // - For the `current_memory` call: Precondition passed to caller + // - For the `finish_grow` call: Precondition passed to caller + // + `current_memory` does the right thing + let ptr = + unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? }; + // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap) }; Ok(()) } - fn grow_exact( + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - The sum of `len` and `additional` must be greater than or equal to + /// `self.capacity(elem_layout.size())` + unsafe fn grow_exact( &mut self, len: usize, additional: usize, @@ -679,7 +744,12 @@ impl RawVecInner { let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; let new_layout = layout_array(cap, elem_layout)?; - let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; + // SAFETY: + // - For the `current_memory` call: Precondition passed to caller + // - For the `finish_grow` call: Precondition passed to caller + // + `current_memory` does the right thing + let ptr = + unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? }; // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap); @@ -687,9 +757,14 @@ impl RawVecInner { Ok(()) } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - `cap` must be less than or equal to `self.capacity(elem_layout.size())` #[cfg(not(no_global_oom_handling))] #[inline] - fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> { + unsafe fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> { assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity"); // SAFETY: Just checked this isn't trying to grow unsafe { self.shrink_unchecked(cap, elem_layout) } @@ -711,8 +786,12 @@ impl RawVecInner { cap: usize, elem_layout: Layout, ) -> Result<(), TryReserveError> { - let (ptr, layout) = - if let Some(mem) = self.current_memory(elem_layout) { mem } else { return Ok(()) }; + // SAFETY: Precondition passed to caller + let (ptr, layout) = if let Some(mem) = unsafe { self.current_memory(elem_layout) } { + mem + } else { + return Ok(()); + }; // If shrinking to 0, deallocate the buffer. We don't reach this point // for the T::IS_ZST case since current_memory() will have returned @@ -748,7 +827,8 @@ impl RawVecInner { /// Ideally this function would take `self` by move, but it cannot because it exists to be /// called from a `Drop` impl. unsafe fn deallocate(&mut self, elem_layout: Layout) { - if let Some((ptr, layout)) = self.current_memory(elem_layout) { + // SAFETY: Precondition passed to caller + if let Some((ptr, layout)) = unsafe { self.current_memory(elem_layout) } { unsafe { self.alloc.deallocate(ptr, layout); } @@ -756,10 +836,17 @@ impl RawVecInner { } } +/// # Safety +/// If `current_memory` matches `Some((ptr, old_layout))`: +/// - `ptr` must denote a block of memory *currently allocated* via `alloc` +/// - `old_layout` must *fit* that block of memory +/// - `new_layout` must have the same alignment as `old_layout` +/// - `new_layout.size()` must be greater than or equal to `old_layout.size()` +/// If `current_memory` is `None`, this function is safe. // not marked inline(never) since we want optimizers to be able to observe the specifics of this // function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] -fn finish_grow( +unsafe fn finish_grow( new_layout: Layout, current_memory: Option<(NonNull, Layout)>, alloc: &mut A, diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index 700fa922739d..15f48c03dc54 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -85,7 +85,7 @@ struct ZST; fn zst_sanity(v: &RawVec) { assert_eq!(v.capacity(), usize::MAX); assert_eq!(v.ptr(), core::ptr::Unique::::dangling().as_ptr()); - assert_eq!(v.inner.current_memory(T::LAYOUT), None); + assert_eq!(unsafe { v.inner.current_memory(T::LAYOUT) }, None); } #[test] @@ -126,12 +126,12 @@ fn zst() { assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err); zst_sanity(&v); - assert_eq!(v.inner.grow_amortized(100, usize::MAX - 100, ZST::LAYOUT), cap_err); - assert_eq!(v.inner.grow_amortized(101, usize::MAX - 100, ZST::LAYOUT), cap_err); + assert_eq!(unsafe { v.inner.grow_amortized(100, usize::MAX - 100, ZST::LAYOUT) }, cap_err); + assert_eq!(unsafe { v.inner.grow_amortized(101, usize::MAX - 100, ZST::LAYOUT) }, cap_err); zst_sanity(&v); - assert_eq!(v.inner.grow_exact(100, usize::MAX - 100, ZST::LAYOUT), cap_err); - assert_eq!(v.inner.grow_exact(101, usize::MAX - 100, ZST::LAYOUT), cap_err); + assert_eq!(unsafe { v.inner.grow_exact(100, usize::MAX - 100, ZST::LAYOUT) }, cap_err); + assert_eq!(unsafe { v.inner.grow_exact(101, usize::MAX - 100, ZST::LAYOUT) }, cap_err); zst_sanity(&v); } From 400e687598320fbd9690af5acc4af091b18f577d Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Mon, 8 Sep 2025 15:55:16 +0200 Subject: [PATCH 018/537] Bump unicode_data to version 17.0.0 --- library/core/src/unicode/unicode_data.rs | 750 ++++++++++++----------- 1 file changed, 383 insertions(+), 367 deletions(-) diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 2f53de183f62..3c38b44224f8 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -1,15 +1,15 @@ //! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually! -// Alphabetic : 1723 bytes, 142707 codepoints in 755 ranges (U+0000AA - U+0323B0) using skiplist -// Case_Ignorable : 1043 bytes, 2744 codepoints in 447 ranges (U+0000A8 - U+0E01F0) using skiplist -// Cased : 403 bytes, 4526 codepoints in 157 ranges (U+0000AA - U+01F18A) using skiplist -// Grapheme_Extend : 887 bytes, 2193 codepoints in 375 ranges (U+000300 - U+0E01F0) using skiplist -// Lowercase : 933 bytes, 2543 codepoints in 674 ranges (U+0000AA - U+01E944) using bitset -// N : 455 bytes, 1901 codepoints in 143 ranges (U+0000B2 - U+01FBFA) using skiplist -// Uppercase : 797 bytes, 1952 codepoints in 655 ranges (U+0000C0 - U+01F18A) using bitset +// Alphabetic : 1723 bytes, 147369 codepoints in 759 ranges (U+0000AA - U+03347A) using skiplist +// Case_Ignorable : 1063 bytes, 2789 codepoints in 459 ranges (U+0000A8 - U+0E01F0) using skiplist +// Cased : 401 bytes, 4580 codepoints in 156 ranges (U+0000AA - U+01F18A) using skiplist +// Grapheme_Extend : 899 bytes, 2232 codepoints in 383 ranges (U+000300 - U+0E01F0) using skiplist +// Lowercase : 943 bytes, 2569 codepoints in 676 ranges (U+0000AA - U+01E944) using bitset +// N : 463 bytes, 1914 codepoints in 145 ranges (U+0000B2 - U+01FBFA) using skiplist +// Uppercase : 799 bytes, 1980 codepoints in 659 ranges (U+0000C0 - U+01F18A) using bitset // White_Space : 256 bytes, 19 codepoints in 8 ranges (U+000085 - U+003001) using cascading -// to_lower : 11484 bytes -// to_upper : 13432 bytes -// Total : 31413 bytes +// to_lower : 11708 bytes +// to_upper : 13656 bytes +// Total : 31911 bytes #[inline(always)] const fn bitset_search< @@ -140,53 +140,52 @@ unsafe fn skip_search( offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u8, u8, u8) = (16, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (17, 0, 0); #[rustfmt::skip] pub mod alphabetic { use super::ShortOffsetRunHeader; - static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 53] = [ + static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 51] = [ ShortOffsetRunHeader::new(0, 706), ShortOffsetRunHeader::new(12, 4681), ShortOffsetRunHeader::new(414, 5741), ShortOffsetRunHeader::new(452, 7958), ShortOffsetRunHeader::new(552, 9398), ShortOffsetRunHeader::new(623, 11264), ShortOffsetRunHeader::new(625, 12293), ShortOffsetRunHeader::new(663, 13312), ShortOffsetRunHeader::new(687, 19904), ShortOffsetRunHeader::new(688, 42125), ShortOffsetRunHeader::new(690, 42509), ShortOffsetRunHeader::new(694, 55204), - ShortOffsetRunHeader::new(784, 63744), ShortOffsetRunHeader::new(789, 64110), - ShortOffsetRunHeader::new(790, 64830), ShortOffsetRunHeader::new(812, 66176), - ShortOffsetRunHeader::new(853, 67383), ShortOffsetRunHeader::new(900, 73440), + ShortOffsetRunHeader::new(778, 63744), ShortOffsetRunHeader::new(783, 64110), + ShortOffsetRunHeader::new(784, 64830), ShortOffsetRunHeader::new(806, 66176), + ShortOffsetRunHeader::new(847, 67383), ShortOffsetRunHeader::new(894, 73440), ShortOffsetRunHeader::new(1217, 74650), ShortOffsetRunHeader::new(1228, 77712), ShortOffsetRunHeader::new(1233, 78896), ShortOffsetRunHeader::new(1236, 82939), ShortOffsetRunHeader::new(1240, 83527), ShortOffsetRunHeader::new(1242, 90368), ShortOffsetRunHeader::new(1243, 92160), ShortOffsetRunHeader::new(1245, 92729), - ShortOffsetRunHeader::new(1246, 93504), ShortOffsetRunHeader::new(1261, 100344), - ShortOffsetRunHeader::new(1278, 101590), ShortOffsetRunHeader::new(1280, 110576), - ShortOffsetRunHeader::new(1283, 110883), ShortOffsetRunHeader::new(1290, 111356), - ShortOffsetRunHeader::new(1300, 113664), ShortOffsetRunHeader::new(1301, 119808), - ShortOffsetRunHeader::new(1311, 120486), ShortOffsetRunHeader::new(1348, 122624), - ShortOffsetRunHeader::new(1371, 123536), ShortOffsetRunHeader::new(1395, 124112), - ShortOffsetRunHeader::new(1399, 124896), ShortOffsetRunHeader::new(1405, 126464), - ShortOffsetRunHeader::new(1421, 127280), ShortOffsetRunHeader::new(1487, 131072), - ShortOffsetRunHeader::new(1493, 173792), ShortOffsetRunHeader::new(1494, 177978), - ShortOffsetRunHeader::new(1496, 183970), ShortOffsetRunHeader::new(1500, 191457), - ShortOffsetRunHeader::new(1502, 192094), ShortOffsetRunHeader::new(1504, 194560), - ShortOffsetRunHeader::new(1505, 195102), ShortOffsetRunHeader::new(1506, 196608), - ShortOffsetRunHeader::new(1507, 201547), ShortOffsetRunHeader::new(1508, 205744), - ShortOffsetRunHeader::new(1510, 1319856), + ShortOffsetRunHeader::new(1246, 93504), ShortOffsetRunHeader::new(1261, 101590), + ShortOffsetRunHeader::new(1282, 110576), ShortOffsetRunHeader::new(1287, 110883), + ShortOffsetRunHeader::new(1294, 111356), ShortOffsetRunHeader::new(1304, 113664), + ShortOffsetRunHeader::new(1305, 119808), ShortOffsetRunHeader::new(1315, 120486), + ShortOffsetRunHeader::new(1352, 122624), ShortOffsetRunHeader::new(1375, 123536), + ShortOffsetRunHeader::new(1399, 124112), ShortOffsetRunHeader::new(1403, 126464), + ShortOffsetRunHeader::new(1431, 127280), ShortOffsetRunHeader::new(1497, 131072), + ShortOffsetRunHeader::new(1503, 173792), ShortOffsetRunHeader::new(1504, 178206), + ShortOffsetRunHeader::new(1506, 183982), ShortOffsetRunHeader::new(1508, 191457), + ShortOffsetRunHeader::new(1510, 192094), ShortOffsetRunHeader::new(1512, 194560), + ShortOffsetRunHeader::new(1513, 195102), ShortOffsetRunHeader::new(1514, 196608), + ShortOffsetRunHeader::new(1515, 201547), ShortOffsetRunHeader::new(1516, 210042), + ShortOffsetRunHeader::new(1518, 1324154), ]; - static OFFSETS: [u8; 1511] = [ + static OFFSETS: [u8; 1519] = [ 170, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 29, 18, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39, 14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10, 3, 2, 1, - 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 6, 8, 1, 8, 42, + 16, 48, 13, 101, 24, 33, 9, 2, 4, 1, 5, 24, 2, 19, 19, 25, 7, 11, 5, 24, 1, 7, 7, 1, 8, 42, 10, 12, 3, 7, 6, 76, 1, 16, 1, 3, 4, 15, 13, 19, 1, 8, 2, 2, 2, 22, 1, 7, 1, 1, 3, 4, 3, 8, 2, 2, 2, 2, 1, 1, 8, 1, 4, 2, 1, 5, 12, 2, 10, 1, 4, 3, 1, 6, 4, 2, 2, 22, 1, 7, 1, 2, 1, 2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1, 5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3, 12, - 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3, 2, - 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4, 13, 3, + 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3, 1, + 2, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 5, 3, 1, 4, 13, 3, 12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, 1, 9, 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, 1, 1, 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67, 55, 1, 1, 2, 5, @@ -201,37 +200,37 @@ pub mod alphabetic { 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23, 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4, 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10, 2, 20, 47, - 5, 8, 3, 113, 39, 9, 2, 103, 2, 67, 2, 2, 1, 1, 1, 8, 21, 20, 1, 33, 24, 52, 12, 68, 1, 1, - 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55, 9, 14, - 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43, 1, 14, - 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1, 1, 2, 1, - 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3, 6, 2, 6, - 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3, 49, 47, 32, - 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52, 12, 11, 1, - 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 3, 52, 12, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1, 9, - 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 70, 56, - 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10, 19, - 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 34, 28, 3, 1, 5, 23, 250, 42, 1, 2, 3, 2, 16, 3, - 55, 1, 3, 29, 10, 1, 8, 22, 42, 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, 13, 25, 23, - 51, 17, 4, 8, 35, 3, 1, 9, 64, 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 4, 62, 7, 1, - 1, 1, 4, 1, 15, 1, 10, 7, 57, 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, - 3, 1, 6, 1, 5, 7, 28, 10, 1, 1, 2, 1, 1, 38, 1, 10, 1, 1, 2, 1, 1, 4, 1, 2, 3, 1, 1, 1, 44, - 66, 1, 3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, - 2, 1, 71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, - 4, 93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 199, 33, 31, 9, 1, - 45, 1, 7, 1, 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, - 6, 1, 2, 1, 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, 102, 111, 17, - 196, 0, 97, 15, 0, 17, 6, 25, 0, 5, 0, 0, 47, 0, 0, 7, 31, 17, 79, 17, 30, 18, 48, 16, 4, - 31, 21, 5, 19, 0, 45, 211, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, 8, 0, 41, - 10, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9, 7, 10, 4, - 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, - 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, - 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45, 10, 7, 16, - 1, 0, 30, 18, 44, 0, 28, 228, 30, 2, 1, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, - 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, - 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32, 0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, - 5, 0, 0, + 5, 8, 3, 113, 39, 9, 2, 103, 2, 82, 20, 21, 1, 33, 24, 52, 12, 68, 1, 1, 44, 6, 3, 1, 1, 3, + 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55, 9, 14, 18, 23, 3, 69, 1, + 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43, 1, 14, 6, 123, 21, 0, 12, + 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1, 1, 2, 1, 2, 1, 108, 33, 0, + 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3, 6, 2, 6, 2, 6, 2, 3, 35, + 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3, 49, 47, 32, 13, 30, 5, 43, + 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52, 12, 11, 1, 15, 1, 7, 1, 2, + 1, 11, 1, 15, 1, 7, 1, 2, 3, 52, 12, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1, 9, 69, 6, 2, 1, 1, + 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 6, 26, 38, 56, 6, 2, 64, + 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10, 19, 13, 18, + 110, 73, 55, 51, 13, 51, 13, 40, 34, 28, 3, 1, 5, 23, 250, 42, 1, 2, 3, 2, 16, 6, 50, 3, 3, + 29, 10, 1, 8, 22, 42, 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, 13, 25, 23, 51, 17, 4, + 8, 35, 3, 1, 9, 64, 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 4, 62, 7, 1, 1, 1, 4, + 1, 15, 1, 10, 7, 57, 23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 3, 1, 6, + 1, 5, 7, 28, 10, 1, 1, 2, 1, 1, 38, 1, 10, 1, 1, 2, 1, 1, 4, 1, 2, 3, 1, 1, 1, 44, 66, 1, 3, + 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, 2, 1, 71, + 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, 4, 93, 8, + 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 103, 8, 88, 33, 31, 9, 1, 45, + 1, 7, 1, 1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, 6, + 1, 2, 1, 37, 1, 2, 1, 4, 1, 1, 23, 44, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, 102, 111, + 17, 196, 0, 97, 15, 0, 17, 6, 25, 0, 5, 0, 0, 47, 0, 0, 7, 31, 17, 79, 17, 30, 18, 48, 16, + 4, 31, 21, 5, 19, 0, 45, 211, 64, 32, 25, 2, 25, 44, 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 7, + 9, 0, 41, 32, 97, 115, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29, 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, + 13, 3, 9, 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, + 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, + 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, + 1, 112, 45, 10, 7, 16, 1, 0, 30, 18, 44, 0, 28, 228, 30, 2, 1, 207, 31, 1, 22, 8, 2, 224, 7, + 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, + 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, + 32, 0, 2, 0, 2, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0, ]; #[inline] pub fn lookup(c: char) -> bool { @@ -259,28 +258,27 @@ pub mod alphabetic { pub mod case_ignorable { use super::ShortOffsetRunHeader; - static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 37] = [ + static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 36] = [ ShortOffsetRunHeader::new(0, 688), ShortOffsetRunHeader::new(11, 4957), ShortOffsetRunHeader::new(263, 5906), ShortOffsetRunHeader::new(265, 8125), - ShortOffsetRunHeader::new(375, 11388), ShortOffsetRunHeader::new(409, 12293), - ShortOffsetRunHeader::new(421, 40981), ShortOffsetRunHeader::new(433, 42232), - ShortOffsetRunHeader::new(435, 42508), ShortOffsetRunHeader::new(437, 64286), - ShortOffsetRunHeader::new(533, 65024), ShortOffsetRunHeader::new(537, 66045), - ShortOffsetRunHeader::new(567, 67456), ShortOffsetRunHeader::new(573, 68097), - ShortOffsetRunHeader::new(579, 68900), ShortOffsetRunHeader::new(591, 69291), - ShortOffsetRunHeader::new(599, 71727), ShortOffsetRunHeader::new(723, 71995), - ShortOffsetRunHeader::new(727, 72752), ShortOffsetRunHeader::new(755, 73459), - ShortOffsetRunHeader::new(785, 78896), ShortOffsetRunHeader::new(797, 90398), - ShortOffsetRunHeader::new(801, 92912), ShortOffsetRunHeader::new(805, 93504), - ShortOffsetRunHeader::new(811, 94031), ShortOffsetRunHeader::new(815, 110576), - ShortOffsetRunHeader::new(823, 113821), ShortOffsetRunHeader::new(829, 118528), - ShortOffsetRunHeader::new(833, 119143), ShortOffsetRunHeader::new(837, 121344), - ShortOffsetRunHeader::new(847, 122880), ShortOffsetRunHeader::new(859, 123566), - ShortOffsetRunHeader::new(875, 124139), ShortOffsetRunHeader::new(879, 125136), - ShortOffsetRunHeader::new(883, 127995), ShortOffsetRunHeader::new(887, 917505), - ShortOffsetRunHeader::new(889, 2032112), + ShortOffsetRunHeader::new(377, 11388), ShortOffsetRunHeader::new(411, 12293), + ShortOffsetRunHeader::new(423, 40981), ShortOffsetRunHeader::new(435, 42232), + ShortOffsetRunHeader::new(437, 42508), ShortOffsetRunHeader::new(439, 64286), + ShortOffsetRunHeader::new(535, 65024), ShortOffsetRunHeader::new(539, 66045), + ShortOffsetRunHeader::new(569, 67456), ShortOffsetRunHeader::new(575, 68097), + ShortOffsetRunHeader::new(581, 68900), ShortOffsetRunHeader::new(593, 69291), + ShortOffsetRunHeader::new(601, 71727), ShortOffsetRunHeader::new(727, 71995), + ShortOffsetRunHeader::new(731, 73459), ShortOffsetRunHeader::new(797, 78896), + ShortOffsetRunHeader::new(809, 90398), ShortOffsetRunHeader::new(813, 92912), + ShortOffsetRunHeader::new(817, 93504), ShortOffsetRunHeader::new(823, 94031), + ShortOffsetRunHeader::new(827, 110576), ShortOffsetRunHeader::new(837, 113821), + ShortOffsetRunHeader::new(843, 118528), ShortOffsetRunHeader::new(847, 119143), + ShortOffsetRunHeader::new(851, 121344), ShortOffsetRunHeader::new(861, 122880), + ShortOffsetRunHeader::new(873, 123566), ShortOffsetRunHeader::new(889, 124139), + ShortOffsetRunHeader::new(893, 125136), ShortOffsetRunHeader::new(907, 127995), + ShortOffsetRunHeader::new(911, 917505), ShortOffsetRunHeader::new(913, 2032112), ]; - static OFFSETS: [u8; 895] = [ + static OFFSETS: [u8; 919] = [ 168, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2, 1, 1, 251, 7, 207, 1, 5, 1, 49, 45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35, 1, 10, 21, 16, 1, 101, 8, 1, 10, 1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24, 24, 43, 3, 44, 1, 7, 2, 5, 9, 41, @@ -292,28 +290,29 @@ pub mod case_ignorable { 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3, 29, 2, 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 3, 1, 5, 1, 45, 5, 51, 1, 65, 2, 34, 1, 118, 3, 4, 2, 9, 1, 6, 3, 219, 2, 2, 1, 58, - 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 31, 49, 4, 48, 1, 1, 5, 1, 1, 5, 1, 40, 9, - 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 64, 6, 82, 3, 1, 13, 1, 7, - 4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 101, 0, 1, 1, 3, 11, 3, 13, 3, 13, 3, 13, 2, 12, 5, 8, - 2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1, 16, 13, 51, 33, 0, 2, 113, 3, 125, 1, 15, - 1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6, 93, 3, 0, 1, 0, 6, 0, 1, 98, 4, 1, 10, 1, - 1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 103, 3, 3, 2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, - 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4, 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, 12, - 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9, - 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3, 1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1, - 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, - 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 38, 1, 26, 5, 1, 1, 0, 2, 79, 4, 70, 11, 49, 4, - 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, 50, 3, 36, 5, 1, 8, 62, - 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 3, - 1, 37, 7, 3, 5, 70, 6, 13, 1, 1, 1, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, - 2, 1, 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 1, 1, - 1, 2, 4, 1, 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, - 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, - 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 23, 1, 0, 17, 6, 15, 0, 12, 3, - 3, 0, 5, 59, 7, 9, 4, 0, 3, 40, 2, 0, 1, 63, 17, 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, - 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, - 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, 14, 0, 1, 61, 4, 0, 5, 254, 2, 0, 7, 109, 8, - 0, 5, 0, 1, 30, 96, 128, 240, 0, + 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 46, 2, 12, 20, 4, 48, 1, 1, 5, 1, 1, 5, 1, + 40, 9, 12, 2, 32, 4, 2, 2, 1, 3, 56, 1, 1, 2, 3, 1, 1, 3, 58, 8, 2, 2, 64, 6, 82, 3, 1, 13, + 1, 7, 4, 1, 6, 1, 3, 2, 50, 63, 13, 1, 34, 101, 0, 1, 1, 3, 11, 3, 13, 3, 13, 3, 13, 2, 12, + 5, 8, 2, 10, 1, 2, 1, 2, 5, 49, 5, 1, 10, 1, 1, 13, 1, 16, 13, 51, 33, 0, 2, 113, 3, 125, 1, + 15, 1, 96, 32, 47, 1, 0, 1, 36, 4, 3, 5, 5, 1, 93, 6, 93, 3, 0, 1, 0, 6, 0, 1, 98, 4, 1, 10, + 1, 1, 28, 4, 80, 2, 14, 34, 78, 1, 23, 3, 102, 4, 3, 2, 8, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, + 2, 26, 18, 13, 1, 38, 8, 25, 11, 46, 3, 48, 1, 2, 4, 2, 2, 17, 1, 21, 2, 66, 6, 2, 2, 2, 2, + 12, 1, 8, 1, 35, 1, 11, 1, 51, 1, 1, 3, 2, 2, 5, 2, 1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, + 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3, 1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, + 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3, 0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, + 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 38, 1, 26, 5, 1, 1, 0, 2, 24, 1, 52, 6, 70, 11, + 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, 50, 3, 36, 5, 1, + 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, + 2, 3, 1, 37, 7, 3, 5, 70, 6, 13, 1, 1, 1, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, + 1, 4, 2, 1, 2, 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, + 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, + 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 198, 1, 1, 3, 1, 1, 201, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, + 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 65, 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, + 1, 23, 1, 0, 17, 6, 15, 0, 12, 3, 3, 0, 5, 59, 7, 9, 4, 0, 3, 40, 2, 0, 1, 63, 17, 64, 2, 1, + 2, 13, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, + 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160, 14, + 0, 1, 61, 4, 0, 5, 254, 2, 243, 1, 2, 1, 7, 2, 5, 1, 9, 1, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, + 128, 240, 0, ]; #[inline] pub fn lookup(c: char) -> bool { @@ -346,24 +345,24 @@ pub mod cased { ShortOffsetRunHeader::new(61, 7296), ShortOffsetRunHeader::new(65, 7958), ShortOffsetRunHeader::new(74, 9398), ShortOffsetRunHeader::new(149, 11264), ShortOffsetRunHeader::new(151, 42560), ShortOffsetRunHeader::new(163, 43824), - ShortOffsetRunHeader::new(183, 64256), ShortOffsetRunHeader::new(189, 65313), - ShortOffsetRunHeader::new(193, 66560), ShortOffsetRunHeader::new(197, 67456), - ShortOffsetRunHeader::new(219, 68736), ShortOffsetRunHeader::new(227, 71840), - ShortOffsetRunHeader::new(235, 93760), ShortOffsetRunHeader::new(237, 119808), - ShortOffsetRunHeader::new(239, 120486), ShortOffsetRunHeader::new(276, 122624), - ShortOffsetRunHeader::new(299, 122928), ShortOffsetRunHeader::new(305, 125184), - ShortOffsetRunHeader::new(307, 127280), ShortOffsetRunHeader::new(309, 1241482), + ShortOffsetRunHeader::new(177, 64256), ShortOffsetRunHeader::new(183, 65313), + ShortOffsetRunHeader::new(187, 66560), ShortOffsetRunHeader::new(191, 67456), + ShortOffsetRunHeader::new(213, 68736), ShortOffsetRunHeader::new(221, 71840), + ShortOffsetRunHeader::new(229, 93760), ShortOffsetRunHeader::new(231, 119808), + ShortOffsetRunHeader::new(237, 120486), ShortOffsetRunHeader::new(274, 122624), + ShortOffsetRunHeader::new(297, 122928), ShortOffsetRunHeader::new(303, 125184), + ShortOffsetRunHeader::new(305, 127280), ShortOffsetRunHeader::new(307, 1241482), ]; - static OFFSETS: [u8; 315] = [ - 170, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5, 96, 1, 42, 4, + static OFFSETS: [u8; 313] = [ + 170, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 2, 35, 7, 2, 30, 5, 96, 1, 42, 4, 2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9, 41, 0, 38, 1, 1, 5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 11, 5, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2, 38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 0, 46, 18, 30, 132, - 102, 3, 4, 1, 62, 2, 2, 1, 1, 1, 8, 21, 5, 1, 3, 0, 43, 1, 14, 6, 80, 0, 7, 12, 5, 0, 26, 6, - 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 0, 1, 2, 3, - 1, 42, 1, 9, 0, 51, 13, 51, 93, 22, 10, 22, 0, 64, 0, 64, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, + 102, 3, 4, 1, 77, 20, 6, 1, 3, 0, 43, 1, 14, 6, 80, 0, 7, 12, 5, 0, 26, 6, 26, 0, 80, 96, + 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, + 51, 13, 51, 93, 22, 10, 22, 0, 64, 0, 64, 32, 25, 2, 25, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 6, 6, 0, 62, 0, 68, 0, 26, 6, 26, 6, 26, 0, @@ -394,26 +393,26 @@ pub mod cased { pub mod grapheme_extend { use super::ShortOffsetRunHeader; - static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 34] = [ + static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 33] = [ ShortOffsetRunHeader::new(0, 768), ShortOffsetRunHeader::new(1, 1155), ShortOffsetRunHeader::new(3, 1425), ShortOffsetRunHeader::new(5, 4957), ShortOffsetRunHeader::new(249, 5906), ShortOffsetRunHeader::new(251, 8204), - ShortOffsetRunHeader::new(345, 11503), ShortOffsetRunHeader::new(349, 12330), - ShortOffsetRunHeader::new(355, 42607), ShortOffsetRunHeader::new(359, 43010), - ShortOffsetRunHeader::new(367, 64286), ShortOffsetRunHeader::new(433, 65024), - ShortOffsetRunHeader::new(435, 65438), ShortOffsetRunHeader::new(439, 66045), - ShortOffsetRunHeader::new(441, 68097), ShortOffsetRunHeader::new(447, 68900), - ShortOffsetRunHeader::new(459, 69291), ShortOffsetRunHeader::new(463, 71727), - ShortOffsetRunHeader::new(599, 72752), ShortOffsetRunHeader::new(631, 73459), - ShortOffsetRunHeader::new(661, 78912), ShortOffsetRunHeader::new(671, 90398), - ShortOffsetRunHeader::new(675, 92912), ShortOffsetRunHeader::new(679, 94031), - ShortOffsetRunHeader::new(683, 113821), ShortOffsetRunHeader::new(691, 118528), - ShortOffsetRunHeader::new(693, 119141), ShortOffsetRunHeader::new(697, 121344), - ShortOffsetRunHeader::new(709, 122880), ShortOffsetRunHeader::new(721, 123566), - ShortOffsetRunHeader::new(735, 124140), ShortOffsetRunHeader::new(739, 125136), - ShortOffsetRunHeader::new(743, 917536), ShortOffsetRunHeader::new(747, 2032112), + ShortOffsetRunHeader::new(347, 11503), ShortOffsetRunHeader::new(351, 12330), + ShortOffsetRunHeader::new(357, 42607), ShortOffsetRunHeader::new(361, 43010), + ShortOffsetRunHeader::new(369, 64286), ShortOffsetRunHeader::new(435, 65024), + ShortOffsetRunHeader::new(437, 65438), ShortOffsetRunHeader::new(441, 66045), + ShortOffsetRunHeader::new(443, 68097), ShortOffsetRunHeader::new(449, 68900), + ShortOffsetRunHeader::new(461, 69291), ShortOffsetRunHeader::new(465, 71727), + ShortOffsetRunHeader::new(601, 73459), ShortOffsetRunHeader::new(669, 78912), + ShortOffsetRunHeader::new(679, 90398), ShortOffsetRunHeader::new(683, 92912), + ShortOffsetRunHeader::new(687, 94031), ShortOffsetRunHeader::new(691, 113821), + ShortOffsetRunHeader::new(699, 118528), ShortOffsetRunHeader::new(701, 119141), + ShortOffsetRunHeader::new(705, 121344), ShortOffsetRunHeader::new(717, 122880), + ShortOffsetRunHeader::new(729, 123566), ShortOffsetRunHeader::new(743, 124140), + ShortOffsetRunHeader::new(747, 125136), ShortOffsetRunHeader::new(759, 917536), + ShortOffsetRunHeader::new(763, 2032112), ]; - static OFFSETS: [u8; 751] = [ + static OFFSETS: [u8; 767] = [ 0, 112, 0, 7, 0, 45, 1, 1, 1, 2, 1, 2, 1, 1, 72, 11, 48, 21, 16, 1, 101, 7, 2, 6, 2, 2, 1, 4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 59, 9, 42, 24, 1, 32, 55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 29, 1, 58, 1, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 26, 1, 2, @@ -424,23 +423,24 @@ pub mod grapheme_extend { 12, 8, 98, 1, 2, 9, 11, 7, 73, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1, 102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 4, 28, 3, 29, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 1, 1, 117, 2, 34, 1, 118, 3, 4, 2, 9, - 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 31, 49, 4, 48, 10, 4, - 3, 38, 9, 12, 2, 32, 4, 2, 6, 56, 1, 1, 2, 3, 1, 1, 5, 56, 8, 2, 2, 152, 3, 1, 13, 1, 7, 4, - 1, 6, 1, 3, 2, 198, 64, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, 4, 1, 10, 32, - 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 1, 1, 44, 3, - 48, 1, 2, 4, 2, 2, 2, 1, 36, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2, 5, - 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149, 5, - 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 65, 5, 0, 2, 79, 4, 70, 11, 49, 4, 123, 1, 54, - 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 1, 1, 8, - 4, 2, 1, 95, 3, 2, 4, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 12, 1, 9, 1, 14, - 7, 3, 5, 67, 1, 2, 6, 1, 1, 2, 1, 1, 3, 4, 3, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, 81, 1, - 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, - 1, 2, 8, 101, 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 4, 4, 1, 144, 4, 2, 2, 4, 1, 32, - 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, - 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 3, 23, 1, 0, 1, 6, - 15, 0, 12, 3, 3, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 11, 2, 0, 2, 0, 46, 2, 23, 0, 5, 3, 6, 8, - 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, - 5, 100, 1, 160, 7, 0, 1, 61, 4, 0, 4, 254, 2, 0, 7, 109, 7, 0, 96, 128, 240, 0, + 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 46, 2, 12, 20, 4, 48, + 10, 4, 3, 38, 9, 12, 2, 32, 4, 2, 6, 56, 1, 1, 2, 3, 1, 1, 5, 56, 8, 2, 2, 152, 3, 1, 13, 1, + 7, 4, 1, 6, 1, 3, 2, 198, 64, 0, 1, 195, 33, 0, 3, 141, 1, 96, 32, 0, 6, 105, 2, 0, 4, 1, + 10, 32, 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11, 1, 1, + 44, 3, 48, 1, 2, 4, 2, 2, 2, 1, 36, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, + 2, 2, 5, 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, + 149, 5, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 65, 5, 0, 2, 77, 6, 70, 11, 49, 4, 123, + 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, + 1, 1, 8, 4, 2, 1, 95, 3, 2, 4, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 12, 1, 9, + 1, 14, 7, 3, 5, 67, 1, 2, 6, 1, 1, 2, 1, 1, 3, 4, 3, 1, 1, 14, 2, 85, 8, 2, 3, 1, 1, 23, 1, + 81, 1, 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, + 106, 1, 1, 1, 2, 8, 101, 1, 1, 1, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 4, 4, 1, 144, 4, 2, 2, + 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 198, 1, 1, 3, 1, 1, 201, 7, 1, 6, + 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 11, + 2, 52, 5, 5, 3, 23, 1, 0, 1, 6, 15, 0, 12, 3, 3, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 11, 2, 0, + 2, 0, 46, 2, 23, 0, 5, 3, 6, 8, 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, + 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 100, 1, 160, 7, 0, 1, 61, 4, 0, 4, 254, 2, 243, 1, 2, 1, + 7, 2, 5, 1, 0, 7, 109, 7, 0, 96, 128, 240, 0, ]; #[inline] pub fn lookup(c: char) -> bool { @@ -475,27 +475,27 @@ pub mod lowercase { ]; static BITSET_INDEX_CHUNKS: [[u8; 16]; 20] = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 56, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 43, 0, 52, 48, 50, 33], - [0, 0, 0, 0, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 3, 0, 16, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27], - [0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 34, 17, 23, 53, 54, 49, 47, 7, 35, 42, 0, 28, 12, 31], - [0, 0, 46, 0, 56, 56, 56, 0, 22, 22, 69, 22, 36, 25, 24, 37], - [0, 5, 70, 0, 29, 15, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [10, 60, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0], - [16, 26, 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 51, 2, 21, 68, 8, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [16, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [65, 41, 55, 11, 66, 63, 18, 13, 1, 64, 76, 20, 73, 74, 4, 45], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 57, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 19, 62, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 44, 0, 53, 49, 51, 34], + [0, 0, 0, 0, 9, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 3, 0, 16, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28], + [0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 35, 17, 24, 54, 55, 50, 48, 7, 36, 43, 0, 29, 12, 32], + [0, 0, 47, 0, 57, 57, 57, 0, 23, 23, 71, 23, 37, 26, 25, 38], + [0, 5, 72, 0, 30, 15, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [10, 61, 0, 6, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 33, 0], + [16, 27, 23, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [16, 52, 2, 22, 70, 8, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [16, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [67, 42, 56, 11, 68, 65, 18, 13, 1, 66, 78, 21, 75, 76, 4, 46], ]; - static BITSET_CANONICAL: [u64; 56] = [ + static BITSET_CANONICAL: [u64; 57] = [ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b0000111111111111111111111111110000000000000000000000000011111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -515,6 +515,7 @@ pub mod lowercase { 0b1111111111111111000000000000000000000000000000000000000000000000, 0b1111111101111111111111111111111110000000000000000000000000000000, 0b1111110000000000000000000000000011111111111111111111111111000000, + 0b1111100000000000000000000000000000000000000000000000000000000000, 0b1111011111111111111111111111111111111111111111110000000000000000, 0b1111000000000000000000000000001111110111111111111111111111111100, 0b1010101010101010101010101010101010101010101010101101010101010100, @@ -529,9 +530,9 @@ pub mod lowercase { 0b0001101111111011111111111111101111111111100000000000000000000000, 0b0001100100101111101010101010101010101010111000110111111111111111, 0b0000011111111101111111111111111111111111111111111111111110111001, - 0b0000011101011100000000000000000000001010101010100010010100001010, + 0b0000011101011110000000000000000000001010101010101010010100001010, 0b0000010000100000000001000000000000000000000000000000000000000000, - 0b0000000111111111111111111111111111111111111011111111111111111111, + 0b0000000111111111111111111111111111111111110011111111111111111111, 0b0000000011111111000000001111111100000000001111110000000011111111, 0b0000000011011100000000001111111100000000110011110000000011011100, 0b0000000000001000010100000001101010101010101010101010101010101010, @@ -553,10 +554,10 @@ pub mod lowercase { 0b1110011001010001001011010010101001001110001001000011000100101001, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - static BITSET_MAPPING: [(u8, u8); 21] = [ - (0, 64), (1, 184), (1, 182), (1, 179), (1, 172), (1, 161), (1, 146), (1, 144), (1, 140), - (1, 136), (1, 132), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), - (4, 6), (5, 187), (6, 78), + static BITSET_MAPPING: [(u8, u8); 22] = [ + (0, 64), (1, 184), (1, 182), (1, 179), (1, 172), (1, 168), (1, 161), (1, 146), (1, 144), + (1, 140), (1, 136), (1, 132), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), + (4, 12), (4, 6), (5, 187), (6, 78), ]; pub const fn lookup(c: char) -> bool { @@ -576,7 +577,7 @@ pub mod lowercase { pub mod n { use super::ShortOffsetRunHeader; - static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 42] = [ + static SHORT_OFFSET_RUNS: [ShortOffsetRunHeader; 43] = [ ShortOffsetRunHeader::new(0, 1632), ShortOffsetRunHeader::new(7, 2406), ShortOffsetRunHeader::new(13, 4160), ShortOffsetRunHeader::new(47, 4969), ShortOffsetRunHeader::new(51, 5870), ShortOffsetRunHeader::new(53, 6470), @@ -590,16 +591,17 @@ pub mod n { ShortOffsetRunHeader::new(181, 69216), ShortOffsetRunHeader::new(187, 70736), ShortOffsetRunHeader::new(207, 71248), ShortOffsetRunHeader::new(211, 71904), ShortOffsetRunHeader::new(219, 72688), ShortOffsetRunHeader::new(223, 73552), - ShortOffsetRunHeader::new(231, 74752), ShortOffsetRunHeader::new(235, 90416), - ShortOffsetRunHeader::new(237, 92768), ShortOffsetRunHeader::new(239, 93552), - ShortOffsetRunHeader::new(247, 93824), ShortOffsetRunHeader::new(249, 118000), - ShortOffsetRunHeader::new(251, 119488), ShortOffsetRunHeader::new(253, 120782), - ShortOffsetRunHeader::new(259, 123200), ShortOffsetRunHeader::new(261, 123632), - ShortOffsetRunHeader::new(263, 124144), ShortOffsetRunHeader::new(265, 125127), - ShortOffsetRunHeader::new(269, 126065), ShortOffsetRunHeader::new(273, 127232), - ShortOffsetRunHeader::new(283, 130032), ShortOffsetRunHeader::new(285, 1244154), + ShortOffsetRunHeader::new(233, 74752), ShortOffsetRunHeader::new(237, 90416), + ShortOffsetRunHeader::new(239, 92768), ShortOffsetRunHeader::new(241, 93552), + ShortOffsetRunHeader::new(249, 93824), ShortOffsetRunHeader::new(251, 94196), + ShortOffsetRunHeader::new(253, 118000), ShortOffsetRunHeader::new(255, 119488), + ShortOffsetRunHeader::new(257, 120782), ShortOffsetRunHeader::new(263, 123200), + ShortOffsetRunHeader::new(265, 123632), ShortOffsetRunHeader::new(267, 124144), + ShortOffsetRunHeader::new(269, 125127), ShortOffsetRunHeader::new(273, 126065), + ShortOffsetRunHeader::new(277, 127232), ShortOffsetRunHeader::new(287, 130032), + ShortOffsetRunHeader::new(289, 1244154), ]; - static OFFSETS: [u8; 287] = [ + static OFFSETS: [u8; 291] = [ 178, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118, 10, 118, 10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10, 70, 20, 0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10, 182, 10, @@ -609,9 +611,9 @@ pub mod n { 1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9, 52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 6, 10, 0, 31, 158, 10, 42, 4, 112, 7, 134, 30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 6, 20, 76, 12, - 0, 19, 93, 10, 0, 10, 86, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 0, 10, 86, 10, - 134, 10, 1, 7, 0, 10, 0, 23, 0, 10, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 10, 247, - 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0, + 0, 19, 93, 10, 0, 10, 86, 29, 227, 10, 70, 10, 54, 10, 0, 10, 102, 21, 0, 111, 0, 10, 0, 10, + 86, 10, 134, 10, 1, 7, 0, 10, 0, 23, 0, 3, 0, 10, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, + 10, 0, 10, 247, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0, 10, 0, ]; #[inline] pub fn lookup(c: char) -> bool { @@ -647,28 +649,28 @@ pub mod uppercase { static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ [44, 44, 5, 35, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 5, 0], [44, 44, 5, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], - [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 62, 17, 43, 29, 24, 23], + [44, 44, 40, 44, 44, 44, 44, 44, 17, 17, 66, 17, 43, 29, 24, 23], [44, 44, 44, 32, 36, 21, 22, 15, 13, 34, 44, 44, 44, 11, 30, 39], [44, 44, 44, 44, 9, 8, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44], - [44, 44, 44, 44, 37, 28, 66, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 37, 28, 67, 44, 44, 44, 44, 44, 44, 44, 44, 44], [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 57, 44, 44, 44], - [44, 44, 44, 44, 44, 44, 44, 44, 44, 49, 44, 44, 44, 44, 44, 44], - [44, 44, 44, 44, 44, 44, 44, 44, 44, 61, 60, 44, 20, 14, 16, 4], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 49, 63, 44, 44, 44, 44, 44], + [44, 44, 44, 44, 44, 44, 44, 44, 44, 65, 64, 44, 20, 14, 16, 4], [44, 44, 44, 44, 50, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [44, 44, 53, 44, 44, 31, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [44, 44, 54, 46, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [51, 44, 9, 47, 44, 42, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44], - [52, 19, 2, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], + [52, 19, 3, 18, 10, 48, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], [52, 38, 17, 27, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44], - [58, 1, 26, 55, 12, 7, 25, 56, 41, 59, 6, 3, 65, 64, 63, 67], + [58, 1, 26, 55, 12, 7, 25, 56, 41, 59, 6, 2, 62, 61, 60, 68], ]; static BITSET_CANONICAL: [u64; 44] = [ 0b0000000000111111111111111111111111111111111111111111111111111111, 0b1111111111111111111111110000000000000000000000000011111111111111, - 0b0101010101010101010101010101010101010101010101010101010000000001, 0b0000011111111111111111111111110000000000000000000000000000000001, - 0b0000000000100000000000000000000000010101010000010001101011110101, + 0b0101010101010101010101010101010101010101010101010101010000000001, + 0b0000000000100000000000000000000000010101010101010101101011110101, 0b1111111111111111111111111111111100000000000000000000000000000000, 0b1111111111111111111111110000000000000000000000000000001111111111, 0b1111111111111111111100000000000000000000000000011111110001011111, @@ -709,10 +711,10 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - static BITSET_MAPPING: [(u8, u8); 24] = [ + static BITSET_MAPPING: [(u8, u8); 25] = [ (0, 182), (0, 74), (0, 166), (0, 162), (0, 159), (0, 150), (0, 148), (0, 142), (0, 134), - (0, 131), (0, 64), (1, 66), (1, 70), (1, 83), (1, 12), (1, 8), (2, 164), (2, 146), (2, 20), - (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), + (0, 131), (0, 64), (1, 66), (1, 70), (1, 83), (1, 12), (1, 8), (2, 146), (2, 140), (2, 134), + (2, 130), (3, 164), (3, 146), (3, 20), (4, 178), (4, 171), ]; pub const fn lookup(c: char) -> bool { @@ -792,7 +794,7 @@ pub mod conversions { } } - static LOWERCASE_TABLE: &[(char, u32); 1434] = &[ + static LOWERCASE_TABLE: &[(char, u32); 1462] = &[ ('\u{c0}', 224), ('\u{c1}', 225), ('\u{c2}', 226), ('\u{c3}', 227), ('\u{c4}', 228), ('\u{c5}', 229), ('\u{c6}', 230), ('\u{c7}', 231), ('\u{c8}', 232), ('\u{c9}', 233), ('\u{ca}', 234), ('\u{cb}', 235), ('\u{cc}', 236), ('\u{cd}', 237), ('\u{ce}', 238), @@ -1060,77 +1062,84 @@ pub mod conversions { ('\u{a7b4}', 42933), ('\u{a7b6}', 42935), ('\u{a7b8}', 42937), ('\u{a7ba}', 42939), ('\u{a7bc}', 42941), ('\u{a7be}', 42943), ('\u{a7c0}', 42945), ('\u{a7c2}', 42947), ('\u{a7c4}', 42900), ('\u{a7c5}', 642), ('\u{a7c6}', 7566), ('\u{a7c7}', 42952), - ('\u{a7c9}', 42954), ('\u{a7cb}', 612), ('\u{a7cc}', 42957), ('\u{a7d0}', 42961), - ('\u{a7d6}', 42967), ('\u{a7d8}', 42969), ('\u{a7da}', 42971), ('\u{a7dc}', 411), - ('\u{a7f5}', 42998), ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), - ('\u{ff24}', 65348), ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), - ('\u{ff28}', 65352), ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), - ('\u{ff2c}', 65356), ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), - ('\u{ff30}', 65360), ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), - ('\u{ff34}', 65364), ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), - ('\u{ff38}', 65368), ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), - ('\u{10401}', 66601), ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), - ('\u{10405}', 66605), ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), - ('\u{10409}', 66609), ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), - ('\u{1040d}', 66613), ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), - ('\u{10411}', 66617), ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), - ('\u{10415}', 66621), ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), - ('\u{10419}', 66625), ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), - ('\u{1041d}', 66629), ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), - ('\u{10421}', 66633), ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), - ('\u{10425}', 66637), ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), - ('\u{104b1}', 66777), ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), - ('\u{104b5}', 66781), ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), - ('\u{104b9}', 66785), ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), - ('\u{104bd}', 66789), ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), - ('\u{104c1}', 66793), ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), - ('\u{104c5}', 66797), ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), - ('\u{104c9}', 66801), ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), - ('\u{104cd}', 66805), ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), - ('\u{104d1}', 66809), ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), - ('\u{10571}', 66968), ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), - ('\u{10575}', 66972), ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), - ('\u{10579}', 66976), ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), - ('\u{1057e}', 66981), ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), - ('\u{10582}', 66985), ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), - ('\u{10586}', 66989), ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), - ('\u{1058a}', 66993), ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), - ('\u{1058f}', 66998), ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), - ('\u{10594}', 67003), ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), - ('\u{10c82}', 68802), ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), - ('\u{10c86}', 68806), ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), - ('\u{10c8a}', 68810), ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), - ('\u{10c8e}', 68814), ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), - ('\u{10c92}', 68818), ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), - ('\u{10c96}', 68822), ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), - ('\u{10c9a}', 68826), ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), - ('\u{10c9e}', 68830), ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), - ('\u{10ca2}', 68834), ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), - ('\u{10ca6}', 68838), ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), - ('\u{10caa}', 68842), ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), - ('\u{10cae}', 68846), ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), - ('\u{10cb2}', 68850), ('\u{10d50}', 68976), ('\u{10d51}', 68977), ('\u{10d52}', 68978), - ('\u{10d53}', 68979), ('\u{10d54}', 68980), ('\u{10d55}', 68981), ('\u{10d56}', 68982), - ('\u{10d57}', 68983), ('\u{10d58}', 68984), ('\u{10d59}', 68985), ('\u{10d5a}', 68986), - ('\u{10d5b}', 68987), ('\u{10d5c}', 68988), ('\u{10d5d}', 68989), ('\u{10d5e}', 68990), - ('\u{10d5f}', 68991), ('\u{10d60}', 68992), ('\u{10d61}', 68993), ('\u{10d62}', 68994), - ('\u{10d63}', 68995), ('\u{10d64}', 68996), ('\u{10d65}', 68997), ('\u{118a0}', 71872), - ('\u{118a1}', 71873), ('\u{118a2}', 71874), ('\u{118a3}', 71875), ('\u{118a4}', 71876), - ('\u{118a5}', 71877), ('\u{118a6}', 71878), ('\u{118a7}', 71879), ('\u{118a8}', 71880), - ('\u{118a9}', 71881), ('\u{118aa}', 71882), ('\u{118ab}', 71883), ('\u{118ac}', 71884), - ('\u{118ad}', 71885), ('\u{118ae}', 71886), ('\u{118af}', 71887), ('\u{118b0}', 71888), - ('\u{118b1}', 71889), ('\u{118b2}', 71890), ('\u{118b3}', 71891), ('\u{118b4}', 71892), - ('\u{118b5}', 71893), ('\u{118b6}', 71894), ('\u{118b7}', 71895), ('\u{118b8}', 71896), - ('\u{118b9}', 71897), ('\u{118ba}', 71898), ('\u{118bb}', 71899), ('\u{118bc}', 71900), - ('\u{118bd}', 71901), ('\u{118be}', 71902), ('\u{118bf}', 71903), ('\u{16e40}', 93792), - ('\u{16e41}', 93793), ('\u{16e42}', 93794), ('\u{16e43}', 93795), ('\u{16e44}', 93796), - ('\u{16e45}', 93797), ('\u{16e46}', 93798), ('\u{16e47}', 93799), ('\u{16e48}', 93800), - ('\u{16e49}', 93801), ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), ('\u{16e4c}', 93804), - ('\u{16e4d}', 93805), ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), ('\u{16e50}', 93808), - ('\u{16e51}', 93809), ('\u{16e52}', 93810), ('\u{16e53}', 93811), ('\u{16e54}', 93812), - ('\u{16e55}', 93813), ('\u{16e56}', 93814), ('\u{16e57}', 93815), ('\u{16e58}', 93816), - ('\u{16e59}', 93817), ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), ('\u{16e5c}', 93820), - ('\u{16e5d}', 93821), ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), ('\u{1e900}', 125218), + ('\u{a7c9}', 42954), ('\u{a7cb}', 612), ('\u{a7cc}', 42957), ('\u{a7ce}', 42959), + ('\u{a7d0}', 42961), ('\u{a7d2}', 42963), ('\u{a7d4}', 42965), ('\u{a7d6}', 42967), + ('\u{a7d8}', 42969), ('\u{a7da}', 42971), ('\u{a7dc}', 411), ('\u{a7f5}', 42998), + ('\u{ff21}', 65345), ('\u{ff22}', 65346), ('\u{ff23}', 65347), ('\u{ff24}', 65348), + ('\u{ff25}', 65349), ('\u{ff26}', 65350), ('\u{ff27}', 65351), ('\u{ff28}', 65352), + ('\u{ff29}', 65353), ('\u{ff2a}', 65354), ('\u{ff2b}', 65355), ('\u{ff2c}', 65356), + ('\u{ff2d}', 65357), ('\u{ff2e}', 65358), ('\u{ff2f}', 65359), ('\u{ff30}', 65360), + ('\u{ff31}', 65361), ('\u{ff32}', 65362), ('\u{ff33}', 65363), ('\u{ff34}', 65364), + ('\u{ff35}', 65365), ('\u{ff36}', 65366), ('\u{ff37}', 65367), ('\u{ff38}', 65368), + ('\u{ff39}', 65369), ('\u{ff3a}', 65370), ('\u{10400}', 66600), ('\u{10401}', 66601), + ('\u{10402}', 66602), ('\u{10403}', 66603), ('\u{10404}', 66604), ('\u{10405}', 66605), + ('\u{10406}', 66606), ('\u{10407}', 66607), ('\u{10408}', 66608), ('\u{10409}', 66609), + ('\u{1040a}', 66610), ('\u{1040b}', 66611), ('\u{1040c}', 66612), ('\u{1040d}', 66613), + ('\u{1040e}', 66614), ('\u{1040f}', 66615), ('\u{10410}', 66616), ('\u{10411}', 66617), + ('\u{10412}', 66618), ('\u{10413}', 66619), ('\u{10414}', 66620), ('\u{10415}', 66621), + ('\u{10416}', 66622), ('\u{10417}', 66623), ('\u{10418}', 66624), ('\u{10419}', 66625), + ('\u{1041a}', 66626), ('\u{1041b}', 66627), ('\u{1041c}', 66628), ('\u{1041d}', 66629), + ('\u{1041e}', 66630), ('\u{1041f}', 66631), ('\u{10420}', 66632), ('\u{10421}', 66633), + ('\u{10422}', 66634), ('\u{10423}', 66635), ('\u{10424}', 66636), ('\u{10425}', 66637), + ('\u{10426}', 66638), ('\u{10427}', 66639), ('\u{104b0}', 66776), ('\u{104b1}', 66777), + ('\u{104b2}', 66778), ('\u{104b3}', 66779), ('\u{104b4}', 66780), ('\u{104b5}', 66781), + ('\u{104b6}', 66782), ('\u{104b7}', 66783), ('\u{104b8}', 66784), ('\u{104b9}', 66785), + ('\u{104ba}', 66786), ('\u{104bb}', 66787), ('\u{104bc}', 66788), ('\u{104bd}', 66789), + ('\u{104be}', 66790), ('\u{104bf}', 66791), ('\u{104c0}', 66792), ('\u{104c1}', 66793), + ('\u{104c2}', 66794), ('\u{104c3}', 66795), ('\u{104c4}', 66796), ('\u{104c5}', 66797), + ('\u{104c6}', 66798), ('\u{104c7}', 66799), ('\u{104c8}', 66800), ('\u{104c9}', 66801), + ('\u{104ca}', 66802), ('\u{104cb}', 66803), ('\u{104cc}', 66804), ('\u{104cd}', 66805), + ('\u{104ce}', 66806), ('\u{104cf}', 66807), ('\u{104d0}', 66808), ('\u{104d1}', 66809), + ('\u{104d2}', 66810), ('\u{104d3}', 66811), ('\u{10570}', 66967), ('\u{10571}', 66968), + ('\u{10572}', 66969), ('\u{10573}', 66970), ('\u{10574}', 66971), ('\u{10575}', 66972), + ('\u{10576}', 66973), ('\u{10577}', 66974), ('\u{10578}', 66975), ('\u{10579}', 66976), + ('\u{1057a}', 66977), ('\u{1057c}', 66979), ('\u{1057d}', 66980), ('\u{1057e}', 66981), + ('\u{1057f}', 66982), ('\u{10580}', 66983), ('\u{10581}', 66984), ('\u{10582}', 66985), + ('\u{10583}', 66986), ('\u{10584}', 66987), ('\u{10585}', 66988), ('\u{10586}', 66989), + ('\u{10587}', 66990), ('\u{10588}', 66991), ('\u{10589}', 66992), ('\u{1058a}', 66993), + ('\u{1058c}', 66995), ('\u{1058d}', 66996), ('\u{1058e}', 66997), ('\u{1058f}', 66998), + ('\u{10590}', 66999), ('\u{10591}', 67000), ('\u{10592}', 67001), ('\u{10594}', 67003), + ('\u{10595}', 67004), ('\u{10c80}', 68800), ('\u{10c81}', 68801), ('\u{10c82}', 68802), + ('\u{10c83}', 68803), ('\u{10c84}', 68804), ('\u{10c85}', 68805), ('\u{10c86}', 68806), + ('\u{10c87}', 68807), ('\u{10c88}', 68808), ('\u{10c89}', 68809), ('\u{10c8a}', 68810), + ('\u{10c8b}', 68811), ('\u{10c8c}', 68812), ('\u{10c8d}', 68813), ('\u{10c8e}', 68814), + ('\u{10c8f}', 68815), ('\u{10c90}', 68816), ('\u{10c91}', 68817), ('\u{10c92}', 68818), + ('\u{10c93}', 68819), ('\u{10c94}', 68820), ('\u{10c95}', 68821), ('\u{10c96}', 68822), + ('\u{10c97}', 68823), ('\u{10c98}', 68824), ('\u{10c99}', 68825), ('\u{10c9a}', 68826), + ('\u{10c9b}', 68827), ('\u{10c9c}', 68828), ('\u{10c9d}', 68829), ('\u{10c9e}', 68830), + ('\u{10c9f}', 68831), ('\u{10ca0}', 68832), ('\u{10ca1}', 68833), ('\u{10ca2}', 68834), + ('\u{10ca3}', 68835), ('\u{10ca4}', 68836), ('\u{10ca5}', 68837), ('\u{10ca6}', 68838), + ('\u{10ca7}', 68839), ('\u{10ca8}', 68840), ('\u{10ca9}', 68841), ('\u{10caa}', 68842), + ('\u{10cab}', 68843), ('\u{10cac}', 68844), ('\u{10cad}', 68845), ('\u{10cae}', 68846), + ('\u{10caf}', 68847), ('\u{10cb0}', 68848), ('\u{10cb1}', 68849), ('\u{10cb2}', 68850), + ('\u{10d50}', 68976), ('\u{10d51}', 68977), ('\u{10d52}', 68978), ('\u{10d53}', 68979), + ('\u{10d54}', 68980), ('\u{10d55}', 68981), ('\u{10d56}', 68982), ('\u{10d57}', 68983), + ('\u{10d58}', 68984), ('\u{10d59}', 68985), ('\u{10d5a}', 68986), ('\u{10d5b}', 68987), + ('\u{10d5c}', 68988), ('\u{10d5d}', 68989), ('\u{10d5e}', 68990), ('\u{10d5f}', 68991), + ('\u{10d60}', 68992), ('\u{10d61}', 68993), ('\u{10d62}', 68994), ('\u{10d63}', 68995), + ('\u{10d64}', 68996), ('\u{10d65}', 68997), ('\u{118a0}', 71872), ('\u{118a1}', 71873), + ('\u{118a2}', 71874), ('\u{118a3}', 71875), ('\u{118a4}', 71876), ('\u{118a5}', 71877), + ('\u{118a6}', 71878), ('\u{118a7}', 71879), ('\u{118a8}', 71880), ('\u{118a9}', 71881), + ('\u{118aa}', 71882), ('\u{118ab}', 71883), ('\u{118ac}', 71884), ('\u{118ad}', 71885), + ('\u{118ae}', 71886), ('\u{118af}', 71887), ('\u{118b0}', 71888), ('\u{118b1}', 71889), + ('\u{118b2}', 71890), ('\u{118b3}', 71891), ('\u{118b4}', 71892), ('\u{118b5}', 71893), + ('\u{118b6}', 71894), ('\u{118b7}', 71895), ('\u{118b8}', 71896), ('\u{118b9}', 71897), + ('\u{118ba}', 71898), ('\u{118bb}', 71899), ('\u{118bc}', 71900), ('\u{118bd}', 71901), + ('\u{118be}', 71902), ('\u{118bf}', 71903), ('\u{16e40}', 93792), ('\u{16e41}', 93793), + ('\u{16e42}', 93794), ('\u{16e43}', 93795), ('\u{16e44}', 93796), ('\u{16e45}', 93797), + ('\u{16e46}', 93798), ('\u{16e47}', 93799), ('\u{16e48}', 93800), ('\u{16e49}', 93801), + ('\u{16e4a}', 93802), ('\u{16e4b}', 93803), ('\u{16e4c}', 93804), ('\u{16e4d}', 93805), + ('\u{16e4e}', 93806), ('\u{16e4f}', 93807), ('\u{16e50}', 93808), ('\u{16e51}', 93809), + ('\u{16e52}', 93810), ('\u{16e53}', 93811), ('\u{16e54}', 93812), ('\u{16e55}', 93813), + ('\u{16e56}', 93814), ('\u{16e57}', 93815), ('\u{16e58}', 93816), ('\u{16e59}', 93817), + ('\u{16e5a}', 93818), ('\u{16e5b}', 93819), ('\u{16e5c}', 93820), ('\u{16e5d}', 93821), + ('\u{16e5e}', 93822), ('\u{16e5f}', 93823), ('\u{16ea0}', 93883), ('\u{16ea1}', 93884), + ('\u{16ea2}', 93885), ('\u{16ea3}', 93886), ('\u{16ea4}', 93887), ('\u{16ea5}', 93888), + ('\u{16ea6}', 93889), ('\u{16ea7}', 93890), ('\u{16ea8}', 93891), ('\u{16ea9}', 93892), + ('\u{16eaa}', 93893), ('\u{16eab}', 93894), ('\u{16eac}', 93895), ('\u{16ead}', 93896), + ('\u{16eae}', 93897), ('\u{16eaf}', 93898), ('\u{16eb0}', 93899), ('\u{16eb1}', 93900), + ('\u{16eb2}', 93901), ('\u{16eb3}', 93902), ('\u{16eb4}', 93903), ('\u{16eb5}', 93904), + ('\u{16eb6}', 93905), ('\u{16eb7}', 93906), ('\u{16eb8}', 93907), ('\u{1e900}', 125218), ('\u{1e901}', 125219), ('\u{1e902}', 125220), ('\u{1e903}', 125221), ('\u{1e904}', 125222), ('\u{1e905}', 125223), ('\u{1e906}', 125224), ('\u{1e907}', 125225), ('\u{1e908}', 125226), ('\u{1e909}', 125227), ('\u{1e90a}', 125228), ('\u{1e90b}', 125229), ('\u{1e90c}', 125230), @@ -1146,7 +1155,7 @@ pub mod conversions { ['i', '\u{307}', '\u{0}'], ]; - static UPPERCASE_TABLE: &[(char, u32); 1526] = &[ + static UPPERCASE_TABLE: &[(char, u32); 1554] = &[ ('\u{b5}', 924), ('\u{df}', 4194304), ('\u{e0}', 192), ('\u{e1}', 193), ('\u{e2}', 194), ('\u{e3}', 195), ('\u{e4}', 196), ('\u{e5}', 197), ('\u{e6}', 198), ('\u{e7}', 199), ('\u{e8}', 200), ('\u{e9}', 201), ('\u{ea}', 202), ('\u{eb}', 203), ('\u{ec}', 204), @@ -1415,100 +1424,107 @@ pub mod conversions { ('\u{a7a7}', 42918), ('\u{a7a9}', 42920), ('\u{a7b5}', 42932), ('\u{a7b7}', 42934), ('\u{a7b9}', 42936), ('\u{a7bb}', 42938), ('\u{a7bd}', 42940), ('\u{a7bf}', 42942), ('\u{a7c1}', 42944), ('\u{a7c3}', 42946), ('\u{a7c8}', 42951), ('\u{a7ca}', 42953), - ('\u{a7cd}', 42956), ('\u{a7d1}', 42960), ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), - ('\u{a7db}', 42970), ('\u{a7f6}', 42997), ('\u{ab53}', 42931), ('\u{ab70}', 5024), - ('\u{ab71}', 5025), ('\u{ab72}', 5026), ('\u{ab73}', 5027), ('\u{ab74}', 5028), - ('\u{ab75}', 5029), ('\u{ab76}', 5030), ('\u{ab77}', 5031), ('\u{ab78}', 5032), - ('\u{ab79}', 5033), ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), ('\u{ab7c}', 5036), - ('\u{ab7d}', 5037), ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), ('\u{ab80}', 5040), - ('\u{ab81}', 5041), ('\u{ab82}', 5042), ('\u{ab83}', 5043), ('\u{ab84}', 5044), - ('\u{ab85}', 5045), ('\u{ab86}', 5046), ('\u{ab87}', 5047), ('\u{ab88}', 5048), - ('\u{ab89}', 5049), ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), ('\u{ab8c}', 5052), - ('\u{ab8d}', 5053), ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), ('\u{ab90}', 5056), - ('\u{ab91}', 5057), ('\u{ab92}', 5058), ('\u{ab93}', 5059), ('\u{ab94}', 5060), - ('\u{ab95}', 5061), ('\u{ab96}', 5062), ('\u{ab97}', 5063), ('\u{ab98}', 5064), - ('\u{ab99}', 5065), ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), ('\u{ab9c}', 5068), - ('\u{ab9d}', 5069), ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), ('\u{aba0}', 5072), - ('\u{aba1}', 5073), ('\u{aba2}', 5074), ('\u{aba3}', 5075), ('\u{aba4}', 5076), - ('\u{aba5}', 5077), ('\u{aba6}', 5078), ('\u{aba7}', 5079), ('\u{aba8}', 5080), - ('\u{aba9}', 5081), ('\u{abaa}', 5082), ('\u{abab}', 5083), ('\u{abac}', 5084), - ('\u{abad}', 5085), ('\u{abae}', 5086), ('\u{abaf}', 5087), ('\u{abb0}', 5088), - ('\u{abb1}', 5089), ('\u{abb2}', 5090), ('\u{abb3}', 5091), ('\u{abb4}', 5092), - ('\u{abb5}', 5093), ('\u{abb6}', 5094), ('\u{abb7}', 5095), ('\u{abb8}', 5096), - ('\u{abb9}', 5097), ('\u{abba}', 5098), ('\u{abbb}', 5099), ('\u{abbc}', 5100), - ('\u{abbd}', 5101), ('\u{abbe}', 5102), ('\u{abbf}', 5103), ('\u{fb00}', 4194394), - ('\u{fb01}', 4194395), ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), ('\u{fb04}', 4194398), - ('\u{fb05}', 4194399), ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), ('\u{fb14}', 4194402), - ('\u{fb15}', 4194403), ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), ('\u{ff41}', 65313), - ('\u{ff42}', 65314), ('\u{ff43}', 65315), ('\u{ff44}', 65316), ('\u{ff45}', 65317), - ('\u{ff46}', 65318), ('\u{ff47}', 65319), ('\u{ff48}', 65320), ('\u{ff49}', 65321), - ('\u{ff4a}', 65322), ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), ('\u{ff4d}', 65325), - ('\u{ff4e}', 65326), ('\u{ff4f}', 65327), ('\u{ff50}', 65328), ('\u{ff51}', 65329), - ('\u{ff52}', 65330), ('\u{ff53}', 65331), ('\u{ff54}', 65332), ('\u{ff55}', 65333), - ('\u{ff56}', 65334), ('\u{ff57}', 65335), ('\u{ff58}', 65336), ('\u{ff59}', 65337), - ('\u{ff5a}', 65338), ('\u{10428}', 66560), ('\u{10429}', 66561), ('\u{1042a}', 66562), - ('\u{1042b}', 66563), ('\u{1042c}', 66564), ('\u{1042d}', 66565), ('\u{1042e}', 66566), - ('\u{1042f}', 66567), ('\u{10430}', 66568), ('\u{10431}', 66569), ('\u{10432}', 66570), - ('\u{10433}', 66571), ('\u{10434}', 66572), ('\u{10435}', 66573), ('\u{10436}', 66574), - ('\u{10437}', 66575), ('\u{10438}', 66576), ('\u{10439}', 66577), ('\u{1043a}', 66578), - ('\u{1043b}', 66579), ('\u{1043c}', 66580), ('\u{1043d}', 66581), ('\u{1043e}', 66582), - ('\u{1043f}', 66583), ('\u{10440}', 66584), ('\u{10441}', 66585), ('\u{10442}', 66586), - ('\u{10443}', 66587), ('\u{10444}', 66588), ('\u{10445}', 66589), ('\u{10446}', 66590), - ('\u{10447}', 66591), ('\u{10448}', 66592), ('\u{10449}', 66593), ('\u{1044a}', 66594), - ('\u{1044b}', 66595), ('\u{1044c}', 66596), ('\u{1044d}', 66597), ('\u{1044e}', 66598), - ('\u{1044f}', 66599), ('\u{104d8}', 66736), ('\u{104d9}', 66737), ('\u{104da}', 66738), - ('\u{104db}', 66739), ('\u{104dc}', 66740), ('\u{104dd}', 66741), ('\u{104de}', 66742), - ('\u{104df}', 66743), ('\u{104e0}', 66744), ('\u{104e1}', 66745), ('\u{104e2}', 66746), - ('\u{104e3}', 66747), ('\u{104e4}', 66748), ('\u{104e5}', 66749), ('\u{104e6}', 66750), - ('\u{104e7}', 66751), ('\u{104e8}', 66752), ('\u{104e9}', 66753), ('\u{104ea}', 66754), - ('\u{104eb}', 66755), ('\u{104ec}', 66756), ('\u{104ed}', 66757), ('\u{104ee}', 66758), - ('\u{104ef}', 66759), ('\u{104f0}', 66760), ('\u{104f1}', 66761), ('\u{104f2}', 66762), - ('\u{104f3}', 66763), ('\u{104f4}', 66764), ('\u{104f5}', 66765), ('\u{104f6}', 66766), - ('\u{104f7}', 66767), ('\u{104f8}', 66768), ('\u{104f9}', 66769), ('\u{104fa}', 66770), - ('\u{104fb}', 66771), ('\u{10597}', 66928), ('\u{10598}', 66929), ('\u{10599}', 66930), - ('\u{1059a}', 66931), ('\u{1059b}', 66932), ('\u{1059c}', 66933), ('\u{1059d}', 66934), - ('\u{1059e}', 66935), ('\u{1059f}', 66936), ('\u{105a0}', 66937), ('\u{105a1}', 66938), - ('\u{105a3}', 66940), ('\u{105a4}', 66941), ('\u{105a5}', 66942), ('\u{105a6}', 66943), - ('\u{105a7}', 66944), ('\u{105a8}', 66945), ('\u{105a9}', 66946), ('\u{105aa}', 66947), - ('\u{105ab}', 66948), ('\u{105ac}', 66949), ('\u{105ad}', 66950), ('\u{105ae}', 66951), - ('\u{105af}', 66952), ('\u{105b0}', 66953), ('\u{105b1}', 66954), ('\u{105b3}', 66956), - ('\u{105b4}', 66957), ('\u{105b5}', 66958), ('\u{105b6}', 66959), ('\u{105b7}', 66960), - ('\u{105b8}', 66961), ('\u{105b9}', 66962), ('\u{105bb}', 66964), ('\u{105bc}', 66965), - ('\u{10cc0}', 68736), ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), ('\u{10cc3}', 68739), - ('\u{10cc4}', 68740), ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), ('\u{10cc7}', 68743), - ('\u{10cc8}', 68744), ('\u{10cc9}', 68745), ('\u{10cca}', 68746), ('\u{10ccb}', 68747), - ('\u{10ccc}', 68748), ('\u{10ccd}', 68749), ('\u{10cce}', 68750), ('\u{10ccf}', 68751), - ('\u{10cd0}', 68752), ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), ('\u{10cd3}', 68755), - ('\u{10cd4}', 68756), ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), ('\u{10cd7}', 68759), - ('\u{10cd8}', 68760), ('\u{10cd9}', 68761), ('\u{10cda}', 68762), ('\u{10cdb}', 68763), - ('\u{10cdc}', 68764), ('\u{10cdd}', 68765), ('\u{10cde}', 68766), ('\u{10cdf}', 68767), - ('\u{10ce0}', 68768), ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), ('\u{10ce3}', 68771), - ('\u{10ce4}', 68772), ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), ('\u{10ce7}', 68775), - ('\u{10ce8}', 68776), ('\u{10ce9}', 68777), ('\u{10cea}', 68778), ('\u{10ceb}', 68779), - ('\u{10cec}', 68780), ('\u{10ced}', 68781), ('\u{10cee}', 68782), ('\u{10cef}', 68783), - ('\u{10cf0}', 68784), ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), ('\u{10d70}', 68944), - ('\u{10d71}', 68945), ('\u{10d72}', 68946), ('\u{10d73}', 68947), ('\u{10d74}', 68948), - ('\u{10d75}', 68949), ('\u{10d76}', 68950), ('\u{10d77}', 68951), ('\u{10d78}', 68952), - ('\u{10d79}', 68953), ('\u{10d7a}', 68954), ('\u{10d7b}', 68955), ('\u{10d7c}', 68956), - ('\u{10d7d}', 68957), ('\u{10d7e}', 68958), ('\u{10d7f}', 68959), ('\u{10d80}', 68960), - ('\u{10d81}', 68961), ('\u{10d82}', 68962), ('\u{10d83}', 68963), ('\u{10d84}', 68964), - ('\u{10d85}', 68965), ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), - ('\u{118c3}', 71843), ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), - ('\u{118c7}', 71847), ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), - ('\u{118cb}', 71851), ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), - ('\u{118cf}', 71855), ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), - ('\u{118d3}', 71859), ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), - ('\u{118d7}', 71863), ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), - ('\u{118db}', 71867), ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), - ('\u{118df}', 71871), ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), - ('\u{16e63}', 93763), ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), - ('\u{16e67}', 93767), ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), - ('\u{16e6b}', 93771), ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), - ('\u{16e6f}', 93775), ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), - ('\u{16e73}', 93779), ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), - ('\u{16e77}', 93783), ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), - ('\u{16e7b}', 93787), ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), - ('\u{16e7f}', 93791), ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), + ('\u{a7cd}', 42956), ('\u{a7cf}', 42958), ('\u{a7d1}', 42960), ('\u{a7d3}', 42962), + ('\u{a7d5}', 42964), ('\u{a7d7}', 42966), ('\u{a7d9}', 42968), ('\u{a7db}', 42970), + ('\u{a7f6}', 42997), ('\u{ab53}', 42931), ('\u{ab70}', 5024), ('\u{ab71}', 5025), + ('\u{ab72}', 5026), ('\u{ab73}', 5027), ('\u{ab74}', 5028), ('\u{ab75}', 5029), + ('\u{ab76}', 5030), ('\u{ab77}', 5031), ('\u{ab78}', 5032), ('\u{ab79}', 5033), + ('\u{ab7a}', 5034), ('\u{ab7b}', 5035), ('\u{ab7c}', 5036), ('\u{ab7d}', 5037), + ('\u{ab7e}', 5038), ('\u{ab7f}', 5039), ('\u{ab80}', 5040), ('\u{ab81}', 5041), + ('\u{ab82}', 5042), ('\u{ab83}', 5043), ('\u{ab84}', 5044), ('\u{ab85}', 5045), + ('\u{ab86}', 5046), ('\u{ab87}', 5047), ('\u{ab88}', 5048), ('\u{ab89}', 5049), + ('\u{ab8a}', 5050), ('\u{ab8b}', 5051), ('\u{ab8c}', 5052), ('\u{ab8d}', 5053), + ('\u{ab8e}', 5054), ('\u{ab8f}', 5055), ('\u{ab90}', 5056), ('\u{ab91}', 5057), + ('\u{ab92}', 5058), ('\u{ab93}', 5059), ('\u{ab94}', 5060), ('\u{ab95}', 5061), + ('\u{ab96}', 5062), ('\u{ab97}', 5063), ('\u{ab98}', 5064), ('\u{ab99}', 5065), + ('\u{ab9a}', 5066), ('\u{ab9b}', 5067), ('\u{ab9c}', 5068), ('\u{ab9d}', 5069), + ('\u{ab9e}', 5070), ('\u{ab9f}', 5071), ('\u{aba0}', 5072), ('\u{aba1}', 5073), + ('\u{aba2}', 5074), ('\u{aba3}', 5075), ('\u{aba4}', 5076), ('\u{aba5}', 5077), + ('\u{aba6}', 5078), ('\u{aba7}', 5079), ('\u{aba8}', 5080), ('\u{aba9}', 5081), + ('\u{abaa}', 5082), ('\u{abab}', 5083), ('\u{abac}', 5084), ('\u{abad}', 5085), + ('\u{abae}', 5086), ('\u{abaf}', 5087), ('\u{abb0}', 5088), ('\u{abb1}', 5089), + ('\u{abb2}', 5090), ('\u{abb3}', 5091), ('\u{abb4}', 5092), ('\u{abb5}', 5093), + ('\u{abb6}', 5094), ('\u{abb7}', 5095), ('\u{abb8}', 5096), ('\u{abb9}', 5097), + ('\u{abba}', 5098), ('\u{abbb}', 5099), ('\u{abbc}', 5100), ('\u{abbd}', 5101), + ('\u{abbe}', 5102), ('\u{abbf}', 5103), ('\u{fb00}', 4194394), ('\u{fb01}', 4194395), + ('\u{fb02}', 4194396), ('\u{fb03}', 4194397), ('\u{fb04}', 4194398), ('\u{fb05}', 4194399), + ('\u{fb06}', 4194400), ('\u{fb13}', 4194401), ('\u{fb14}', 4194402), ('\u{fb15}', 4194403), + ('\u{fb16}', 4194404), ('\u{fb17}', 4194405), ('\u{ff41}', 65313), ('\u{ff42}', 65314), + ('\u{ff43}', 65315), ('\u{ff44}', 65316), ('\u{ff45}', 65317), ('\u{ff46}', 65318), + ('\u{ff47}', 65319), ('\u{ff48}', 65320), ('\u{ff49}', 65321), ('\u{ff4a}', 65322), + ('\u{ff4b}', 65323), ('\u{ff4c}', 65324), ('\u{ff4d}', 65325), ('\u{ff4e}', 65326), + ('\u{ff4f}', 65327), ('\u{ff50}', 65328), ('\u{ff51}', 65329), ('\u{ff52}', 65330), + ('\u{ff53}', 65331), ('\u{ff54}', 65332), ('\u{ff55}', 65333), ('\u{ff56}', 65334), + ('\u{ff57}', 65335), ('\u{ff58}', 65336), ('\u{ff59}', 65337), ('\u{ff5a}', 65338), + ('\u{10428}', 66560), ('\u{10429}', 66561), ('\u{1042a}', 66562), ('\u{1042b}', 66563), + ('\u{1042c}', 66564), ('\u{1042d}', 66565), ('\u{1042e}', 66566), ('\u{1042f}', 66567), + ('\u{10430}', 66568), ('\u{10431}', 66569), ('\u{10432}', 66570), ('\u{10433}', 66571), + ('\u{10434}', 66572), ('\u{10435}', 66573), ('\u{10436}', 66574), ('\u{10437}', 66575), + ('\u{10438}', 66576), ('\u{10439}', 66577), ('\u{1043a}', 66578), ('\u{1043b}', 66579), + ('\u{1043c}', 66580), ('\u{1043d}', 66581), ('\u{1043e}', 66582), ('\u{1043f}', 66583), + ('\u{10440}', 66584), ('\u{10441}', 66585), ('\u{10442}', 66586), ('\u{10443}', 66587), + ('\u{10444}', 66588), ('\u{10445}', 66589), ('\u{10446}', 66590), ('\u{10447}', 66591), + ('\u{10448}', 66592), ('\u{10449}', 66593), ('\u{1044a}', 66594), ('\u{1044b}', 66595), + ('\u{1044c}', 66596), ('\u{1044d}', 66597), ('\u{1044e}', 66598), ('\u{1044f}', 66599), + ('\u{104d8}', 66736), ('\u{104d9}', 66737), ('\u{104da}', 66738), ('\u{104db}', 66739), + ('\u{104dc}', 66740), ('\u{104dd}', 66741), ('\u{104de}', 66742), ('\u{104df}', 66743), + ('\u{104e0}', 66744), ('\u{104e1}', 66745), ('\u{104e2}', 66746), ('\u{104e3}', 66747), + ('\u{104e4}', 66748), ('\u{104e5}', 66749), ('\u{104e6}', 66750), ('\u{104e7}', 66751), + ('\u{104e8}', 66752), ('\u{104e9}', 66753), ('\u{104ea}', 66754), ('\u{104eb}', 66755), + ('\u{104ec}', 66756), ('\u{104ed}', 66757), ('\u{104ee}', 66758), ('\u{104ef}', 66759), + ('\u{104f0}', 66760), ('\u{104f1}', 66761), ('\u{104f2}', 66762), ('\u{104f3}', 66763), + ('\u{104f4}', 66764), ('\u{104f5}', 66765), ('\u{104f6}', 66766), ('\u{104f7}', 66767), + ('\u{104f8}', 66768), ('\u{104f9}', 66769), ('\u{104fa}', 66770), ('\u{104fb}', 66771), + ('\u{10597}', 66928), ('\u{10598}', 66929), ('\u{10599}', 66930), ('\u{1059a}', 66931), + ('\u{1059b}', 66932), ('\u{1059c}', 66933), ('\u{1059d}', 66934), ('\u{1059e}', 66935), + ('\u{1059f}', 66936), ('\u{105a0}', 66937), ('\u{105a1}', 66938), ('\u{105a3}', 66940), + ('\u{105a4}', 66941), ('\u{105a5}', 66942), ('\u{105a6}', 66943), ('\u{105a7}', 66944), + ('\u{105a8}', 66945), ('\u{105a9}', 66946), ('\u{105aa}', 66947), ('\u{105ab}', 66948), + ('\u{105ac}', 66949), ('\u{105ad}', 66950), ('\u{105ae}', 66951), ('\u{105af}', 66952), + ('\u{105b0}', 66953), ('\u{105b1}', 66954), ('\u{105b3}', 66956), ('\u{105b4}', 66957), + ('\u{105b5}', 66958), ('\u{105b6}', 66959), ('\u{105b7}', 66960), ('\u{105b8}', 66961), + ('\u{105b9}', 66962), ('\u{105bb}', 66964), ('\u{105bc}', 66965), ('\u{10cc0}', 68736), + ('\u{10cc1}', 68737), ('\u{10cc2}', 68738), ('\u{10cc3}', 68739), ('\u{10cc4}', 68740), + ('\u{10cc5}', 68741), ('\u{10cc6}', 68742), ('\u{10cc7}', 68743), ('\u{10cc8}', 68744), + ('\u{10cc9}', 68745), ('\u{10cca}', 68746), ('\u{10ccb}', 68747), ('\u{10ccc}', 68748), + ('\u{10ccd}', 68749), ('\u{10cce}', 68750), ('\u{10ccf}', 68751), ('\u{10cd0}', 68752), + ('\u{10cd1}', 68753), ('\u{10cd2}', 68754), ('\u{10cd3}', 68755), ('\u{10cd4}', 68756), + ('\u{10cd5}', 68757), ('\u{10cd6}', 68758), ('\u{10cd7}', 68759), ('\u{10cd8}', 68760), + ('\u{10cd9}', 68761), ('\u{10cda}', 68762), ('\u{10cdb}', 68763), ('\u{10cdc}', 68764), + ('\u{10cdd}', 68765), ('\u{10cde}', 68766), ('\u{10cdf}', 68767), ('\u{10ce0}', 68768), + ('\u{10ce1}', 68769), ('\u{10ce2}', 68770), ('\u{10ce3}', 68771), ('\u{10ce4}', 68772), + ('\u{10ce5}', 68773), ('\u{10ce6}', 68774), ('\u{10ce7}', 68775), ('\u{10ce8}', 68776), + ('\u{10ce9}', 68777), ('\u{10cea}', 68778), ('\u{10ceb}', 68779), ('\u{10cec}', 68780), + ('\u{10ced}', 68781), ('\u{10cee}', 68782), ('\u{10cef}', 68783), ('\u{10cf0}', 68784), + ('\u{10cf1}', 68785), ('\u{10cf2}', 68786), ('\u{10d70}', 68944), ('\u{10d71}', 68945), + ('\u{10d72}', 68946), ('\u{10d73}', 68947), ('\u{10d74}', 68948), ('\u{10d75}', 68949), + ('\u{10d76}', 68950), ('\u{10d77}', 68951), ('\u{10d78}', 68952), ('\u{10d79}', 68953), + ('\u{10d7a}', 68954), ('\u{10d7b}', 68955), ('\u{10d7c}', 68956), ('\u{10d7d}', 68957), + ('\u{10d7e}', 68958), ('\u{10d7f}', 68959), ('\u{10d80}', 68960), ('\u{10d81}', 68961), + ('\u{10d82}', 68962), ('\u{10d83}', 68963), ('\u{10d84}', 68964), ('\u{10d85}', 68965), + ('\u{118c0}', 71840), ('\u{118c1}', 71841), ('\u{118c2}', 71842), ('\u{118c3}', 71843), + ('\u{118c4}', 71844), ('\u{118c5}', 71845), ('\u{118c6}', 71846), ('\u{118c7}', 71847), + ('\u{118c8}', 71848), ('\u{118c9}', 71849), ('\u{118ca}', 71850), ('\u{118cb}', 71851), + ('\u{118cc}', 71852), ('\u{118cd}', 71853), ('\u{118ce}', 71854), ('\u{118cf}', 71855), + ('\u{118d0}', 71856), ('\u{118d1}', 71857), ('\u{118d2}', 71858), ('\u{118d3}', 71859), + ('\u{118d4}', 71860), ('\u{118d5}', 71861), ('\u{118d6}', 71862), ('\u{118d7}', 71863), + ('\u{118d8}', 71864), ('\u{118d9}', 71865), ('\u{118da}', 71866), ('\u{118db}', 71867), + ('\u{118dc}', 71868), ('\u{118dd}', 71869), ('\u{118de}', 71870), ('\u{118df}', 71871), + ('\u{16e60}', 93760), ('\u{16e61}', 93761), ('\u{16e62}', 93762), ('\u{16e63}', 93763), + ('\u{16e64}', 93764), ('\u{16e65}', 93765), ('\u{16e66}', 93766), ('\u{16e67}', 93767), + ('\u{16e68}', 93768), ('\u{16e69}', 93769), ('\u{16e6a}', 93770), ('\u{16e6b}', 93771), + ('\u{16e6c}', 93772), ('\u{16e6d}', 93773), ('\u{16e6e}', 93774), ('\u{16e6f}', 93775), + ('\u{16e70}', 93776), ('\u{16e71}', 93777), ('\u{16e72}', 93778), ('\u{16e73}', 93779), + ('\u{16e74}', 93780), ('\u{16e75}', 93781), ('\u{16e76}', 93782), ('\u{16e77}', 93783), + ('\u{16e78}', 93784), ('\u{16e79}', 93785), ('\u{16e7a}', 93786), ('\u{16e7b}', 93787), + ('\u{16e7c}', 93788), ('\u{16e7d}', 93789), ('\u{16e7e}', 93790), ('\u{16e7f}', 93791), + ('\u{16ebb}', 93856), ('\u{16ebc}', 93857), ('\u{16ebd}', 93858), ('\u{16ebe}', 93859), + ('\u{16ebf}', 93860), ('\u{16ec0}', 93861), ('\u{16ec1}', 93862), ('\u{16ec2}', 93863), + ('\u{16ec3}', 93864), ('\u{16ec4}', 93865), ('\u{16ec5}', 93866), ('\u{16ec6}', 93867), + ('\u{16ec7}', 93868), ('\u{16ec8}', 93869), ('\u{16ec9}', 93870), ('\u{16eca}', 93871), + ('\u{16ecb}', 93872), ('\u{16ecc}', 93873), ('\u{16ecd}', 93874), ('\u{16ece}', 93875), + ('\u{16ecf}', 93876), ('\u{16ed0}', 93877), ('\u{16ed1}', 93878), ('\u{16ed2}', 93879), + ('\u{16ed3}', 93880), ('\u{1e922}', 125184), ('\u{1e923}', 125185), ('\u{1e924}', 125186), ('\u{1e925}', 125187), ('\u{1e926}', 125188), ('\u{1e927}', 125189), ('\u{1e928}', 125190), ('\u{1e929}', 125191), ('\u{1e92a}', 125192), ('\u{1e92b}', 125193), ('\u{1e92c}', 125194), ('\u{1e92d}', 125195), ('\u{1e92e}', 125196), ('\u{1e92f}', 125197), ('\u{1e930}', 125198), From 83a99aadcff60482552fc81e0dc2992403c5652e Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Tue, 9 Sep 2025 15:01:47 +0200 Subject: [PATCH 019/537] Bump unicode printable to version 17.0.0 --- library/core/src/unicode/printable.rs | 160 +++++++++++++------------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/library/core/src/unicode/printable.rs b/library/core/src/unicode/printable.rs index d8fb50e4ed29..68e1c8ae31c0 100644 --- a/library/core/src/unicode/printable.rs +++ b/library/core/src/unicode/printable.rs @@ -54,13 +54,10 @@ pub(crate) fn is_printable(x: char) -> bool { if 0x2a6e0 <= x && x < 0x2a700 { return false; } - if 0x2b73a <= x && x < 0x2b740 { - return false; - } if 0x2b81e <= x && x < 0x2b820 { return false; } - if 0x2cea2 <= x && x < 0x2ceb0 { + if 0x2ceae <= x && x < 0x2ceb0 { return false; } if 0x2ebe1 <= x && x < 0x2ebf0 { @@ -75,7 +72,7 @@ pub(crate) fn is_printable(x: char) -> bool { if 0x3134b <= x && x < 0x31350 { return false; } - if 0x323b0 <= x && x < 0xe0100 { + if 0x3347a <= x && x < 0xe0100 { return false; } if 0xe01f0 <= x && x < 0x110000 { @@ -96,7 +93,7 @@ const SINGLETONS0U: &[(u8, u8)] = &[ (0x09, 17), (0x0a, 28), (0x0b, 25), - (0x0c, 26), + (0x0c, 25), (0x0d, 16), (0x0e, 12), (0x0f, 4), @@ -107,24 +104,22 @@ const SINGLETONS0U: &[(u8, u8)] = &[ (0x17, 4), (0x18, 1), (0x19, 3), - (0x1a, 7), + (0x1a, 9), (0x1b, 1), (0x1c, 2), (0x1f, 22), (0x20, 3), - (0x2b, 3), + (0x2b, 2), (0x2d, 11), (0x2e, 1), (0x30, 4), (0x31, 2), (0x32, 1), - (0xa7, 4), (0xa9, 2), (0xaa, 4), (0xab, 8), (0xfa, 2), (0xfb, 5), - (0xfd, 2), (0xfe, 3), (0xff, 9), ]; @@ -143,30 +138,29 @@ const SINGLETONS0L: &[u8] = &[ 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x3a, 0x3b, 0x45, 0x49, - 0x57, 0x5b, 0x5c, 0x5e, 0x5f, 0x64, 0x65, 0x8d, - 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, - 0xe4, 0xe5, 0xf0, 0x0d, 0x11, 0x45, 0x49, 0x64, - 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, - 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, - 0xbe, 0xbf, 0xc5, 0xc7, 0xcf, 0xda, 0xdb, 0x48, - 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, - 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, - 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, - 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, - 0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x1f, - 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, - 0xaf, 0x4d, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f, - 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, - 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, + 0x57, 0x5b, 0x5e, 0x5f, 0x64, 0x65, 0x8d, 0x91, + 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, + 0xe5, 0xf0, 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, + 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, + 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, + 0xbf, 0xc5, 0xc7, 0xcf, 0xda, 0xdb, 0x48, 0x98, + 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, 0x4f, + 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, + 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, + 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, + 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, + 0xde, 0xdf, 0x4d, 0xbb, 0xbc, 0x16, 0x17, 0x1e, + 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, + 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, + 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x00, 0x40, 0x97, 0x98, - 0x30, 0x8f, 0x1f, 0xce, 0xcf, 0xd2, 0xd4, 0xce, - 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, - 0x10, 0x27, 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, - 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, 0x53, 0x67, - 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, - 0xfe, 0xff, + 0x30, 0x8f, 0x1f, 0xce, 0xff, 0x4e, 0x4f, 0x5a, + 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, + 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, + 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, + 0xd9, 0xe7, 0xfe, 0xff, ]; #[rustfmt::skip] const SINGLETONS1U: &[(u8, u8)] = &[ @@ -195,6 +189,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[ (0x24, 1), (0x6a, 4), (0x6b, 2), + (0x6e, 2), (0xaf, 3), (0xb1, 2), (0xbc, 2), @@ -207,12 +202,13 @@ const SINGLETONS1U: &[(u8, u8)] = &[ (0xda, 1), (0xe0, 5), (0xe1, 2), + (0xe6, 1), (0xe7, 4), (0xe8, 2), (0xee, 32), (0xf0, 4), (0xf8, 2), - (0xfa, 4), + (0xfa, 5), (0xfb, 1), ]; #[rustfmt::skip] @@ -231,18 +227,19 @@ const SINGLETONS1L: &[u8] = &[ 0x39, 0x3a, 0xa8, 0xa9, 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92, 0x11, 0x6f, 0x5f, 0xbf, 0xee, - 0xef, 0x5a, 0x62, 0xf4, 0xfc, 0xff, 0x53, 0x54, - 0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28, 0x55, 0x9d, - 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, - 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, - 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, - 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xe7, - 0xec, 0xef, 0xff, 0xc5, 0xc6, 0x04, 0x20, 0x23, - 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, - 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, - 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, 0x78, - 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, - 0xd0, 0xae, 0xaf, 0x6e, 0x6f, 0xdd, 0xde, 0x93, + 0xef, 0x5a, 0x62, 0xb9, 0xba, 0xf4, 0xfc, 0xff, + 0x53, 0x54, 0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, + 0x3f, 0xdf, 0xe7, 0xec, 0xef, 0xff, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, + 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, + 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, + 0xaf, 0xb0, 0xc0, 0xd0, 0xae, 0xaf, 0x6e, 0x6f, + 0xc7, 0xdd, 0xde, 0x93, ]; #[rustfmt::skip] const NORMAL0: &[u8] = &[ @@ -254,7 +251,7 @@ const NORMAL0: &[u8] = &[ 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x05, - 0x1f, 0x08, + 0x20, 0x07, 0x81, 0x1c, 0x03, 0x19, 0x08, 0x01, 0x04, @@ -282,8 +279,8 @@ const NORMAL0: &[u8] = &[ 0x4e, 0x07, 0x1b, 0x07, 0x57, 0x07, - 0x02, 0x06, - 0x17, 0x0c, + 0x02, 0x05, + 0x18, 0x0c, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, @@ -319,7 +316,7 @@ const NORMAL0: &[u8] = &[ 0x0b, 0x03, 0x80, 0xac, 0x06, 0x0a, 0x06, - 0x2f, 0x31, + 0x4c, 0x14, 0x80, 0xf4, 0x08, 0x3c, 0x03, 0x0f, 0x03, @@ -330,7 +327,7 @@ const NORMAL0: &[u8] = &[ 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, - 0x21, 0x0f, + 0x22, 0x0e, 0x21, 0x0f, 0x80, 0x8c, 0x04, 0x82, 0x9a, 0x16, @@ -349,8 +346,8 @@ const NORMAL0: &[u8] = &[ 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, - 0x80, 0xdd, 0x15, - 0x3b, 0x03, + 0x80, 0xdd, 0x14, + 0x3c, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, @@ -370,9 +367,7 @@ const NORMAL0: &[u8] = &[ 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, - 0x80, 0xa6, 0x10, - 0x81, 0xf5, 0x07, - 0x01, 0x20, + 0x82, 0xb3, 0x20, 0x2a, 0x06, 0x4c, 0x04, 0x80, 0x8d, 0x04, @@ -414,7 +409,7 @@ const NORMAL1: &[u8] = &[ 0x16, 0x05, 0x21, 0x03, 0x1b, 0x05, - 0x01, 0x40, + 0x1b, 0x26, 0x38, 0x04, 0x4b, 0x05, 0x2f, 0x04, @@ -437,8 +432,9 @@ const NORMAL1: &[u8] = &[ 0x1d, 0x08, 0x02, 0x80, 0xd0, 0x52, 0x10, - 0x03, 0x37, - 0x2c, 0x08, + 0x06, 0x08, + 0x09, 0x21, + 0x2e, 0x08, 0x2a, 0x16, 0x1a, 0x26, 0x1c, 0x14, @@ -481,7 +477,8 @@ const NORMAL1: &[u8] = &[ 0x48, 0x08, 0x53, 0x0d, 0x49, 0x07, - 0x0a, 0x80, 0xb6, + 0x0a, 0x56, + 0x08, 0x58, 0x22, 0x0e, 0x0a, 0x06, 0x46, 0x0a, @@ -491,7 +488,9 @@ const NORMAL1: &[u8] = &[ 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, - 0x0a, 0x81, 0x36, + 0x0a, 0x06, + 0x2c, 0x04, + 0x0a, 0x80, 0xf6, 0x19, 0x07, 0x3b, 0x03, 0x1d, 0x55, @@ -514,15 +513,16 @@ const NORMAL1: &[u8] = &[ 0x28, 0x05, 0x13, 0x81, 0xb0, 0x3a, 0x80, 0xc6, - 0x5b, 0x65, + 0x5b, 0x05, + 0x34, 0x2c, 0x4b, 0x04, 0x39, 0x07, 0x11, 0x40, 0x05, 0x0b, - 0x02, 0x0e, - 0x97, 0xf8, 0x08, - 0x84, 0xd6, 0x29, - 0x0a, 0xa2, 0xe7, + 0x07, 0x09, + 0x9c, 0xd6, 0x29, + 0x20, 0x61, + 0x73, 0xa1, 0xfd, 0x81, 0x33, 0x0f, 0x01, 0x1d, 0x06, 0x0e, @@ -532,8 +532,10 @@ const NORMAL1: &[u8] = &[ 0x0d, 0x03, 0x09, 0x07, 0x10, 0x8f, 0x60, - 0x80, 0xfa, 0x06, - 0x81, 0xb4, 0x4c, + 0x80, 0xfd, 0x03, + 0x81, 0xb4, 0x06, + 0x17, 0x0f, + 0x11, 0x0f, 0x47, 0x09, 0x74, 0x3c, 0x80, 0xf6, 0x0a, @@ -560,7 +562,9 @@ const NORMAL1: &[u8] = &[ 0x01, 0x81, 0xd0, 0x2a, 0x80, 0xd6, 0x2b, 0x04, - 0x01, 0x81, 0xe0, + 0x01, 0x80, 0xc0, + 0x36, 0x08, + 0x02, 0x80, 0xe0, 0x80, 0xf7, 0x29, 0x4c, 0x04, 0x0a, 0x04, @@ -581,11 +585,10 @@ const NORMAL1: &[u8] = &[ 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, 0x9a, - 0x83, 0xd8, 0x04, + 0x83, 0xd9, 0x03, 0x11, 0x03, 0x0d, 0x03, - 0x77, 0x04, - 0x5f, 0x06, + 0x80, 0xda, 0x06, 0x0c, 0x04, 0x01, 0x0f, 0x0c, 0x04, @@ -593,12 +596,13 @@ const NORMAL1: &[u8] = &[ 0x0a, 0x06, 0x28, 0x08, 0x2c, 0x04, - 0x02, 0x3e, - 0x81, 0x54, 0x0c, + 0x02, 0x0e, + 0x09, 0x27, + 0x81, 0x58, 0x08, 0x1d, 0x03, - 0x0a, 0x05, - 0x38, 0x07, - 0x1c, 0x06, - 0x09, 0x07, - 0x80, 0xfa, 0x84, 0x06, + 0x0b, 0x03, + 0x3b, 0x04, + 0x1e, 0x04, + 0x0a, 0x07, + 0x80, 0xfb, 0x84, 0x05, ]; From ec5375fc55802290738b710ae285e78244e141f5 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Thu, 11 Sep 2025 21:51:13 +0100 Subject: [PATCH 020/537] Add general arm-linux.md platform doc. Covers all Arm Linux systems, and means that we can reduce the amount of information required in the target specific pages to just the Tier level, the maintainer, and any specific details for that target. --- src/doc/rustc/src/SUMMARY.md | 9 +- .../rustc/src/platform-support/arm-linux.md | 217 ++++++++++++++++++ .../armeb-unknown-linux-gnueabi.md | 3 + .../armv5te-unknown-linux-gnueabi.md | 3 + .../armv7-unknown-linux-uclibceabi.md | 3 + .../armv7-unknown-linux-uclibceabihf.md | 3 + 6 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/arm-linux.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 8e378e53e518..fc3f71b4a6a8 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -51,7 +51,6 @@ - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) @@ -62,12 +61,14 @@ - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) - - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md) + - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) + - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) + - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) - - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv7a-vex-v5](platform-support/armv7a-vex-v5.md) - [\*-android and \*-androideabi](platform-support/android.md) - [\*-linux-ohos](platform-support/openharmony.md) diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md new file mode 100644 index 000000000000..5f320762e937 --- /dev/null +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -0,0 +1,217 @@ +# Arm Linux support in Rust + +The Arm Architecture has been around since the mid-1980s, going through nine +major revisions, many minor revisions, and spanning both 32-bith and 64-bit +architectures. This page covers 32-bit Arm platforms that run some form of +Linux (but not Android). Those targets are: + +* `arm-unknown-linux-gnueabi` +* `arm-unknown-linux-gnueabihf` +* `arm-unknown-linux-musleabi` +* `arm-unknown-linux-musleabihf` +* [`armeb-unknown-linux-gnueabi`](armeb-unknown-linux-gnueabi.md) +* `armv4t-unknown-linux-gnueabi` +* [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md) +* `armv5te-unknown-linux-musleabi` +* `armv5te-unknown-linux-uclibceabi` +* `armv7-unknown-linux-gnueabi` +* `armv7-unknown-linux-gnueabihf` +* `armv7-unknown-linux-musleabi` +* `armv7-unknown-linux-musleabihf` +* `armv7-unknown-linux-ohos` +* [`armv7-unknown-linux-uclibceabi`](armv7-unknown-linux-uclibceabi.md) +* [`armv7-unknown-linux-uclibceabihf`](armv7-unknown-linux-uclibceabihf.md) +* `thumbv7neon-unknown-linux-gnueabihf` +* `thumbv7neon-unknown-linux-musleabihf` + +Some of these targets have dedicated pages and some do not. This is largely +due to historical accident, or the enthusiasm of the maintainers. This +document attempts to cover all the targets, but only in broad terms. + +To make sense of this list, the architecture and ABI component of the +`-unknown-linux-` tuple will be discussed separately. + +The second part of the tuple is `unknown` because these systems don't come +from any one specific vendor (like `powerpc-ibm-aix` or +`aarch64-apple-darwin`). The third part is `linux`, because this page only +discusses Linux targets. + +## Architecture Component + +* `arm` +* `armeb` +* `armv4t` +* `armv5te` +* `armv7` +* `thumbv7neon` + +The architecture component simply called `arm` corresponds to the Armv6 +architecture - that is, version 6 of the Arm Architecture as defined in +version 6 of the Arm Architecture Reference Manual (the Arm ARM). This was the +last 'legacy' release of the Arm architecture, before they split into +Application, Real-Time and Microcontroller profiles (leading to Armv7-A, +Armv7-R and Armv7-M). Processors that implement the Armv6 architecture include +the ARM1176JZF-S, as found in BCM2835 SoC that powers the Raspberry Pi Zero. +Arm processors are generally fairly backwards compatible, especially for +user-mode code, so code compiled for the `arm` architecture should also work +on newer ARMv7-A systems, or even 64/32-bit Armv8-A systems. + +The `armeb` architecture component specifies an Armv6 processor running in Big +Endian mode (`eb` is for big-endian - the letters are backwards because +engineers used to little-endian systems perceive big-endian numbers to be +written into memory backwards, and they thought it was funnier like that). +Most Arm processors can operate in either little-endian or big-endian mode and +little-endian mode is by far the most common. However, if for whatever reason +you wish to store your Most Significant Bytes first, these targets are +available. They just aren't terribly well tested, or compatible with most +existing pre-compiled Arm libraries. + +Targets that start with `armv4t` are for processors implementing the Armv4T +architecture from 1994. These include the ARM7TDMI, as found in the Nokia 6110 +brick-phone and the Game Boy Advance. The 'T' stands for *Thumb* and indicate +that the processors can execute smaller 16-bit versions of some of the 32-bit +Arm instructions. Because a Thumb is like a small version of an Arm. + +Targets that start with `armv5te` are for processors implementing the Armv5TE +architecture. These are mostly from the ARM9 family, like the ARM946E-S found +in the Nintendo DS. If you are programming an Arm machine from the early +2000s, this might be what you need. + +The `armv7` is arguably a misnomer, and it should be `armv7a`. This is because +it corresponds to the Application profile of Armv7 (i.e. Armv7-A), as opposed +to the Real-Time or Microcontroller profile. Processors implementing this +architecture include the Cortex-A7 and Cortex-A8. + +The `thumbv7neon` component indicates support for a processor that implements +ARMv7-A (the same as `armv7`), it generates Thumb instructions (technically +Thumb-2, also known as the T32 ISA) as opposed to Arm instructions (also known +as the A32 ISA). These instructions are smaller, giving more code per KB of +RAM, but may have a performance penalty if they take two instructions to do +something Arm instructions could do in one. It's a complex trade-off and you +should be doing benchmarks to work out which is better for you, if you +strongly care about code size and/or performance. This component also enables +support for Arm's SIMD extensions, known as Neon. These extensions will +improve performance for certain kinds of repetitive operations. + +## ABI Component + +* `gnueabi` +* `gnueabihf` +* `musleabi` +* `musleabihf` +* `ohos` +* `uclibceabi` +* `uclibceabihf` + +You will need to select the appropriate ABI to match the system you want to be +running this code on. For example, running `eabihf` code on an `eabi` system +will not work correctly. + +The `gnueabi` ABI component indicates support for using the GNU C Library +(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement of for the +original ABI (now called the Old ABI or OABI), and it is the standard ABI for +32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64` +are passed as if they were integers, instead of being passed via in FPU +registers. Generally these targets also disable the use of the FPU entirely, +although that isn't always true. + +The `gnueabihf` ABI component is like `gnueabi`, except that it support the +'hard-float' of the EABI. That is, function parameters that are `f32` or `f64` +are passed in FPU registers. Naturally, this makes the FPU mandatory. + +Most 'desktop' Linux distributions (Debian, Ubuntu, Fedora, etc) use the GNU C +Library and so you should probably select either `gnueabi` or `gnueabihf`, +depending on whether your distribution is using 'soft-float' (EABI) or +'hard-float' (EABIHF). Debian happens to offer +[both](https://wiki.debian.org/ArmEabiPort) +[kinds](https://wiki.debian.org/ArmHardFloatPort). + +The `musleabi` and `musleabihf` ABI components offer support for the [musl C +library](https://musl.libc.org/). This C library can be used to create 'static +binaries' that have no run-time library requirements (a feature that that +glibc does not support). There are soft-float (`eabi`) and hard-float +(`eabihf`) variants, as per the `gnu*` targets above. + +The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C +library](https://uclibc-ng.org/). This is sometimes used in light-weight +embedded Linux distributions, like those created with +[buildroot](https://www.buildroot.org/). + +## Cross Compilation + +Unfortunately, 32-bit Arm machines are generally not the fastest around, and +they don't have much RAM. This means you are likely to be cross-compiling. + +To do this, you need to give Rust a suitable linker to use - one that knows +the Arm architecture, and more importantly, knows where to find a suitable C +Library to link against. + +To do that, you can add the `linker` property to your `.cargo/config.toml`. +Typically you would refer to a suitable copy of GCC that has built as a +cross-compiler, alongside a C library. + +```toml +[target.arm-unknown-linux-gnueabi] +linker = "arm-linux-gnueabi-gcc" +``` + +On Debian Linux, you could install such a cross-compilation toolchain with +`apt install gcc-arm-linux-gnueabi`. For more exotic combinations, you might +need to build a bespoke version of GCC using [crosstool-ng]. + +[crosstool-ng]: https://github.com/crosstool-ng/crosstool-ng + +Note that for GCC, all 32-bit Arm architectures are handled in the same build +- there are no separate Armv4T or Armv6 builds of GCC. The architecture is +selected with flags, like `-march=armv6`, but they aren't required for the +linker. + +Let's assume we are on some Debian machine, and we want to build a basic Arm +Linux binary for a distribution using the GNU C Library, targeting Armv6 with +a hard-float ABI. Such a binary should work on a Raspberry Pi, for example. +The commands are: + +```bash +sudo apt install -y gcc-arm-linux-gnueabihf +rustup target add arm-unknown-linux-gnueabihf +cargo new --bin armdemo +cd armdemo +mkdir .cargo +cat > .cargo/config.toml << EOF +[target.arm-unknown-linux-gnueabihf] +linker = "arm-linux-gnueabihf-gcc" +EOF +cargo build --target=arm-unknown-linux-gnueabihf +``` + +This will give us our ARM Linux binary for the GNU C Library with a soft-float ABI: + +```console +$ file ./target/arm-unknown-linux-gnueabi/debug/armdemo +./target/arm-unknown-linux-gnueabi/debug/armdemo: ELF 32-bit LSB pie + executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter + /lib/ld-linux.so.3, BuildID[sha1]=dd0b9aa5ae876330fd4e2fcf393850f083ec7fcd, + for GNU/Linux 3.2.0, with debug_info, not stripped +``` + +If you are building C code as part of your Rust project, you may want to +direct `cc-rs` to use an appropriate cross-compiler with the `CROSS_COMPILE` +environment variable. You may also want to set the CFLAGS environment variable +for the target. For example: + +```bash +export CROSS_COMPILE=arm-linux-gnueabi +export CFLAGS_arm_unknown_linux_gnueabi="-march=armv6" +``` + +(Note that the dashes (`-`) turn to underscores (`_`) to form the name of the +CFLAGS environment variable) + +If you are building for a Tier 3 target using `-Zbuild-std` (on Nightly Rust), +you need to set these variables as well: + +```bash +export CXX_arm_unknown_linux_gnueabi=arm-linux-gnueabi-g++ +export CC_arm_unknown_linux_gnueabi=arm-linux-gnueabi-gcc +cargo +nightly build -Zbuild-std --target=arm-unknown-linux-gnueabi +``` diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md index 7c1c5db7076b..cd0623f73a1d 100644 --- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md @@ -3,6 +3,9 @@ Target for cross-compiling Linux user-mode applications targeting the Arm BE8 architecture. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Overview BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian Arm systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md index 0aebbc34d400..a924f476411d 100644 --- a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md @@ -5,6 +5,9 @@ This target supports Linux programs with glibc on ARMv5TE CPUs without floating-point units. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target maintainers There are currently no formally documented target maintainers. diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md index e553c49589de..4ab0a07090a6 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md @@ -4,6 +4,9 @@ This target supports Armv7-A softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U). +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target maintainers [@lancethepants](https://github.com/lancethepants) diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md index 91f3ea886ccb..9fb24906b4fc 100644 --- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md @@ -4,6 +4,9 @@ This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library. +See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux +targets. + ## Target Maintainers [@skrap](https://github.com/skrap) From 88d7d20122e45f4167e262e6eda03fbf5383fb18 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Sep 2025 15:48:44 -0700 Subject: [PATCH 021/537] Skip cleanups on unsupported targets This commit is an update to the `AbortUnwindingCalls` MIR pass in the compiler. Specifically a new boolean is added for "can this target possibly unwind" and if that's `false` then terminators are all adjusted to be unreachable/not present. The end result is that this fixes 140293 for wasm targets. The motivation for this PR is that currently on WebAssembly targets the usage of the `C-unwind` ABI can lead LLVM to either (a) emit exception-handling instructions or (b) hit a LLVM-ICE-style codegen error. WebAssembly as a base instruction set does not support unwinding at all, and a later proposal to WebAssembly, the exception-handling proposal, was what enabled this. This means that the current intent of WebAssembly targets is that they maintain the baseline of "don't emit exception-handling instructions unless enabled". The commit here is intended to restore this behavior by skipping these instructions even when `C-unwind` is present. Exception-handling is a relatively tricky and also murky topic in WebAssembly, however. There are two sets of instructions LLVM can emit for WebAssembly exceptions, Rust's Emscripten target supports exceptions, WASI targets do not, the LLVM flags to enable this are not always obvious, and additionally this all touches on "changing exception-handling behavior should be a target-level concern, not a feature". Effectively WebAssembly's exception-handling integration into Rust is not finalized at this time. The best idea at this time is that a parallel set of targets will eventually be added which support exceptions, but it's not clear if/when to do this. In the meantime the goal is to keep existing targets working while still enabling experimentation with exception-handling with `-Zbuild-std` and various permutations of LLVM flags. To that extent this commit does not blanket disable these landing pads and cleanup routines for WebAssembly but instead checks to see if panic=unwind is enabled or if `+exception-handling` is enabled. Tests are updated here as well to account for this where, by default, using a `C-unwind` ABI won't affect Rust codegen at all. If `+exception-handling` is enabled, however, then Rust codegen will look like native platforms where exceptions are caught and the program aborts. More-or-less I've done my best to keep exceptions working on wasm where it's possible to have them work, but turned them off where they're not supposed to be emitted. --- .../src/abort_unwinding_calls.rs | 37 +++++++++--- compiler/rustc_span/src/symbol.rs | 1 + .../unwind-abis/c-unwind-abi-panic-abort.rs | 9 ++- tests/codegen-llvm/unwind-and-panic-abort.rs | 9 ++- tests/codegen-llvm/wasm_exceptions.rs | 57 +++++++++++++------ 5 files changed, 86 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 5bd6fdcf4857..35a21a2a8342 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -3,6 +3,7 @@ use rustc_ast::InlineAsmOptions; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, layout}; +use rustc_span::sym; use rustc_target::spec::PanicStrategy; /// A pass that runs which is targeted at ensuring that codegen guarantees about @@ -33,6 +34,19 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { return; } + // Represent whether this compilation target fundamentally doesn't + // support unwinding at all at an ABI level. If this the target has no + // support for unwinding then cleanup actions, for example, are all + // unnecessary and can be considered unreachable. + // + // Currently this is only true for wasm targets on panic=abort when the + // `exception-handling` target feature is disabled. In such a + // configuration it's illegal to emit exception-related instructions so + // it's not possible to unwind. + let target_supports_unwinding = !(tcx.sess.target.is_like_wasm + && tcx.sess.panic_strategy() == PanicStrategy::Abort + && !tcx.asm_target_features(def_id).contains(&sym::exception_handling)); + // Here we test for this function itself whether its ABI allows // unwinding or not. let body_ty = tcx.type_of(def_id).skip_binder(); @@ -54,12 +68,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { let Some(terminator) = &mut block.terminator else { continue }; let span = terminator.source_info.span; - // If we see an `UnwindResume` terminator inside a function that cannot unwind, we need - // to replace it with `UnwindTerminate`. - if let TerminatorKind::UnwindResume = &terminator.kind - && !body_can_unwind - { - terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi); + // If we see an `UnwindResume` terminator inside a function then: + // + // * If the target doesn't support unwinding at all, then this is an + // unreachable block. + // * If the body cannot unwind, we need to replace it with + // `UnwindTerminate`. + if let TerminatorKind::UnwindResume = &terminator.kind { + if !target_supports_unwinding { + terminator.kind = TerminatorKind::Unreachable; + } else if !body_can_unwind { + terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi); + } } if block.is_cleanup { @@ -93,8 +113,9 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { _ => continue, }; - if !call_can_unwind { - // If this function call can't unwind, then there's no need for it + if !call_can_unwind || !target_supports_unwinding { + // If this function call can't unwind, or if the target doesn't + // support unwinding at all, then there's no need for it // to have a landing pad. This means that we can remove any cleanup // registered for it (and turn it into `UnwindAction::Unreachable`). let cleanup = block.terminator_mut().unwind_mut().unwrap(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cdb0b5b58da6..c9c352213168 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -938,6 +938,7 @@ symbols! { ermsb_target_feature, exact_div, except, + exception_handling: "exception-handling", exchange_malloc, exclusive_range_pattern, exhaustive_integer_patterns, diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs index 8d2745ba2f7a..2ce1d1b2e00e 100644 --- a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs @@ -1,4 +1,9 @@ //@ compile-flags: -C panic=abort +//@ revisions: NONWASM WASM WASMEXN +//@ [NONWASM] ignore-wasm32 +//@ [WASM] only-wasm32 +//@ [WASMEXN] only-wasm32 +//@ [WASMEXN] compile-flags: -Ctarget-feature=+exception-handling // Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions // when the code is compiled with `panic=abort`. @@ -9,7 +14,9 @@ #[no_mangle] pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { // Handle both legacy and v0 symbol mangling. - // CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} + // NONWASM: call void @{{.*core9panicking19panic_cannot_unwind}} + // WASMEXN: call void @{{.*core9panicking19panic_cannot_unwind}} + // WASM-NOT: call void @{{.*core9panicking19panic_cannot_unwind}} may_unwind(); } diff --git a/tests/codegen-llvm/unwind-and-panic-abort.rs b/tests/codegen-llvm/unwind-and-panic-abort.rs index 8efa140058ad..c2838be00afa 100644 --- a/tests/codegen-llvm/unwind-and-panic-abort.rs +++ b/tests/codegen-llvm/unwind-and-panic-abort.rs @@ -1,4 +1,9 @@ //@ compile-flags: -C panic=abort +//@ revisions: NONWASM WASM WASMEXN +//@ [NONWASM] ignore-wasm32 +//@ [WASM] only-wasm32 +//@ [WASMEXN] only-wasm32 +//@ [WASMEXN] compile-flags: -Ctarget-feature=+exception-handling #![crate_type = "lib"] @@ -9,7 +14,9 @@ extern "C-unwind" { // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: define{{.*}}void @foo // Handle both legacy and v0 symbol mangling. -// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} +// NONWASM: call void @{{.*core9panicking19panic_cannot_unwind}} +// WASMEXN: call void @{{.*core9panicking19panic_cannot_unwind}} +// WASM-NOT: call void @{{.*core9panicking19panic_cannot_unwind}} #[no_mangle] pub unsafe extern "C" fn foo() { bar(); diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs index 796b69b722b5..e718f599a3c2 100644 --- a/tests/codegen-llvm/wasm_exceptions.rs +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -1,8 +1,9 @@ //@ only-wasm32 -//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh +//@ revisions: WASM WASMEXN +//@ [WASMEXN] compile-flags: -C panic=unwind -Z emscripten-wasm-eh #![crate_type = "lib"] -#![feature(core_intrinsics, wasm_exception_handling_intrinsics)] +#![feature(core_intrinsics, wasm_exception_handling_intrinsics, link_llvm_intrinsics)] extern "C-unwind" { fn may_panic(); @@ -22,7 +23,8 @@ impl Drop for LogOnDrop { } } -// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 +// WASM-LABEL: @test_cleanup() {{.*}} +// WASMEXN-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] pub fn test_cleanup() { let _log_on_drop = LogOnDrop; @@ -30,12 +32,16 @@ pub fn test_cleanup() { may_panic(); } - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: %cleanuppad = cleanuppad within none [] + // WASMEXN-NOT: call + // WASMEXN: invoke void @may_panic() + // WASMEXN: %cleanuppad = cleanuppad within none [] + // + // WASM: call void @may_panic() + // WASM-NOT: invoke void @may_panic() } -// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 +// WASM-LABEL: @test_rtry() {{.*}} +// WASMEXN-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] pub fn test_rtry() { unsafe { @@ -51,23 +57,40 @@ pub fn test_rtry() { ); } - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller - // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] - // CHECK: catchret + // WASMEXN-NOT: call + // WASMEXN: invoke void @may_panic() + // WASMEXN: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller + // WASMEXN: {{.*}} = catchpad within {{.*}} [ptr null] + // WASMEXN: catchret + + // WASM: call void @may_panic() + // WASM-NOT: invoke void @may_panic() + // WASM-NOT: catchswitch + // WASM-NOT: catchpad + // WASM-NOT: catchret } // Make sure the intrinsic is not inferred as nounwind. This is a regression test for #132416. -// CHECK-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0 +// +// Note that this test uses the raw `wasm_throw` intrinsic because the one from +// libstd was built with `-Cpanic=abort` and it's technically not valid to use +// when this crate is compiled with `-Cpanic=unwind`. +// +// WASMEXN-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] +#[cfg(wasmexn)] pub fn test_intrinsic() { let _log_on_drop = LogOnDrop; + + unsafe extern "C-unwind" { + #[link_name = "llvm.wasm.throw"] + fn wasm_throw(tag: i32, ptr: *mut u8) -> !; + } unsafe { - core::arch::wasm32::throw::<0>(core::ptr::null_mut()); + wasm_throw(0, core::ptr::null_mut()); } - // CHECK-NOT: call - // CHECK: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null) - // CHECK: %cleanuppad = cleanuppad within none [] + // WASMEXN-NOT: call + // WASMEXN: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null) + // WASMEXN: %cleanuppad = cleanuppad within none [] } From 4d273c4d91fc31b02c345f0dadea4a0b751f0238 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 12 Sep 2025 20:45:34 +0100 Subject: [PATCH 022/537] Fix two typos spotted in review --- src/doc/rustc/src/platform-support/arm-linux.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md index 5f320762e937..5f40743f3d07 100644 --- a/src/doc/rustc/src/platform-support/arm-linux.md +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -108,7 +108,7 @@ running this code on. For example, running `eabihf` code on an `eabi` system will not work correctly. The `gnueabi` ABI component indicates support for using the GNU C Library -(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement of for the +(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement for the original ABI (now called the Old ABI or OABI), and it is the standard ABI for 32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64` are passed as if they were integers, instead of being passed via in FPU @@ -128,9 +128,9 @@ depending on whether your distribution is using 'soft-float' (EABI) or The `musleabi` and `musleabihf` ABI components offer support for the [musl C library](https://musl.libc.org/). This C library can be used to create 'static -binaries' that have no run-time library requirements (a feature that that -glibc does not support). There are soft-float (`eabi`) and hard-float -(`eabihf`) variants, as per the `gnu*` targets above. +binaries' that have no run-time library requirements (a feature that glibc +does not support). There are soft-float (`eabi`) and hard-float (`eabihf`) +variants, as per the `gnu*` targets above. The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C library](https://uclibc-ng.org/). This is sometimes used in light-weight From 996962243670f15a88910f5c52b30fbc7b409138 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 13 Sep 2025 20:16:58 +0200 Subject: [PATCH 023/537] Improve the documentation around ZERO_AR_DATE --- compiler/rustc_target/src/spec/base/apple/mod.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index ecc742641605..39e604bcce7c 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -158,12 +158,22 @@ pub(crate) fn base( SplitDebuginfo::Off, ]), + // Tell the linker that we would like it to avoid irreproducible binaries. + // // This environment variable is pretty magical but is intended for // producing deterministic builds. This was first discovered to be used // by the `ar` tool as a way to control whether or not mtime entries in - // the archive headers were set to zero or not. It appears that - // eventually the linker got updated to do the same thing and now reads - // this environment variable too in recent versions. + // the archive headers were set to zero or not. + // + // In `ld64-351.8`, shipped with Xcode 9.3, the linker was updated to + // read this flag too. Linker versions that don't support this flag + // may embed modification timestamps in binaries (especially in debug + // information). + // + // A cleaner alternative would be to pass the `-reproducible` flag, + // though that is only supported since `ld64-819.6` shipped with Xcode + // 14, which is too new for our minimum supported version: + // https://doc.rust-lang.org/rustc/platform-support/apple-darwin.html#host-tooling // // For some more info see the commentary on #47086 link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]), From 15f6d2e8d276ba908dfa05e55eeb629373024f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 14 Sep 2025 01:12:34 +0200 Subject: [PATCH 024/537] rustdoc: Move HTML-specific attr rendering code into HTML rendering mod These functions used to be shared with the JSON backend but nowadays they aren't. --- src/librustdoc/clean/types.rs | 112 ------------------ src/librustdoc/html/render/mod.rs | 181 +++++++++++++++++++++++------- 2 files changed, 143 insertions(+), 150 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index dcd67cb7ebc7..53ae8afc027d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -801,50 +801,6 @@ impl Item { Some(tcx.visibility(def_id)) } - /// Get a list of attributes excluding `#[repr]` to display. - /// - /// Only used by the HTML output-format. - fn attributes_without_repr(&self) -> Vec { - self.attrs - .other_attrs - .iter() - .filter_map(|attr| match attr { - hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { - Some(format!("#[unsafe(link_section = \"{name}\")]")) - } - hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { - Some("#[unsafe(no_mangle)]".to_string()) - } - hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { - Some(format!("#[unsafe(export_name = \"{name}\")]")) - } - hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { - Some("#[non_exhaustive]".to_string()) - } - _ => None, - }) - .collect() - } - - /// Get a list of attributes to display on this item. - /// - /// Only used by the HTML output-format. - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { - let mut attrs = self.attributes_without_repr(); - - if let Some(repr_attr) = self.repr(tcx, cache) { - attrs.push(repr_attr); - } - attrs - } - - /// Returns a stringified `#[repr(...)]` attribute. - /// - /// Only used by the HTML output-format. - pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option { - repr_attributes(tcx, cache, self.def_id()?, self.type_()) - } - pub fn is_doc_hidden(&self) -> bool { self.attrs.is_doc_hidden() } @@ -854,74 +810,6 @@ impl Item { } } -/// Return a string representing the `#[repr]` attribute if present. -/// -/// Only used by the HTML output-format. -pub(crate) fn repr_attributes( - tcx: TyCtxt<'_>, - cache: &Cache, - def_id: DefId, - item_type: ItemType, -) -> Option { - use rustc_abi::IntegerType; - - if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) { - return None; - } - let adt = tcx.adt_def(def_id); - let repr = adt.repr(); - let mut out = Vec::new(); - if repr.c() { - out.push("C"); - } - if repr.transparent() { - // Render `repr(transparent)` iff the non-1-ZST field is public or at least one - // field is public in case all fields are 1-ZST fields. - let render_transparent = cache.document_private - || adt - .all_fields() - .find(|field| { - let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); - tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty)) - .is_ok_and(|layout| !layout.is_1zst()) - }) - .map_or_else( - || adt.all_fields().any(|field| field.vis.is_public()), - |field| field.vis.is_public(), - ); - - if render_transparent { - out.push("transparent"); - } - } - if repr.simd() { - out.push("simd"); - } - let pack_s; - if let Some(pack) = repr.pack { - pack_s = format!("packed({})", pack.bytes()); - out.push(&pack_s); - } - let align_s; - if let Some(align) = repr.align { - align_s = format!("align({})", align.bytes()); - out.push(&align_s); - } - let int_s; - if let Some(int) = repr.int { - int_s = match int { - IntegerType::Pointer(is_signed) => { - format!("{}size", if is_signed { 'i' } else { 'u' }) - } - IntegerType::Fixed(size, is_signed) => { - format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) - } - }; - out.push(&int_s); - } - if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None } -} - #[derive(Clone, Debug)] pub(crate) enum ItemKind { ExternCrateItem { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b4ef47d1e269..cc2744e48c8f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -51,7 +51,8 @@ use askama::Template; use itertools::Either; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_hir::attrs::{DeprecatedSince, Deprecation}; +use rustc_hir as hir; +use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince}; use rustc_middle::ty::print::PrintTraitRefExt; @@ -1310,43 +1311,6 @@ fn render_assoc_item( }) } -struct CodeAttribute(String); - -fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) { - write!( - w, - "
{prefix}{attr}
", - prefix = prefix, - attr = code_attr.0 - ) - .unwrap(); -} - -// When an attribute is rendered inside a tag, it is formatted using -// a div to produce a newline after it. -fn render_attributes_in_code( - w: &mut impl fmt::Write, - it: &clean::Item, - prefix: &str, - cx: &Context<'_>, -) { - for attr in it.attributes(cx.tcx(), cx.cache()) { - render_code_attribute(prefix, CodeAttribute(attr), w); - } -} - -/// used for type aliases to only render their `repr` attribute. -fn render_repr_attributes_in_code( - w: &mut impl fmt::Write, - cx: &Context<'_>, - def_id: DefId, - item_type: ItemType, -) { - if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { - render_code_attribute("", CodeAttribute(repr), w); - } -} - #[derive(Copy, Clone)] enum AssocItemLink<'a> { Anchor(Option<&'a str>), @@ -2959,3 +2923,144 @@ fn render_call_locations( w.write_str("") } + +struct CodeAttribute(String); + +fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) { + write!( + w, + "
{prefix}{attr}
", + prefix = prefix, + attr = code_attr.0 + ) + .unwrap(); +} + +// When an attribute is rendered inside a tag, it is formatted using +// a div to produce a newline after it. +fn render_attributes_in_code( + w: &mut impl fmt::Write, + item: &clean::Item, + prefix: &str, + cx: &Context<'_>, +) { + for attr in attributes(item, cx.tcx(), cx.cache()) { + render_code_attribute(prefix, CodeAttribute(attr), w); + } +} + +/// used for type aliases to only render their `repr` attribute. +fn render_repr_attributes_in_code( + w: &mut impl fmt::Write, + cx: &Context<'_>, + def_id: DefId, + item_type: ItemType, +) { + if let Some(repr) = repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { + render_code_attribute("", CodeAttribute(repr), w); + } +} + +/// Get a list of attributes excluding `#[repr]` to display. +fn attributes_without_repr(item: &clean::Item) -> Vec { + item.attrs + .other_attrs + .iter() + .filter_map(|attr| match attr { + hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { + Some(format!("#[unsafe(link_section = \"{name}\")]")) + } + hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { + Some("#[unsafe(no_mangle)]".to_string()) + } + hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { + Some(format!("#[unsafe(export_name = \"{name}\")]")) + } + hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { + Some("#[non_exhaustive]".to_string()) + } + _ => None, + }) + .collect() +} + +/// Get a list of attributes to display on this item. +fn attributes(item: &clean::Item, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { + let mut attrs = attributes_without_repr(item); + + if let Some(repr_attr) = repr(item, tcx, cache) { + attrs.push(repr_attr); + } + attrs +} + +/// Returns a stringified `#[repr(...)]` attribute. +fn repr(item: &clean::Item, tcx: TyCtxt<'_>, cache: &Cache) -> Option { + repr_attributes(tcx, cache, item.def_id()?, item.type_()) +} + +/// Return a string representing the `#[repr]` attribute if present. +pub(crate) fn repr_attributes( + tcx: TyCtxt<'_>, + cache: &Cache, + def_id: DefId, + item_type: ItemType, +) -> Option { + use rustc_abi::IntegerType; + + if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) { + return None; + } + let adt = tcx.adt_def(def_id); + let repr = adt.repr(); + let mut out = Vec::new(); + if repr.c() { + out.push("C"); + } + if repr.transparent() { + // Render `repr(transparent)` iff the non-1-ZST field is public or at least one + // field is public in case all fields are 1-ZST fields. + let render_transparent = cache.document_private + || adt + .all_fields() + .find(|field| { + let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); + tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty)) + .is_ok_and(|layout| !layout.is_1zst()) + }) + .map_or_else( + || adt.all_fields().any(|field| field.vis.is_public()), + |field| field.vis.is_public(), + ); + + if render_transparent { + out.push("transparent"); + } + } + if repr.simd() { + out.push("simd"); + } + let pack_s; + if let Some(pack) = repr.pack { + pack_s = format!("packed({})", pack.bytes()); + out.push(&pack_s); + } + let align_s; + if let Some(align) = repr.align { + align_s = format!("align({})", align.bytes()); + out.push(&align_s); + } + let int_s; + if let Some(int) = repr.int { + int_s = match int { + IntegerType::Pointer(is_signed) => { + format!("{}size", if is_signed { 'i' } else { 'u' }) + } + IntegerType::Fixed(size, is_signed) => { + format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) + } + }; + out.push(&int_s); + } + if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None } +} From d8cc5757ba92085c4fe19e86c4293bb619b2385f Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Tue, 9 Sep 2025 22:27:37 -0700 Subject: [PATCH 025/537] std_detect Darwin AArch64: add new-style detection for FEAT_CRC32 Now that this feature has a standard identifier, Darwin has started exposing it accordingly, in addition to the existing less-standard way. Check both, and enable the `crc` feature if either identifier for it is present to ensure backwards and forwards compatibility. --- library/std_detect/src/detect/os/darwin/aarch64.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index f5409361d93b..89521c1c6afb 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -37,12 +37,13 @@ pub(crate) fn detect_features() -> cache::Initializer { // Armv8.0 features not using the standard identifiers let fp = _sysctlbyname(c"hw.optional.floatingpoint"); let asimd = _sysctlbyname(c"hw.optional.AdvSIMD"); - let crc = _sysctlbyname(c"hw.optional.armv8_crc32"); + let crc_old = _sysctlbyname(c"hw.optional.armv8_crc32"); // Armv8 and Armv9 features using the standard identifiers let aes = _sysctlbyname(c"hw.optional.arm.FEAT_AES"); let bf16 = _sysctlbyname(c"hw.optional.arm.FEAT_BF16"); let bti = _sysctlbyname(c"hw.optional.arm.FEAT_BTI"); + let crc = _sysctlbyname(c"hw.optional.arm.FEAT_CRC32"); let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC"); let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT"); let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB"); @@ -111,7 +112,7 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::asimd, asimd); enable_feature(Feature::bf16, bf16); enable_feature(Feature::bti, bti); - enable_feature(Feature::crc, crc); + enable_feature(Feature::crc, crc_old || crc); enable_feature(Feature::cssc, cssc); enable_feature(Feature::dit, dit); enable_feature(Feature::dotprod, dotprod); From edc87e301b7eee22331b147dcfac2f855fdfb03a Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Sat, 13 Sep 2025 23:18:16 -0700 Subject: [PATCH 026/537] std_detect Darwin AArch64: re-alphabetize --- library/std_detect/src/detect/os/darwin/aarch64.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index 89521c1c6afb..7d9229592aaa 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -46,16 +46,16 @@ pub(crate) fn detect_features() -> cache::Initializer { let crc = _sysctlbyname(c"hw.optional.arm.FEAT_CRC32"); let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC"); let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT"); + let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd"); let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB"); let dpb2 = _sysctlbyname(c"hw.optional.arm.FEAT_DPB2"); - let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd"); let ecv = _sysctlbyname(c"hw.optional.arm.FEAT_ECV"); let fcma = _sysctlbyname(c"hw.optional.arm.FEAT_FCMA"); let fhm = _sysctlbyname(c"hw.optional.arm.FEAT_FHM"); - let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16"); - let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS"); let flagm = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM"); let flagm2 = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM2"); + let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16"); + let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS"); let hbc = _sysctlbyname(c"hw.optional.arm.FEAT_HBC"); let i8mm = _sysctlbyname(c"hw.optional.arm.FEAT_I8MM"); let jsconv = _sysctlbyname(c"hw.optional.arm.FEAT_JSCVT"); From d49f6a789ffe4b498fca1f6e173ea5ab727477a6 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Sat, 13 Sep 2025 23:24:16 -0700 Subject: [PATCH 027/537] std_detect Darwin AArch64: synchronize features Brings the list of checkable features up to date with the initial release of macOS 26 "Tahoe". --- library/std_detect/src/detect/os/darwin/aarch64.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index 7d9229592aaa..8c9fd9647b8a 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -63,6 +63,8 @@ pub(crate) fn detect_features() -> cache::Initializer { let rcpc2 = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC2"); let lse = _sysctlbyname(c"hw.optional.arm.FEAT_LSE"); let lse2 = _sysctlbyname(c"hw.optional.arm.FEAT_LSE2"); + let mte = _sysctlbyname(c"hw.optional.arm.FEAT_MTE"); + let mte2 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE2"); let pauth = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth"); let pmull = _sysctlbyname(c"hw.optional.arm.FEAT_PMULL"); let rdm = _sysctlbyname(c"hw.optional.arm.FEAT_RDM"); @@ -73,6 +75,7 @@ pub(crate) fn detect_features() -> cache::Initializer { let sha512 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA512"); let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME"); let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2"); + let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1"); let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64"); let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64"); let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS"); @@ -88,6 +91,12 @@ pub(crate) fn detect_features() -> cache::Initializer { let ebf16 = _sysctlbyname(c"hw.optional.arm.FEAT_EBF16"); let fpac = _sysctlbyname(c"hw.optional.arm.FEAT_FPAC"); let fpaccombine = _sysctlbyname(c"hw.optional.arm.FEAT_FPACCOMBINE"); + let mte_async = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_ASYNC"); + let mte_canonical_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_CANONICAL_TAGS"); + let mte_no_address_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_NO_ADDRESS_TAGS"); + let mte_store_only = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_STORE_ONLY"); + let mte3 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE3"); + let mte4 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE4"); let pacimp = _sysctlbyname(c"hw.optional.arm.FEAT_PACIMP"); let pauth2 = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth2"); let rpres = _sysctlbyname(c"hw.optional.arm.FEAT_RPRES"); @@ -131,6 +140,7 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::jsconv, jsconv); enable_feature(Feature::lse, lse); enable_feature(Feature::lse2, lse2); + enable_feature(Feature::mte, mte && mte2); enable_feature(Feature::paca, pauth); enable_feature(Feature::pacg, pauth); enable_feature(Feature::pmull, aes && pmull); @@ -142,6 +152,7 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::sha3, sha512 && sha3 && asimd); enable_feature(Feature::sme, sme); enable_feature(Feature::sme2, sme2); + enable_feature(Feature::sme2p1, sme2p1); enable_feature(Feature::sme_f64f64, sme_f64f64); enable_feature(Feature::sme_i16i64, sme_i16i64); enable_feature(Feature::ssbs, ssbs); From 430d3532662fe309f3893ac2680775c1a5db0c41 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sun, 7 Sep 2025 18:36:15 +0100 Subject: [PATCH 028/537] Drop armebv7r-none-eabi* to Tier 3 These targets are not widely used, and are difficult to test because qemu-system-arm cannot emulate them. --- compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs | 2 +- .../rustc_target/src/spec/targets/armebv7r_none_eabihf.rs | 2 +- src/doc/rustc/src/platform-support.md | 4 ++-- src/doc/rustc/src/platform-support/armebv7r-none-eabi.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index d227d63c4a34..0ae7cd7a3773 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { llvm_target: "armebv7r-none-eabi".into(), metadata: TargetMetadata { description: Some("Bare Armv7-R, Big Endian".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index c373afb914e3..71ffd8baed57 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { llvm_target: "armebv7r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Bare Armv7-R, Big Endian, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e5e46f726375..3f8e753334e7 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -156,8 +156,6 @@ target | std | notes `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3 `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC -[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian -[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android @@ -283,6 +281,8 @@ target | std | host | notes [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS [`arm64e-apple-tvos`](platform-support/arm64e-apple-tvos.md) | ✓ | | ARM64e Apple tvOS [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). +[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian +[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat [`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Bare Armv4T `armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md index 3e90319c373e..d5c676ea9a4c 100644 --- a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md @@ -1,6 +1,6 @@ # `armebv7r-none-eabi` and `armebv7r-none-eabihf` -* **Tier: 2** +* **Tier: 3** * **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv7-R architecture family running in Big From c8663eec6a667ae6e7571297cb15192425311c33 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Fri, 29 Aug 2025 23:29:46 +0300 Subject: [PATCH 029/537] Introduce CoerceShared lang item and trait --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/marker.rs | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 67d2f15d4147..889b16a7a2bb 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -441,6 +441,7 @@ language_item_table! { // Reborrowing related lang-items Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0); + CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cdb0b5b58da6..882abf7bcc97 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -679,6 +679,7 @@ symbols! { cmpxchg16b_target_feature, cmse_nonsecure_entry, coerce_pointee_validated, + coerce_shared, coerce_unsized, cold, cold_path, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index d03d7a43469a..8541a5b91cdd 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1372,3 +1372,12 @@ pub trait CoercePointeeValidated { pub trait Reborrow { // Empty. } + +/// Allows reborrowable value to be reborrowed as shared, creating a copy of +/// that disables the source for writes for the lifetime of the copy. +#[lang = "coerce_shared"] +#[unstable(feature = "reborrow", issue = "145612")] +pub trait CoerceShared: Reborrow { + /// The type of this value when reborrowed as shared. + type Target: Copy; +} From fce8c13f77bcbebfea4461536be828d7136b8c1a Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Fri, 29 Aug 2025 23:35:07 +0300 Subject: [PATCH 030/537] Add reborrow CoerceShared feature gate test --- .../feature-gate-reborrow-coerce-shared.rs | 3 +++ .../feature-gate-reborrow-coerce-shared.stderr | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs create mode 100644 tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs new file mode 100644 index 000000000000..48a14959d8d6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs @@ -0,0 +1,3 @@ +use std::marker::CoerceShared; //~ ERROR use of unstable library feature `reborrow` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr new file mode 100644 index 000000000000..c4c5e06778af --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow-coerce-shared.rs:1:5 + | +LL | use std::marker::CoerceShared; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 35bae9df1dfb164de7be95180a0982312128d559 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Sat, 30 Aug 2025 21:16:56 +0300 Subject: [PATCH 031/537] Introduce basic Reborrow tests --- tests/ui/reborrow/custom_mut.rs | 13 +++++++++ tests/ui/reborrow/custom_mut.stderr | 29 +++++++++++++++++++ tests/ui/reborrow/custom_mut_coerce_shared.rs | 28 ++++++++++++++++++ .../reborrow/custom_mut_coerce_shared.stderr | 19 ++++++++++++ tests/ui/reborrow/option_mut.rs | 7 +++++ tests/ui/reborrow/option_mut.stderr | 21 ++++++++++++++ tests/ui/reborrow/option_mut_coerce_shared.rs | 11 +++++++ .../reborrow/option_mut_coerce_shared.stderr | 23 +++++++++++++++ tests/ui/reborrow/pin_mut.rs | 10 +++++++ tests/ui/reborrow/pin_mut.stderr | 21 ++++++++++++++ tests/ui/reborrow/pin_mut_coerce_shared.rs | 14 +++++++++ .../ui/reborrow/pin_mut_coerce_shared.stderr | 19 ++++++++++++ 12 files changed, 215 insertions(+) create mode 100644 tests/ui/reborrow/custom_mut.rs create mode 100644 tests/ui/reborrow/custom_mut.stderr create mode 100644 tests/ui/reborrow/custom_mut_coerce_shared.rs create mode 100644 tests/ui/reborrow/custom_mut_coerce_shared.stderr create mode 100644 tests/ui/reborrow/option_mut.rs create mode 100644 tests/ui/reborrow/option_mut.stderr create mode 100644 tests/ui/reborrow/option_mut_coerce_shared.rs create mode 100644 tests/ui/reborrow/option_mut_coerce_shared.stderr create mode 100644 tests/ui/reborrow/pin_mut.rs create mode 100644 tests/ui/reborrow/pin_mut.stderr create mode 100644 tests/ui/reborrow/pin_mut_coerce_shared.rs create mode 100644 tests/ui/reborrow/pin_mut_coerce_shared.stderr diff --git a/tests/ui/reborrow/custom_mut.rs b/tests/ui/reborrow/custom_mut.rs new file mode 100644 index 000000000000..b55a5e6faa3d --- /dev/null +++ b/tests/ui/reborrow/custom_mut.rs @@ -0,0 +1,13 @@ +#![feature(reborrow)] +use std::marker::Reborrow; + +struct CustomMut<'a, T>(&'a mut T); +impl<'a, T> Reborrow for CustomMut<'a, T> {} + +fn method(a: CustomMut<'_, ()>) {} + +fn main() { + let a = CustomMut(&mut ()); + let _ = method(a); + let _ = method(a); //~ERROR use of moved value: `a` +} diff --git a/tests/ui/reborrow/custom_mut.stderr b/tests/ui/reborrow/custom_mut.stderr new file mode 100644 index 000000000000..3b3f47b62d6f --- /dev/null +++ b/tests/ui/reborrow/custom_mut.stderr @@ -0,0 +1,29 @@ +error[E0382]: use of moved value: `a` + --> $DIR/custom_mut.rs:12:20 + | +LL | let a = CustomMut(&mut ()); + | - move occurs because `a` has type `CustomMut<'_, ()>`, which does not implement the `Copy` trait +LL | let _ = method(a); + | - value moved here +LL | let _ = method(a); + | ^ value used here after move + | +note: consider changing this parameter type in function `method` to borrow instead if owning the value isn't necessary + --> $DIR/custom_mut.rs:7:14 + | +LL | fn method(a: CustomMut<'_, ()>) {} + | ------ ^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +note: if `CustomMut<'_, ()>` implemented `Clone`, you could clone the value + --> $DIR/custom_mut.rs:4:1 + | +LL | struct CustomMut<'a, T>(&'a mut T); + | ^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let _ = method(a); + | - you could clone this value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.rs b/tests/ui/reborrow/custom_mut_coerce_shared.rs new file mode 100644 index 000000000000..b292b5b073ce --- /dev/null +++ b/tests/ui/reborrow/custom_mut_coerce_shared.rs @@ -0,0 +1,28 @@ +#![feature(reborrow)] +use std::marker::{Reborrow, CoerceShared}; + +struct CustomMut<'a, T>(&'a mut T); +impl<'a, T> Reborrow for CustomMut<'a, T> {} +impl<'a, T> CoerceShared for CustomMut<'a, T> { + type Target = CustomRef<'a, T>; +} + +struct CustomRef<'a, T>(&'a T); + +impl<'a, T> Clone for CustomRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for CustomRef<'a, T> {} + +fn method(a: CustomRef<'_, ()>) {} //~NOTE function defined here + +fn main() { + let a = CustomMut(&mut ()); + method(a); + //~^ ERROR mismatched types + //~| NOTE expected `CustomRef<'_, ()>`, found `CustomMut<'_, ()>` + //~| NOTE arguments to this function are incorrect + //~| NOTE expected struct `CustomRef<'_, ()>` +} diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.stderr b/tests/ui/reborrow/custom_mut_coerce_shared.stderr new file mode 100644 index 000000000000..508651badc0a --- /dev/null +++ b/tests/ui/reborrow/custom_mut_coerce_shared.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/custom_mut_coerce_shared.rs:23:12 + | +LL | method(a); + | ------ ^ expected `CustomRef<'_, ()>`, found `CustomMut<'_, ()>` + | | + | arguments to this function are incorrect + | + = note: expected struct `CustomRef<'_, ()>` + found struct `CustomMut<'_, ()>` +note: function defined here + --> $DIR/custom_mut_coerce_shared.rs:19:4 + | +LL | fn method(a: CustomRef<'_, ()>) {} + | ^^^^^^ -------------------- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/reborrow/option_mut.rs b/tests/ui/reborrow/option_mut.rs new file mode 100644 index 000000000000..60b7145a7b2e --- /dev/null +++ b/tests/ui/reborrow/option_mut.rs @@ -0,0 +1,7 @@ +fn method(a: Option<& mut ()>) {} + +fn main() { + let a = Some(&mut ()); + let _ = method(a); + let _ = method(a); //~ERROR use of moved value: `a` +} diff --git a/tests/ui/reborrow/option_mut.stderr b/tests/ui/reborrow/option_mut.stderr new file mode 100644 index 000000000000..497319d2e903 --- /dev/null +++ b/tests/ui/reborrow/option_mut.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `a` + --> $DIR/option_mut.rs:6:20 + | +LL | let a = Some(&mut ()); + | - move occurs because `a` has type `Option<&mut ()>`, which does not implement the `Copy` trait +LL | let _ = method(a); + | - value moved here +LL | let _ = method(a); + | ^ value used here after move + | +note: consider changing this parameter type in function `method` to borrow instead if owning the value isn't necessary + --> $DIR/option_mut.rs:1:14 + | +LL | fn method(a: Option<& mut ()>) {} + | ------ ^^^^^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/reborrow/option_mut_coerce_shared.rs b/tests/ui/reborrow/option_mut_coerce_shared.rs new file mode 100644 index 000000000000..95d33ed94dd7 --- /dev/null +++ b/tests/ui/reborrow/option_mut_coerce_shared.rs @@ -0,0 +1,11 @@ +fn method(a: Option<&()>) {} //~NOTE function defined here + +fn main() { + let a = Some(&mut ()); + method(a); + //~^ ERROR mismatched types + //~| NOTE arguments to this function are incorrect + //~| NOTE types differ in mutability + //~| NOTE expected enum `Option<&()>` + //~| NOTE found enum `Option<&mut ()>` +} diff --git a/tests/ui/reborrow/option_mut_coerce_shared.stderr b/tests/ui/reborrow/option_mut_coerce_shared.stderr new file mode 100644 index 000000000000..6ca1a2374610 --- /dev/null +++ b/tests/ui/reborrow/option_mut_coerce_shared.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/option_mut_coerce_shared.rs:5:12 + | +LL | method(a); + | ------ ^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected enum `Option<&()>` + found enum `Option<&mut ()>` +note: function defined here + --> $DIR/option_mut_coerce_shared.rs:1:4 + | +LL | fn method(a: Option<&()>) {} + | ^^^^^^ -------------- +help: try using `.as_deref()` to convert `Option<&mut ()>` to `Option<&()>` + | +LL | method(a.as_deref()); + | +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/reborrow/pin_mut.rs b/tests/ui/reborrow/pin_mut.rs new file mode 100644 index 000000000000..966106969943 --- /dev/null +++ b/tests/ui/reborrow/pin_mut.rs @@ -0,0 +1,10 @@ +use std::pin::Pin; + +fn method(a: Pin<& mut ()>) {} + +fn main() { + let a = &mut (); + let a = Pin::new(a); + let _ = method(a); + let _ = method(a); //~ERROR use of moved value: `a` +} diff --git a/tests/ui/reborrow/pin_mut.stderr b/tests/ui/reborrow/pin_mut.stderr new file mode 100644 index 000000000000..8a10e2d9af26 --- /dev/null +++ b/tests/ui/reborrow/pin_mut.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `a` + --> $DIR/pin_mut.rs:9:20 + | +LL | let a = Pin::new(a); + | - move occurs because `a` has type `Pin<&mut ()>`, which does not implement the `Copy` trait +LL | let _ = method(a); + | - value moved here +LL | let _ = method(a); + | ^ value used here after move + | +note: consider changing this parameter type in function `method` to borrow instead if owning the value isn't necessary + --> $DIR/pin_mut.rs:3:14 + | +LL | fn method(a: Pin<& mut ()>) {} + | ------ ^^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/reborrow/pin_mut_coerce_shared.rs b/tests/ui/reborrow/pin_mut_coerce_shared.rs new file mode 100644 index 000000000000..fd529195fe01 --- /dev/null +++ b/tests/ui/reborrow/pin_mut_coerce_shared.rs @@ -0,0 +1,14 @@ +use std::pin::Pin; + +fn method(a: Pin<&()>) {} //~NOTE function defined here + +fn main() { + let a = &mut (); + let a = Pin::new(a); + method(a); + //~^ ERROR mismatched types + //~| NOTE arguments to this function are incorrect + //~| NOTE types differ in mutability + //~| NOTE expected struct `Pin<&()>` + //~| NOTE found struct `Pin<&mut ()>` +} diff --git a/tests/ui/reborrow/pin_mut_coerce_shared.stderr b/tests/ui/reborrow/pin_mut_coerce_shared.stderr new file mode 100644 index 000000000000..74ecf4de4c78 --- /dev/null +++ b/tests/ui/reborrow/pin_mut_coerce_shared.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/pin_mut_coerce_shared.rs:8:12 + | +LL | method(a); + | ------ ^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected struct `Pin<&()>` + found struct `Pin<&mut ()>` +note: function defined here + --> $DIR/pin_mut_coerce_shared.rs:3:4 + | +LL | fn method(a: Pin<&()>) {} + | ^^^^^^ ----------- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From c4a87eb62cd74e31e5d3889741a76a4bb2a48ed6 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Mon, 15 Sep 2025 20:32:06 +0300 Subject: [PATCH 032/537] fix: Move CoerceShared into ops --- library/core/src/marker.rs | 9 --------- library/core/src/ops/mod.rs | 3 +++ library/core/src/ops/reborrow.rs | 10 ++++++++++ .../feature-gate-reborrow-coerce-shared.rs | 2 +- .../feature-gate-reborrow-coerce-shared.stderr | 4 ++-- tests/ui/reborrow/custom_mut_coerce_shared.rs | 3 ++- tests/ui/reborrow/custom_mut_coerce_shared.stderr | 4 ++-- 7 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 library/core/src/ops/reborrow.rs diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 8541a5b91cdd..d03d7a43469a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1372,12 +1372,3 @@ pub trait CoercePointeeValidated { pub trait Reborrow { // Empty. } - -/// Allows reborrowable value to be reborrowed as shared, creating a copy of -/// that disables the source for writes for the lifetime of the copy. -#[lang = "coerce_shared"] -#[unstable(feature = "reborrow", issue = "145612")] -pub trait CoerceShared: Reborrow { - /// The type of this value when reborrowed as shared. - type Target: Copy; -} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 87dd873fdb57..9814f5d5795c 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -149,6 +149,7 @@ mod function; mod index; mod index_range; mod range; +mod reborrow; mod try_trait; mod unsize; @@ -189,6 +190,8 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; pub use self::range::{OneSidedRange, OneSidedRangeBound}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; +#[unstable(feature = "reborrow", issue = "145612")] +pub use self::reborrow::CoerceShared; #[unstable(feature = "try_trait_v2_residual", issue = "91285")] pub use self::try_trait::Residual; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] diff --git a/library/core/src/ops/reborrow.rs b/library/core/src/ops/reborrow.rs new file mode 100644 index 000000000000..90288f766d50 --- /dev/null +++ b/library/core/src/ops/reborrow.rs @@ -0,0 +1,10 @@ +use crate::marker::Reborrow; + +/// Allows reborrowable value to be reborrowed as shared, creating a copy +/// that disables the source for writes for the lifetime of the copy. +#[lang = "coerce_shared"] +#[unstable(feature = "reborrow", issue = "145612")] +pub trait CoerceShared: Reborrow { + /// The type of this value when reborrowed as shared. + type Target: Copy; +} diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs index 48a14959d8d6..c8ca45370891 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs @@ -1,3 +1,3 @@ -use std::marker::CoerceShared; //~ ERROR use of unstable library feature `reborrow` +use std::ops::CoerceShared; //~ ERROR use of unstable library feature `reborrow` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr index c4c5e06778af..dbbbcdf2fd57 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `reborrow` --> $DIR/feature-gate-reborrow-coerce-shared.rs:1:5 | -LL | use std::marker::CoerceShared; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | use std::ops::CoerceShared; + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #145612 for more information = help: add `#![feature(reborrow)]` to the crate attributes to enable diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.rs b/tests/ui/reborrow/custom_mut_coerce_shared.rs index b292b5b073ce..28d802aabffe 100644 --- a/tests/ui/reborrow/custom_mut_coerce_shared.rs +++ b/tests/ui/reborrow/custom_mut_coerce_shared.rs @@ -1,5 +1,6 @@ #![feature(reborrow)] -use std::marker::{Reborrow, CoerceShared}; +use std::marker::Reborrow; +use std::ops::CoerceShared; struct CustomMut<'a, T>(&'a mut T); impl<'a, T> Reborrow for CustomMut<'a, T> {} diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.stderr b/tests/ui/reborrow/custom_mut_coerce_shared.stderr index 508651badc0a..90d8a9816054 100644 --- a/tests/ui/reborrow/custom_mut_coerce_shared.stderr +++ b/tests/ui/reborrow/custom_mut_coerce_shared.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/custom_mut_coerce_shared.rs:23:12 + --> $DIR/custom_mut_coerce_shared.rs:24:12 | LL | method(a); | ------ ^ expected `CustomRef<'_, ()>`, found `CustomMut<'_, ()>` @@ -9,7 +9,7 @@ LL | method(a); = note: expected struct `CustomRef<'_, ()>` found struct `CustomMut<'_, ()>` note: function defined here - --> $DIR/custom_mut_coerce_shared.rs:19:4 + --> $DIR/custom_mut_coerce_shared.rs:20:4 | LL | fn method(a: CustomRef<'_, ()>) {} | ^^^^^^ -------------------- From 9e2f9edd7f79c1e11339277bfb83a0c888740438 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 15 Sep 2025 21:43:13 -0400 Subject: [PATCH 033/537] =?UTF-8?q?Don=E2=80=99t=20suggest=20foreign=20`do?= =?UTF-8?q?c(hidden)`=20types=20in=20E0277=20diagnostics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../traits/fulfillment_errors.rs | 17 ++++++- tests/ui/proc-macro/quote/not-quotable.stderr | 4 +- .../ui/suggestions/auxiliary/hidden-struct.rs | 32 +++++++++++--- .../dont-suggest-foreign-doc-hidden.rs | 18 ++++++-- .../dont-suggest-foreign-doc-hidden.stderr | 44 ++++++++++++++++--- 5 files changed, 97 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 149f5e638b1a..dff846cfc0af 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1894,6 +1894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { other: bool, param_env: ty::ParamEnv<'tcx>, ) -> bool { + let parent_map = self.tcx.visible_parent_map(()); let alternative_candidates = |def_id: DefId| { let mut impl_candidates: Vec<_> = self .tcx @@ -1918,7 +1919,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be generalized, both to // be more granular, and probably look past other `#[fundamental]` // types, too. - self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx) + let mut did = def.did(); + if self.tcx.visibility(did).is_accessible_from(body_def_id, self.tcx) { + // don't suggest foreign `#[doc(hidden)]` types + if !did.is_local() { + while let Some(parent) = parent_map.get(&did) { + if self.tcx.is_doc_hidden(did) { + return false; + } + did = *parent; + } + } + true + } else { + false + } } else { true } diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr index d1c3d06f2b66..62a02638e548 100644 --- a/tests/ui/proc-macro/quote/not-quotable.stderr +++ b/tests/ui/proc-macro/quote/not-quotable.stderr @@ -15,8 +15,8 @@ LL | let _ = quote! { $ip }; Cow<'_, T> Option Rc - RepInterp - and 25 others + bool + and 24 others error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/auxiliary/hidden-struct.rs b/tests/ui/suggestions/auxiliary/hidden-struct.rs index 30d69acac209..1f495a9f2224 100644 --- a/tests/ui/suggestions/auxiliary/hidden-struct.rs +++ b/tests/ui/suggestions/auxiliary/hidden-struct.rs @@ -1,3 +1,5 @@ +// `Foo` and `Bar` should not be suggested in diagnostics of dependents + #[doc(hidden)] pub mod hidden { pub struct Foo; @@ -5,13 +7,29 @@ pub mod hidden { pub mod hidden1 { #[doc(hidden)] - pub struct Foo; -} - - -#[doc(hidden)] -pub(crate) mod hidden2 { pub struct Bar; } -pub use hidden2::Bar; +// `Baz` and `Quux` *should* be suggested in diagnostics of dependents + +#[doc(hidden)] +pub mod hidden2 { + pub struct Baz; +} + +pub use hidden2::Baz; + +#[doc(hidden)] +pub(crate) mod hidden3 { + pub struct Quux; +} + +pub use hidden3::Quux; + +pub trait Marker {} + +impl Marker for Option {} +impl Marker for hidden::Foo {} +impl Marker for hidden1::Bar {} +impl Marker for Baz {} +impl Marker for Quux {} diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs index 281975dcc2f3..a83e496f2703 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.rs @@ -1,5 +1,4 @@ //@ aux-build:hidden-struct.rs -//@ compile-flags: --crate-type lib extern crate hidden_struct; @@ -9,7 +8,20 @@ mod local { } pub fn test(_: Foo) {} -//~^ ERROR cannot find type `Foo` in this scope +//~^ ERROR [E0412] pub fn test2(_: Bar) {} -//~^ ERROR cannot find type `Bar` in this scope +//~^ ERROR [E0412] + +pub fn test3(_: Baz) {} +//~^ ERROR [E0412] + +pub fn test4(_: Quux) {} +//~^ ERROR [E0412] + +fn test5() {} + +fn main() { + test5::(); + //~^ ERROR [E0277] +} diff --git a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr index 7fb4d95ff9bf..7036708756d6 100644 --- a/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr +++ b/tests/ui/suggestions/dont-suggest-foreign-doc-hidden.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Foo` in this scope - --> $DIR/dont-suggest-foreign-doc-hidden.rs:11:16 + --> $DIR/dont-suggest-foreign-doc-hidden.rs:10:16 | LL | pub fn test(_: Foo) {} | ^^^ not found in this scope @@ -10,16 +10,50 @@ LL + use local::Foo; | error[E0412]: cannot find type `Bar` in this scope - --> $DIR/dont-suggest-foreign-doc-hidden.rs:14:17 + --> $DIR/dont-suggest-foreign-doc-hidden.rs:13:17 | LL | pub fn test2(_: Bar) {} | ^^^ not found in this scope + +error[E0412]: cannot find type `Baz` in this scope + --> $DIR/dont-suggest-foreign-doc-hidden.rs:16:17 + | +LL | pub fn test3(_: Baz) {} + | ^^^ not found in this scope | help: consider importing this struct | -LL + use hidden_struct::Bar; +LL + use hidden_struct::Baz; | -error: aborting due to 2 previous errors +error[E0412]: cannot find type `Quux` in this scope + --> $DIR/dont-suggest-foreign-doc-hidden.rs:19:17 + | +LL | pub fn test4(_: Quux) {} + | ^^^^ not found in this scope + | +help: consider importing this struct + | +LL + use hidden_struct::Quux; + | -For more information about this error, try `rustc --explain E0412`. +error[E0277]: the trait bound `i32: Marker` is not satisfied + --> $DIR/dont-suggest-foreign-doc-hidden.rs:25:13 + | +LL | test5::(); + | ^^^ the trait `Marker` is not implemented for `i32` + | + = help: the following other types implement trait `Marker`: + Baz + Option + Quux +note: required by a bound in `test5` + --> $DIR/dont-suggest-foreign-doc-hidden.rs:22:13 + | +LL | fn test5() {} + | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test5` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0412. +For more information about an error, try `rustc --explain E0277`. From 1ae720a52dd6a3ed5a375d183aea5330de49eb42 Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Tue, 16 Sep 2025 11:51:19 +0100 Subject: [PATCH 034/537] Fix spelling of "adaptor" These docs are in en_US, so "adapter" is the correct spelling (and indeed used in the next line.) --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ff0e29e04c25..a45edd08e8cc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1081,7 +1081,7 @@ pub trait Read { default_read_buf_exact(self, cursor) } - /// Creates a "by reference" adaptor for this instance of `Read`. + /// Creates a "by reference" adapter for this instance of `Read`. /// /// The returned adapter also implements `Read` and will simply borrow this /// current reader. From 325ceef018030f922840a10741d194b4223ecc59 Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Tue, 16 Sep 2025 11:52:43 +0100 Subject: [PATCH 035/537] Fix other uses of "adaptor" --- library/core/src/iter/adapters/flatten.rs | 2 +- tests/ui/iterators/issue-58952-filter-type-length.rs | 2 +- .../traits/next-solver/typeck/normalize-in-upvar-collection.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index a820045521b9..c50f07ff6bb6 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -779,7 +779,7 @@ impl OneShot for result::IterMut<'_, T> {} impl OneShot for Empty {} impl OneShot for array::IntoIter {} -// These adaptors never increase the number of items. +// These adapters never increase the number of items. // (There are more possible, but for now this matches BoundedSize above.) impl OneShot for Cloned {} impl OneShot for Copied {} diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index 6730865b6c7f..525a2e39a913 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -2,7 +2,7 @@ //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. -// FIXME: Once the size of iterator adaptors is further reduced, +// FIXME: Once the size of iterator adapters is further reduced, // increase the complexity of this test. use std::collections::VecDeque; diff --git a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs index 6567f2752404..2f108daf1e5a 100644 --- a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs +++ b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Znext-solver //@ check-pass -// Fixes a regression in icu_provider_adaptors where we weren't normalizing the +// Fixes a regression in icu_provider_adapters where we weren't normalizing the // return type of a function type before performing a `Ty::builtin_deref` call, // leading to an ICE. From 79c9f6ee9b3229279ffdaa0515c7b0320c0b0737 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 16 Sep 2025 21:36:45 +1000 Subject: [PATCH 036/537] Stop using `as_c_char_ptr` for coverage-related bindings --- .../rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs | 7 +++---- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 12 +++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index bc4f6bb6a82b..2aa3dec81317 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -2,7 +2,6 @@ use std::ffi::CString; -use crate::common::AsCCharPtr; use crate::coverageinfo::ffi; use crate::llvm; @@ -34,7 +33,7 @@ pub(crate) fn create_pgo_func_name_var<'ll>( unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar( llfn, - mangled_fn_name.as_c_char_ptr(), + mangled_fn_name.as_ptr(), mangled_fn_name.len(), ) } @@ -44,7 +43,7 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef]) -> Vec, Vec<_>>(); llvm::build_byte_buffer(|buffer| unsafe { @@ -89,7 +88,7 @@ pub(crate) fn write_function_mappings_to_buffer( /// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`, /// as required for parts of the LLVM coverage mapping format. pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { - unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) } + unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_ptr(), bytes.len()) } } /// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0679f55ab7f0..52c24169f893 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2080,8 +2080,11 @@ unsafe extern "C" { ConstraintsLen: size_t, ) -> bool; + /// A list of pointer-length strings is passed as two pointer-length slices, + /// one slice containing pointers and one slice containing their corresponding + /// lengths. The implementation will check that both slices have the same length. pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer( - Filenames: *const *const c_char, + Filenames: *const *const c_uchar, // See "PTR_LEN_STR". FilenamesLen: size_t, Lengths: *const size_t, LengthsLen: size_t, @@ -2104,10 +2107,13 @@ unsafe extern "C" { pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar( F: &Value, - FuncName: *const c_char, + FuncName: *const c_uchar, // See "PTR_LEN_STR". FuncNameLen: size_t, ) -> &Value; - pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64; + pub(crate) fn LLVMRustCoverageHashBytes( + Bytes: *const c_uchar, // See "PTR_LEN_STR". + NumBytes: size_t, + ) -> u64; pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString); From 06a7460455284aca27fbf65505c385e3dc275da3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 16 Sep 2025 21:44:40 +1000 Subject: [PATCH 037/537] Mark some coverage-related bindings as safe --- .../src/coverageinfo/llvm_cov.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index 2aa3dec81317..d50eb533ffdb 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -6,21 +6,21 @@ use crate::coverageinfo::ffi; use crate::llvm; pub(crate) fn covmap_var_name() -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovmapVarNameToString(s); })) .expect("covmap variable name should not contain NUL") } pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s); })) .expect("covmap section name should not contain NUL") } pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s); })) .expect("covfun section name should not contain NUL") @@ -95,5 +95,5 @@ pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { /// as a raw numeric value. For historical reasons, the numeric value is 1 less /// than the number in the version's name, so `Version7` is actually `6u32`. pub(crate) fn mapping_version() -> u32 { - unsafe { llvm::LLVMRustCoverageMappingVersion() } + llvm::LLVMRustCoverageMappingVersion() } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 52c24169f893..74251cd2b494 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2115,13 +2115,17 @@ unsafe extern "C" { NumBytes: size_t, ) -> u64; - pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString); + pub(crate) safe fn LLVMRustCoverageWriteCovmapSectionNameToString( + M: &Module, + OutStr: &RustString, + ); + pub(crate) safe fn LLVMRustCoverageWriteCovfunSectionNameToString( + M: &Module, + OutStr: &RustString, + ); + pub(crate) safe fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString); - pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString); - - pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString); - - pub(crate) fn LLVMRustCoverageMappingVersion() -> u32; + pub(crate) safe fn LLVMRustCoverageMappingVersion() -> u32; pub(crate) fn LLVMRustDebugMetadataVersion() -> u32; pub(crate) fn LLVMRustVersionMajor() -> u32; pub(crate) fn LLVMRustVersionMinor() -> u32; From 401857aaa1e21df49e0d013b9856ab6dbe34870b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 16 Sep 2025 20:20:02 +0200 Subject: [PATCH 038/537] cmse: fix 'region variables should not be hashed' --- .../src/hir_ty_lowering/cmse.rs | 1 + .../undeclared-lifetime.rs | 20 +++++++++++++++++++ .../undeclared-lifetime.stderr | 19 ++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 5088c63702e6..ae9558cae3b9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -128,6 +128,7 @@ fn is_valid_cmse_inputs<'tcx>( // this type is only used for layout computation, which does not rely on regions let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); for (index, ty) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs new file mode 100644 index 000000000000..5fa5b74c0c0b --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs @@ -0,0 +1,20 @@ +//@ add-core-stubs +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Cincremental=true +//@ needs-llvm-components: arm +#![feature(abi_cmse_nonsecure_call, no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// A regression test for https://github.com/rust-lang/rust/issues/131639. +// NOTE: -Cincremental=true was required for triggering the bug. + +fn foo() { + id::(PhantomData); + //~^ ERROR use of undeclared lifetime name `'a` +} + +fn id(x: PhantomData) -> PhantomData { + x +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr new file mode 100644 index 000000000000..4aca17e73544 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr @@ -0,0 +1,19 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/undeclared-lifetime.rs:14:43 + | +LL | id::(PhantomData); + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | id:: extern "cmse-nonsecure-call" fn(&'a ())>(PhantomData); + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | fn foo<'a>() { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0261`. From 603d64c3bb61e5e39bf624cc152fe1b844e70220 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 17 Sep 2025 14:59:02 +0800 Subject: [PATCH 039/537] Fix complete type in nested pattern Example --- ```rust struct Foo { num: u32 } struct Bar(Foo); fn foo(Bar($0)) {} ``` **Before this PR**: ```rust struct Foo { num: u32 } struct Bar(Foo); fn foo(Bar(Foo { num$1 }: Foo$0)) {} ``` **After this PR**: ```rust struct Foo { num: u32 } struct Bar(Foo); fn foo(Bar(Foo { num$1 }$0)) {} ``` --- .../ide-completion/src/render/pattern.rs | 1 + .../ide-completion/src/tests/pattern.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 60ec1128233e..312d3bd426f9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -163,6 +163,7 @@ fn render_pat( PatternContext { param_ctx: Some(ParamContext { kind: ParamKind::Function(_), .. }), has_type_ascription: false, + parent_pat: None, .. } ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 9ec27252fd74..6eb0b818d697 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -398,6 +398,25 @@ fn foo($0) {} ) } +#[test] +fn completes_in_fn_param_in_nested_pattern() { + check( + r#" +struct Foo { num: u32 } +struct Bar(Foo); +fn foo(Bar($0)) {} +"#, + expect![[r#" + st Bar + st Foo + bn Bar(…) Bar($1)$0 + bn Foo {…} Foo { num$1 }$0 + kw mut + kw ref + "#]], + ) +} + #[test] fn completes_in_closure_param() { check( From 6f813e887af44d74e9bcfdb207ecab407037a939 Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Mon, 1 Sep 2025 16:53:50 +0100 Subject: [PATCH 040/537] Adds AArch64 GCS support - Adds option to rustc config to enable GCS - Passes `guarded-control-stack` flag to llvm if enabled --- compiler/rustc_codegen_llvm/src/attributes.rs | 5 ++++- compiler/rustc_codegen_llvm/src/context.rs | 9 ++++++++- compiler/rustc_interface/src/tests.rs | 3 ++- compiler/rustc_session/src/config.rs | 1 + compiler/rustc_session/src/options.rs | 3 ++- .../src/compiler-flags/branch-protection.md | 1 + 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 573c51a95398..dcf6b9454978 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -407,13 +407,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); // For non-naked functions, set branch protection attributes on aarch64. - if let Some(BranchProtection { bti, pac_ret }) = + if let Some(BranchProtection { bti, pac_ret, gcs }) = cx.sess().opts.unstable_opts.branch_protection { assert!(cx.sess().target.arch == "aarch64"); if bti { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); } + if gcs { + to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack")); + } if let Some(PacRet { leaf, pc, key }) = pac_ret { if pc { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr")); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a8ea11a3a83..057f525c76f0 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -370,7 +370,8 @@ pub(crate) unsafe fn create_module<'ll>( ); } - if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { + if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.opts.unstable_opts.branch_protection + { if sess.target.arch == "aarch64" { llvm::add_module_flag_u32( llmod, @@ -403,6 +404,12 @@ pub(crate) unsafe fn create_module<'ll>( "sign-return-address-with-bkey", u32::from(pac_opts.key == PAuthKey::B), ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "guarded-control-stack", + gcs.into(), + ); } else { bug!( "branch-protection used on non-AArch64 target; \ diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7730bddc0f12..800f5efee41b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -772,7 +772,8 @@ fn test_unstable_options_tracking_hash() { branch_protection, Some(BranchProtection { bti: true, - pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }) + pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }), + gcs: true, }) ); tracked!(codegen_backend, Some("abc".to_string())); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 297df7c2c976..8d9f424f1fe3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1615,6 +1615,7 @@ pub struct PacRet { pub struct BranchProtection { pub bti: bool, pub pac_ret: Option, + pub gcs: bool, } pub(crate) const fn default_lib_output() -> CrateType { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69facde69368..7956a06f6a98 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -866,7 +866,7 @@ mod desc { pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`"; pub(crate) const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; - pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`"; + pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; pub(crate) const parse_remap_path_scope: &str = @@ -1903,6 +1903,7 @@ pub mod parse { Some(pac) => pac.pc = true, _ => return false, }, + "gcs" => slot.gcs = true, _ => return false, }; } diff --git a/src/doc/unstable-book/src/compiler-flags/branch-protection.md b/src/doc/unstable-book/src/compiler-flags/branch-protection.md index f0cc44a07f30..c15567dcac2e 100644 --- a/src/doc/unstable-book/src/compiler-flags/branch-protection.md +++ b/src/doc/unstable-book/src/compiler-flags/branch-protection.md @@ -13,6 +13,7 @@ It takes some combination of the following values, separated by a `,`. - `leaf` - Enable pointer authentication for all functions, including leaf functions. - `b-key` - Sign return addresses with key B, instead of the default key A. - `bti` - Enable branch target identification. +- `gcs` - Enable guarded control stack support. `leaf`, `b-key` and `pc` are only valid if `pac-ret` was previously specified. For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but From 987f9603f9907bdcea9911517f216554f3c5cd4d Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 17 Sep 2025 14:10:13 -0400 Subject: [PATCH 041/537] Sort safe intrinsic list --- .../rustc_hir_analysis/src/check/intrinsic.rs | 126 +++++++++--------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index aa2d27ab8094..5fd04427496d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -64,83 +64,87 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi // it's usually worth updating that intrinsic's documentation // to note that it's safe to call, since // safe extern fns are otherwise unprecedented. - sym::abort + + // tidy-alphabetical-start + | sym::abort + | sym::add_with_overflow + | sym::aggregate_raw_ptr + | sym::align_of | sym::assert_inhabited - | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid + | sym::assert_zero_valid + | sym::autodiff + | sym::bitreverse + | sym::black_box | sym::box_new | sym::breakpoint - | sym::size_of - | sym::align_of - | sym::needs_drop - | sym::caller_location - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - | sym::carrying_mul_add - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::saturating_add - | sym::saturating_sub - | sym::rotate_left - | sym::rotate_right - | sym::ctpop - | sym::ctlz - | sym::cttz | sym::bswap - | sym::bitreverse - | sym::three_way_compare - | sym::discriminant_value - | sym::type_id - | sym::type_id_eq - | sym::select_unpredictable + | sym::caller_location + | sym::carrying_mul_add | sym::cold_path - | sym::ptr_guaranteed_cmp - | sym::minnumf16 - | sym::minnumf32 - | sym::minnumf64 - | sym::minnumf128 - | sym::minimumf16 - | sym::minimumf32 - | sym::minimumf64 - | sym::minimumf128 - | sym::maxnumf16 - | sym::maxnumf32 - | sym::maxnumf64 - | sym::maxnumf128 + | sym::const_eval_select + | sym::contract_check_ensures + | sym::contract_check_requires + | sym::contract_checks + | sym::ctlz + | sym::ctpop + | sym::cttz + | sym::discriminant_value + | sym::fadd_algebraic + | sym::fdiv_algebraic + | sym::fmul_algebraic + | sym::forget + | sym::frem_algebraic + | sym::fsub_algebraic + | sym::is_val_statically_known | sym::maximumf16 | sym::maximumf32 | sym::maximumf64 | sym::maximumf128 - | sym::rustc_peek - | sym::type_name - | sym::forget - | sym::black_box - | sym::variant_count - | sym::is_val_statically_known + | sym::maxnumf16 + | sym::maxnumf32 + | sym::maxnumf64 + | sym::maxnumf128 + | sym::minimumf16 + | sym::minimumf32 + | sym::minimumf64 + | sym::minimumf128 + | sym::minnumf16 + | sym::minnumf32 + | sym::minnumf64 + | sym::minnumf128 + | sym::mul_with_overflow + | sym::needs_drop + | sym::prefetch_read_data + | sym::prefetch_read_instruction + | sym::prefetch_write_data + | sym::prefetch_write_instruction + | sym::ptr_guaranteed_cmp | sym::ptr_mask - | sym::aggregate_raw_ptr | sym::ptr_metadata - | sym::ub_checks - | sym::contract_checks - | sym::contract_check_requires - | sym::contract_check_ensures - | sym::fadd_algebraic - | sym::fsub_algebraic - | sym::fmul_algebraic - | sym::fdiv_algebraic - | sym::frem_algebraic + | sym::rotate_left + | sym::rotate_right | sym::round_ties_even_f16 | sym::round_ties_even_f32 | sym::round_ties_even_f64 | sym::round_ties_even_f128 - | sym::autodiff - | sym::prefetch_read_data - | sym::prefetch_write_data - | sym::prefetch_read_instruction - | sym::prefetch_write_instruction - | sym::const_eval_select => hir::Safety::Safe, + | sym::rustc_peek + | sym::saturating_add + | sym::saturating_sub + | sym::select_unpredictable + | sym::size_of + | sym::sub_with_overflow + | sym::three_way_compare + | sym::type_id + | sym::type_id_eq + | sym::type_name + | sym::ub_checks + | sym::variant_count + | sym::wrapping_add + | sym::wrapping_mul + | sym::wrapping_sub + // tidy-alphabetical-end + => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; From b216cf34b1d4dfce1a44f99f7c58e64724439a8e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 18 Sep 2025 00:46:27 +0000 Subject: [PATCH 042/537] Avoid invalidating from MirPatch::apply. --- compiler/rustc_mir_transform/src/patch.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index c781d1a5324b..f38881baf0f2 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -244,7 +244,7 @@ impl<'tcx> MirPatch<'tcx> { self.new_blocks.len(), body.basic_blocks.len() ); - let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() { + let bbs = if self.term_patch_map.iter().all(Option::is_none) && self.new_blocks.is_empty() { body.basic_blocks.as_mut_preserves_cfg() } else { body.basic_blocks.as_mut() @@ -273,8 +273,8 @@ impl<'tcx> MirPatch<'tcx> { } debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); loc.statement_index += delta; - let source_info = Self::source_info_for_index(&body[loc.block], loc); - body[loc.block] + let source_info = Self::source_info_for_index(&bbs[loc.block], loc); + bbs[loc.block] .statements .insert(loc.statement_index, Statement::new(source_info, stmt)); delta += 1; From 4919d5560120e8dfbf4f93924a2c3dc5d4ed446a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 18 Sep 2025 10:50:51 +0200 Subject: [PATCH 043/537] fix location for nested bodies in promoteds --- compiler/rustc_borrowck/src/type_check/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8c5447fe1e9e..e05c5b224858 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -505,6 +505,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let mut constraints = Default::default(); let mut liveness_constraints = LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); + let mut deferred_closure_requirements = Default::default(); // Don't try to add borrow_region facts for the promoted MIR as they refer // to the wrong locations. @@ -512,6 +513,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { mem::swap(this.polonius_facts, polonius_facts); mem::swap(&mut this.constraints.outlives_constraints, &mut constraints); mem::swap(&mut this.constraints.liveness_constraints, &mut liveness_constraints); + mem::swap(this.deferred_closure_requirements, &mut deferred_closure_requirements); }; swap_constraints(self); @@ -536,6 +538,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.constraints.outlives_constraints.push(constraint) } + + // If there are nested bodies in promoteds, we also need to update their + // location to something in the actually body, not the promoted. + // + // We don't update the constraint categories of the resulting constraints + // as returns in nested bodies are a proper return, even if that nested body + // is in a promoted. + for (closure_def_id, args, _locations) in deferred_closure_requirements { + self.deferred_closure_requirements.push((closure_def_id, args, locations)); + } + // If the region is live at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method From 3b2bbcd87ebdf9c1a62b1169667481cafe6d8d5d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 18 Sep 2025 10:57:13 +0200 Subject: [PATCH 044/537] internal constraints are better than placeholder outlives --- .../rustc_borrowck/src/region_infer/mod.rs | 7 ++-- .../hr-do-not-blame-outlives-static-ice.rs | 17 ++++++++++ ...hr-do-not-blame-outlives-static-ice.stderr | 34 +++++++++++++++++++ .../do-not-blame-outlives-static-ice.rs | 12 +++++++ .../do-not-blame-outlives-static-ice.stderr | 17 ++++++++++ 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs create mode 100644 tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr create mode 100644 tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs create mode 100644 tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f57456949bb5..bd017b213b64 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1726,9 +1726,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `BoringNoLocation` constraints can point to user-written code, but are less // specific, and are not used for relations that would make sense to blame. ConstraintCategory::BoringNoLocation => 6, - // Do not blame internal constraints. - ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 7, - ConstraintCategory::Internal => 8, + // Do not blame internal constraints if we can avoid it. Never blame + // the `'region: 'static` constraints introduced by placeholder outlives. + ConstraintCategory::Internal => 7, + ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 8, }; debug!("constraint {constraint:?} category: {category:?}, interest: {interest:?}"); diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs new file mode 100644 index 000000000000..e5c1f47b9e02 --- /dev/null +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Zdeduplicate-diagnostics=yes + +// Regression test for #146467. +#![feature(inherent_associated_types)] +//~^ WARN the feature `inherent_associated_types` is incomplete + +struct Foo(T); + +impl<'a> Foo { + //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait + type Assoc = &'a (); +} + +fn foo(_: for<'a> fn(Foo::Assoc)) {} +//~^ ERROR mismatched types +//~| ERROR higher-ranked subtype error +fn main() {} diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr new file mode 100644 index 000000000000..4c0726d4ddca --- /dev/null +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr @@ -0,0 +1,34 @@ +warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:4:12 + | +LL | #![feature(inherent_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #8995 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:9:6 + | +LL | impl<'a> Foo { + | ^^ unconstrained lifetime parameter + +error[E0308]: mismatched types + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:11 + | +LL | fn foo(_: for<'a> fn(Foo::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected struct `Foo fn(&'a ())>` + found struct `Foo fn(&'a ())>` + +error: higher-ranked subtype error + --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:1 + | +LL | fn foo(_: for<'a> fn(Foo::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0308. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs new file mode 100644 index 000000000000..dfdb816652c4 --- /dev/null +++ b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Zdeduplicate-diagnostics=yes + +// Regression test for #146467. +trait Trait { type Assoc; } + +impl Trait for fn(&()) { type Assoc = (); } + +fn f(_: for<'a> fn(::Assoc)) {} +//~^ ERROR implementation of `Trait` is not general enough +//~| ERROR higher-ranked subtype error + +fn main() {} diff --git a/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr new file mode 100644 index 000000000000..c75a063e45fa --- /dev/null +++ b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr @@ -0,0 +1,17 @@ +error: implementation of `Trait` is not general enough + --> $DIR/do-not-blame-outlives-static-ice.rs:8:9 + | +LL | fn f(_: for<'a> fn(::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `for<'a> fn(&'a ())` must implement `Trait`, for any lifetime `'0`... + = note: ...but `Trait` is actually implemented for the type `for<'a> fn(&'a ())` + +error: higher-ranked subtype error + --> $DIR/do-not-blame-outlives-static-ice.rs:8:1 + | +LL | fn f(_: for<'a> fn(::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 1a56d279b8dee896dd46552806686fac513336a7 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 18 Sep 2025 20:00:31 +0800 Subject: [PATCH 045/537] Fix applicable after l_curly for replace_is_method_with_if_let_method --- .../replace_is_method_with_if_let_method.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index 5ef8ba46b9e5..f507cae1bb0d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -31,6 +31,9 @@ pub(crate) fn replace_is_method_with_if_let_method( ast::Expr::MethodCallExpr(call) => call, _ => return None, }; + if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() { + return None; + } let name_ref = call_expr.name_ref()?; match name_ref.text().as_str() { @@ -188,6 +191,21 @@ fn main() { let x = Ok(1); if x.is_e$0rr() {} } +"#, + ); + } + + #[test] + fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() { + check_assist_not_applicable( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + if x.is_some() { + ()$0 + } +} "#, ); } From 389907a17e5c1eecd9fe41a53ca145f42dcd1488 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 15 Sep 2025 09:42:14 -0400 Subject: [PATCH 046/537] Enforce E0719 only for trait aliases --- .../src/error_codes/E0719.md | 14 +- .../src/hir_ty_lowering/bounds.rs | 27 +- .../src/hir_ty_lowering/dyn_trait.rs | 6 +- .../src/hir_ty_lowering/mod.rs | 3 +- .../duplicate-bound-err.rs | 114 +++ .../duplicate-bound-err.stderr | 268 +++++++ .../associated-type-bounds/duplicate-bound.rs | 240 ++++++ tests/ui/associated-type-bounds/duplicate.rs | 278 ------- .../associated-type-bounds/duplicate.stderr | 751 ------------------ ...sociated-types-overridden-binding-2.stderr | 2 +- ...associated-types-overridden-binding.stderr | 2 +- tests/ui/error-codes/E0719.rs | 5 - tests/ui/error-codes/E0719.stderr | 34 +- 13 files changed, 650 insertions(+), 1094 deletions(-) create mode 100644 tests/ui/associated-type-bounds/duplicate-bound-err.rs create mode 100644 tests/ui/associated-type-bounds/duplicate-bound-err.stderr create mode 100644 tests/ui/associated-type-bounds/duplicate-bound.rs delete mode 100644 tests/ui/associated-type-bounds/duplicate.rs delete mode 100644 tests/ui/associated-type-bounds/duplicate.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md index cd981db1058a..17cbd2de49ef 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0719.md +++ b/compiler/rustc_error_codes/src/error_codes/E0719.md @@ -1,4 +1,4 @@ -An associated type value was specified more than once. +An associated item value was specified more than once in a trait object. Erroneous code example: @@ -7,21 +7,15 @@ trait FooTrait {} trait BarTrait {} // error: associated type `Item` in trait `Iterator` is specified twice -struct Foo> { f: T } +type Foo = dyn Iterator; ``` -`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`. -To fix this, create a new trait that is a combination of the desired traits and -specify the associated type with the new trait. +To fix this, remove the duplicate specifier: Corrected example: ``` -trait FooTrait {} -trait BarTrait {} -trait FooBarTrait: FooTrait + BarTrait {} - -struct Foo> { f: T } // ok! +type Foo = dyn Iterator; // ok! ``` For more information about associated types, see [the book][bk-at]. For more diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 99dc8e6e5221..a8d75ba223ab 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -362,6 +362,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { param_ty, bounds, predicate_filter, + false, ); } hir::GenericBound::Outlives(lifetime) => { @@ -402,7 +403,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref: ty::PolyTraitRef<'tcx>, constraint: &hir::AssocItemConstraint<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - duplicates: &mut FxIndexMap, + duplicates: Option<&mut FxIndexMap>, path_span: Span, predicate_filter: PredicateFilter, ) -> Result<(), ErrorGuaranteed> { @@ -458,17 +459,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .expect("failed to find associated item"); - duplicates - .entry(assoc_item.def_id) - .and_modify(|prev_span| { - self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { - span: constraint.span, - prev_span: *prev_span, - item_name: constraint.ident, - def_path: tcx.def_path_str(assoc_item.container_id(tcx)), - }); - }) - .or_insert(constraint.span); + if let Some(duplicates) = duplicates { + duplicates + .entry(assoc_item.def_id) + .and_modify(|prev_span| { + self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { + span: constraint.span, + prev_span: *prev_span, + item_name: constraint.ident, + def_path: tcx.def_path_str(assoc_item.container_id(tcx)), + }); + }) + .or_insert(constraint.span); + } let projection_term = if let ty::AssocTag::Fn = assoc_tag { let bound_vars = tcx.late_bound_vars(constraint.hir_id); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c248cd7fec2e..a4179776572d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -60,6 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, + true, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { potential_assoc_types.extend(invalid_args); @@ -157,10 +158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx() .struct_span_err( span, - format!( - "conflicting associated type bounds for `{item}` when \ - expanding trait alias" - ), + format!("conflicting associated type bounds for `{item}`"), ) .with_span_label( old_proj_span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 9b198d044542..0ff1fabd7b30 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -752,6 +752,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, + for_dyn: bool, ) -> GenericArgCountResult { let tcx = self.tcx(); @@ -927,7 +928,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { poly_trait_ref, constraint, bounds, - &mut dup_constraints, + for_dyn.then_some(&mut dup_constraints), constraint.span, predicate_filter, ); diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs new file mode 100644 index 000000000000..50db5de7ca76 --- /dev/null +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -0,0 +1,114 @@ +//@ edition: 2024 + +#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)] +#![allow(refining_impl_trait_internal)] + +use std::iter; + +fn frpit1() -> impl Iterator { + iter::empty() + //~^ ERROR type annotations needed +} +fn frpit2() -> impl Iterator { + iter::empty() + //~^ ERROR type annotations needed +} +fn frpit3() -> impl Iterator { + iter::empty() + //~^ ERROR type annotations needed +} + +type ETAI1> = impl Copy; +//~^ ERROR unconstrained opaque type +type ETAI2> = impl Copy; +//~^ ERROR unconstrained opaque type +type ETAI3> = impl Copy; +//~^ ERROR unconstrained opaque type + +type ETAI4 = impl Iterator; +//~^ ERROR unconstrained opaque type +type ETAI5 = impl Iterator; +//~^ ERROR unconstrained opaque type +type ETAI6 = impl Iterator; +//~^ ERROR unconstrained opaque type + +fn mismatch() -> impl Iterator { + //~^ ERROR [E0277] + iter::empty::<*const ()>() +} + +fn mismatch_2() -> impl Iterator { + //~^ ERROR [E0277] + iter::empty::() +} + +trait Trait { + type Gat; + + const ASSOC: i32; + + fn foo() -> impl Sized; +} + +impl Trait for () { + type Gat = (); + + const ASSOC: i32 = 3; + + fn foo() {} +} + +impl Trait for u32 { + type Gat = (); + + const ASSOC: i32 = 4; + + fn foo() -> u32 { + 42 + } +} + +fn uncallable(_: impl Iterator) {} + +fn uncallable_const(_: impl Trait) {} + +fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + +type MustFail = dyn Iterator; +//~^ ERROR [E0719] +//~| ERROR conflicting associated type bounds + +trait Trait2 { + const ASSOC: u32; +} + +type MustFail2 = dyn Trait2; +//~^ ERROR [E0719] +//~| ERROR conflicting associated type bounds + +type MustFail3 = dyn Iterator; +//~^ ERROR [E0719] + +type MustFail4 = dyn Trait2; +//~^ ERROR [E0719] + +trait Trait3 { + fn foo() -> impl Iterator; +} + +impl Trait3 for () { + fn foo() -> impl Iterator { + //~^ ERROR[E0271] + //~| ERROR[E0271] + [2u32].into_iter() + } +} + +fn main() { + uncallable(iter::empty::()); //~ ERROR [E0271] + uncallable(iter::empty::()); //~ ERROR [E0271] + uncallable_const(()); //~ ERROR [E0271] + uncallable_const(4u32); //~ ERROR [E0271] + uncallable_rtn(()); //~ ERROR [E0271] + uncallable_rtn(17u32); //~ ERROR [E0271] +} diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr new file mode 100644 index 000000000000..6c1dc03676c7 --- /dev/null +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -0,0 +1,268 @@ +error[E0282]: type annotations needed + --> $DIR/duplicate-bound-err.rs:9:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate-bound-err.rs:13:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate-bound-err.rs:17:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:21:51 + | +LL | type ETAI1> = impl Copy; + | ^^^^^^^^^ + | + = note: `ETAI1` must be used in combination with a concrete type within the same crate + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:23:51 + | +LL | type ETAI2> = impl Copy; + | ^^^^^^^^^ + | + = note: `ETAI2` must be used in combination with a concrete type within the same crate + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:25:57 + | +LL | type ETAI3> = impl Copy; + | ^^^^^^^^^ + | + = note: `ETAI3` must be used in combination with a concrete type within the same crate + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:28:14 + | +LL | type ETAI4 = impl Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `ETAI4` must be used in combination with a concrete type within the same crate + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:30:14 + | +LL | type ETAI5 = impl Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `ETAI5` must be used in combination with a concrete type within the same crate + +error: unconstrained opaque type + --> $DIR/duplicate-bound-err.rs:32:14 + | +LL | type ETAI6 = impl Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `ETAI6` must be used in combination with a concrete type within the same crate + +error[E0277]: `*const ()` cannot be sent between threads safely + --> $DIR/duplicate-bound-err.rs:35:18 + | +LL | fn mismatch() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely +LL | +LL | iter::empty::<*const ()>() + | -------------------------- return type was inferred to be `std::iter::Empty<*const ()>` here + | + = help: the trait `Send` is not implemented for `*const ()` + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/duplicate-bound-err.rs:40:20 + | +LL | fn mismatch_2() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` +LL | +LL | iter::empty::() + | ----------------------- return type was inferred to be `std::iter::Empty` here + +error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` + --> $DIR/duplicate-bound-err.rs:100:17 + | +LL | fn foo() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` +... +LL | [2u32].into_iter() + | ------------------ return type was inferred to be `std::array::IntoIter` here + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate-bound-err.rs:77:42 + | +LL | type MustFail = dyn Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error: conflicting associated type bounds for `Item` + --> $DIR/duplicate-bound-err.rs:77:17 + | +LL | type MustFail = dyn Iterator; + | ^^^^^^^^^^^^^----------^^----------^ + | | | + | | `Item` is specified to be `u32` here + | `Item` is specified to be `i32` here + +error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified + --> $DIR/duplicate-bound-err.rs:85:43 + | +LL | type MustFail2 = dyn Trait2; + | ------------ ^^^^^^^^^^^^ re-bound here + | | + | `ASSOC` bound here first + +error: conflicting associated type bounds for `ASSOC` + --> $DIR/duplicate-bound-err.rs:85:18 + | +LL | type MustFail2 = dyn Trait2; + | ^^^^^^^^^^^------------^^------------^ + | | | + | | `ASSOC` is specified to be `4` here + | `ASSOC` is specified to be `3` here + +error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified + --> $DIR/duplicate-bound-err.rs:89:43 + | +LL | type MustFail3 = dyn Iterator; + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified + --> $DIR/duplicate-bound-err.rs:92:43 + | +LL | type MustFail4 = dyn Trait2; + | ------------ ^^^^^^^^^^^^ re-bound here + | | + | `ASSOC` bound here first + +error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` + --> $DIR/duplicate-bound-err.rs:100:17 + | +LL | fn foo() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` + | +note: required by a bound in `Trait3::foo::{anon_assoc#0}` + --> $DIR/duplicate-bound-err.rs:96:31 + | +LL | fn foo() -> impl Iterator; + | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` + +error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` + --> $DIR/duplicate-bound-err.rs:108:16 + | +LL | uncallable(iter::empty::()); + | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` + | | + | required by a bound introduced by this call + | +note: required by a bound in `uncallable` + --> $DIR/duplicate-bound-err.rs:71:32 + | +LL | fn uncallable(_: impl Iterator) {} + | ^^^^^^^^^^ required by this bound in `uncallable` + +error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` + --> $DIR/duplicate-bound-err.rs:109:16 + | +LL | uncallable(iter::empty::()); + | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` + | | + | required by a bound introduced by this call + | +note: required by a bound in `uncallable` + --> $DIR/duplicate-bound-err.rs:71:44 + | +LL | fn uncallable(_: impl Iterator) {} + | ^^^^^^^^^^ required by this bound in `uncallable` + +error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` + --> $DIR/duplicate-bound-err.rs:110:22 + | +LL | uncallable_const(()); + | ---------------- ^^ expected `4`, found `3` + | | + | required by a bound introduced by this call + | + = note: expected constant `4` + found constant `3` +note: required by a bound in `uncallable_const` + --> $DIR/duplicate-bound-err.rs:73:46 + | +LL | fn uncallable_const(_: impl Trait) {} + | ^^^^^^^^^ required by this bound in `uncallable_const` + +error[E0271]: type mismatch resolving `::ASSOC == 3` + --> $DIR/duplicate-bound-err.rs:111:22 + | +LL | uncallable_const(4u32); + | ---------------- ^^^^ expected `3`, found `4` + | | + | required by a bound introduced by this call + | + = note: expected constant `3` + found constant `4` +note: required by a bound in `uncallable_const` + --> $DIR/duplicate-bound-err.rs:73:35 + | +LL | fn uncallable_const(_: impl Trait) {} + | ^^^^^^^^^ required by this bound in `uncallable_const` + +error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` + --> $DIR/duplicate-bound-err.rs:112:20 + | +LL | uncallable_rtn(()); + | -------------- ^^ expected `4`, found `3` + | | + | required by a bound introduced by this call + | + = note: expected constant `4` + found constant `3` +note: required by a bound in `uncallable_rtn` + --> $DIR/duplicate-bound-err.rs:75:75 + | +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` + +error[E0271]: type mismatch resolving `::ASSOC == 3` + --> $DIR/duplicate-bound-err.rs:113:20 + | +LL | uncallable_rtn(17u32); + | -------------- ^^^^^ expected `3`, found `4` + | | + | required by a bound introduced by this call + | + = note: expected constant `3` + found constant `4` +note: required by a bound in `uncallable_rtn` + --> $DIR/duplicate-bound-err.rs:75:48 + | +LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + | ^^^^^^^^^ required by this bound in `uncallable_rtn` + +error: aborting due to 25 previous errors + +Some errors have detailed explanations: E0271, E0277, E0282, E0719. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs new file mode 100644 index 000000000000..97b2b3905a55 --- /dev/null +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -0,0 +1,240 @@ +//@ edition: 2024 +//@ run-pass + +#![feature(associated_const_equality, return_type_notation)] +#![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)] + +use std::iter; +use std::mem::ManuallyDrop; + +struct SI1> { + f: T, +} +struct SI2> { + f: T, +} +struct SI3> { + f: T, +} +struct SW1 +where + T: Iterator, +{ + f: T, +} +struct SW2 +where + T: Iterator, +{ + f: T, +} +struct SW3 +where + T: Iterator, +{ + f: T, +} + +enum EI1> { + V(T), +} +enum EI2> { + V(T), +} +enum EI3> { + V(T), +} +enum EW1 +where + T: Iterator, +{ + V(T), +} +enum EW2 +where + T: Iterator, +{ + V(T), +} +enum EW3 +where + T: Iterator, +{ + V(T), +} + +union UI1> { + f: ManuallyDrop, +} +union UI2> { + f: ManuallyDrop, +} +union UI3> { + f: ManuallyDrop, +} +union UW1 +where + T: Iterator, +{ + f: ManuallyDrop, +} +union UW2 +where + T: Iterator, +{ + f: ManuallyDrop, +} +union UW3 +where + T: Iterator, +{ + f: ManuallyDrop, +} + +fn fi1>() {} +fn fi2>() {} +fn fi3>() {} +fn fw1() +where + T: Iterator, +{ +} +fn fw2() +where + T: Iterator, +{ +} +fn fw3() +where + T: Iterator, +{ +} + +fn frpit1() -> impl Iterator { + iter::empty::() +} +fn frpit2() -> impl Iterator { + iter::empty::() +} +fn frpit3() -> impl Iterator { + iter::empty::() +} +fn fapit1(_: impl Iterator) {} +fn fapit2(_: impl Iterator) {} +fn fapit3(_: impl Iterator) {} + +type TAI1> = T; +type TAI2> = T; +type TAI3> = T; +type TAW1 +where + T: Iterator, += T; +type TAW2 +where + T: Iterator, += T; +type TAW3 +where + T: Iterator, += T; + +trait TRI1> {} +trait TRI2> {} +trait TRI3> {} +trait TRS1: Iterator {} +trait TRS2: Iterator {} +trait TRS3: Iterator {} +trait TRW1 +where + T: Iterator, +{ +} +trait TRW2 +where + T: Iterator, +{ +} +trait TRW3 +where + T: Iterator, +{ +} +trait TRSW1 +where + Self: Iterator, +{ +} +trait TRSW2 +where + Self: Iterator, +{ +} +trait TRSW3 +where + Self: Iterator, +{ +} +trait TRA1 { + type A: Iterator; +} +trait TRA2 { + type A: Iterator; +} +trait TRA3 { + type A: Iterator; +} + +trait Trait { + type Gat; + + const ASSOC: i32; + + fn foo() -> impl Sized; +} + +impl Trait for () { + type Gat = (); + + const ASSOC: i32 = 3; + + fn foo() {} +} + +trait Subtrait: Trait = u32, Gat = u64> {} + +fn f = (), Gat = ()>>() { + let _: T::Gat = (); + let _: T::Gat = (); +} + +fn g = (), Gat = &'static str>>() { + let _: T::Gat = (); + let _: T::Gat = ""; +} + +fn uncallable(_: impl Iterator) {} + +fn callable(_: impl Iterator) {} + +fn uncallable_const(_: impl Trait) {} + +fn callable_const(_: impl Trait) {} + +fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} + +fn callable_rtn(_: impl Trait) {} + +trait Trait2 { + const ASSOC: u32; +} + +trait Trait3 { + fn foo() -> impl Iterator; +} + +fn main() { + callable(iter::empty::()); + callable_const(()); + callable_rtn(()); +} diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs deleted file mode 100644 index e9d94787e982..000000000000 --- a/tests/ui/associated-type-bounds/duplicate.rs +++ /dev/null @@ -1,278 +0,0 @@ -#![feature(type_alias_impl_trait)] - -use std::iter; -use std::mem::ManuallyDrop; - -struct SI1> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: T, -} -struct SI2> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: T, -} -struct SI3> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: T, -} -struct SW1 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: T, -} -struct SW2 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: T, -} -struct SW3 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: T, -} - -enum EI1> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - V(T), -} -enum EI2> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - V(T), -} -enum EI3> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - V(T), -} -enum EW1 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - V(T), -} -enum EW2 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - V(T), -} -enum EW3 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - V(T), -} - -union UI1> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: ManuallyDrop, -} -union UI2> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: ManuallyDrop, -} -union UI3> { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - f: ManuallyDrop, -} -union UW1 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: ManuallyDrop, -} -union UW2 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: ManuallyDrop, -} -union UW3 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ - f: ManuallyDrop, -} - -fn FI1>() {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -fn FI2>() {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -fn FI3>() {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -fn FW1() -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -fn FW2() -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -fn FW3() -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} - -fn FRPIT1() -> impl Iterator { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - iter::empty() - //~^ ERROR type annotations needed -} -fn FRPIT2() -> impl Iterator { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - iter::empty() - //~^ ERROR type annotations needed -} -fn FRPIT3() -> impl Iterator { - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - iter::empty() - //~^ ERROR type annotations needed -} -fn FAPIT1(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -fn FAPIT2(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -fn FAPIT3(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - -type TAI1> = T; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -type TAI2> = T; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -type TAI3> = T; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -type TAW1 -where - T: Iterator, -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -= T; -type TAW2 -where - T: Iterator, -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -= T; -type TAW3 -where - T: Iterator, -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -= T; - -type ETAI1> = impl Copy; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type -type ETAI2> = impl Copy; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type -type ETAI3> = impl Copy; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type -type ETAI4 = impl Iterator; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type -type ETAI5 = impl Iterator; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type -type ETAI6 = impl Iterator; -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR unconstrained opaque type - -trait TRI1> {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRI2> {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRI3> {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRS1: Iterator {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRS2: Iterator {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRS3: Iterator {} -//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -trait TRW1 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRW2 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRW3 -where - T: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRSW1 -where - Self: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRSW2 -where - Self: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRSW3 -where - Self: Iterator, - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -{ -} -trait TRA1 { - type A: Iterator; - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -} -trait TRA2 { - type A: Iterator; - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -} -trait TRA3 { - type A: Iterator; - //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] -} - -fn main() {} diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr deleted file mode 100644 index 68fbb345f6f9..000000000000 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ /dev/null @@ -1,751 +0,0 @@ -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:6:36 - | -LL | struct SI1> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:10:36 - | -LL | struct SI2> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:14:39 - | -LL | struct SI3> { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:20:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:27:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:34:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:40:34 - | -LL | enum EI1> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:44:34 - | -LL | enum EI2> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:48:37 - | -LL | enum EI3> { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:54:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:61:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:68:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:74:35 - | -LL | union UI1> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:78:35 - | -LL | union UI2> { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:82:38 - | -LL | union UI3> { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:88:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:95:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:102:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:108:32 - | -LL | fn FI1>() {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:110:32 - | -LL | fn FI2>() {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:112:35 - | -LL | fn FI3>() {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:116:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:122:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:128:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:133:42 - | -LL | fn FRPIT1() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:139:42 - | -LL | fn FRPIT2() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:145:45 - | -LL | fn FRPIT3() -> impl Iterator { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:151:40 - | -LL | fn FAPIT1(_: impl Iterator) {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:153:40 - | -LL | fn FAPIT2(_: impl Iterator) {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:155:43 - | -LL | fn FAPIT3(_: impl Iterator) {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:158:35 - | -LL | type TAI1> = T; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:160:35 - | -LL | type TAI2> = T; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:162:38 - | -LL | type TAI3> = T; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:166:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:171:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:176:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:180:36 - | -LL | type ETAI1> = impl Copy; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:183:36 - | -LL | type ETAI2> = impl Copy; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:186:39 - | -LL | type ETAI3> = impl Copy; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:202:36 - | -LL | trait TRI1> {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:204:36 - | -LL | trait TRI2> {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:206:39 - | -LL | trait TRI3> {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:208:34 - | -LL | trait TRS1: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:208:34 - | -LL | trait TRS1: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:208:34 - | -LL | trait TRS1: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:212:34 - | -LL | trait TRS2: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:212:34 - | -LL | trait TRS2: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:212:34 - | -LL | trait TRS2: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:216:37 - | -LL | trait TRS3: Iterator {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:216:37 - | -LL | trait TRS3: Iterator {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:216:37 - | -LL | trait TRS3: Iterator {} - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:222:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:228:29 - | -LL | T: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:234:32 - | -LL | T: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:240:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:240:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:240:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:248:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:248:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:248:32 - | -LL | Self: Iterator, - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:256:35 - | -LL | Self: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:256:35 - | -LL | Self: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:256:35 - | -LL | Self: Iterator, - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:263:34 - | -LL | type A: Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:263:34 - | -LL | type A: Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:268:34 - | -LL | type A: Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:268:34 - | -LL | type A: Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:273:37 - | -LL | type A: Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:273:37 - | -LL | type A: Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:133:42 - | -LL | fn FRPIT1() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:136:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:139:42 - | -LL | fn FRPIT2() -> impl Iterator { - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:142:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:145:45 - | -LL | fn FRPIT3() -> impl Iterator { - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:148:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - -error: unconstrained opaque type - --> $DIR/duplicate.rs:180:51 - | -LL | type ETAI1> = impl Copy; - | ^^^^^^^^^ - | - = note: `ETAI1` must be used in combination with a concrete type within the same crate - -error: unconstrained opaque type - --> $DIR/duplicate.rs:183:51 - | -LL | type ETAI2> = impl Copy; - | ^^^^^^^^^ - | - = note: `ETAI2` must be used in combination with a concrete type within the same crate - -error: unconstrained opaque type - --> $DIR/duplicate.rs:186:57 - | -LL | type ETAI3> = impl Copy; - | ^^^^^^^^^ - | - = note: `ETAI3` must be used in combination with a concrete type within the same crate - -error: unconstrained opaque type - --> $DIR/duplicate.rs:189:14 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `ETAI4` must be used in combination with a concrete type within the same crate - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:189:40 - | -LL | type ETAI4 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:189:40 - | -LL | type ETAI4 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: unconstrained opaque type - --> $DIR/duplicate.rs:193:14 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `ETAI5` must be used in combination with a concrete type within the same crate - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:193:40 - | -LL | type ETAI5 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:193:40 - | -LL | type ETAI5 = impl Iterator; - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: unconstrained opaque type - --> $DIR/duplicate.rs:197:14 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `ETAI6` must be used in combination with a concrete type within the same crate - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:43 - | -LL | type ETAI6 = impl Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:197:43 - | -LL | type ETAI6 = impl Iterator; - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 87 previous errors - -Some errors have detailed explanations: E0282, E0719. -For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr index 71a4a2610aac..e96a2446b6ce 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,4 +1,4 @@ -error: conflicting associated type bounds for `Item` when expanding trait alias +error: conflicting associated type bounds for `Item` --> $DIR/associated-types-overridden-binding-2.rs:6:13 | LL | trait I32Iterator = Iterator; diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr index 3b20015dfcab..08ab9b63ee9f 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr @@ -22,7 +22,7 @@ note: required by a bound in `I32Iterator` LL | trait I32Iterator = Iterator; | ^^^^^^^^^^ required by this bound in `I32Iterator` -error: conflicting associated type bounds for `Item` when expanding trait alias +error: conflicting associated type bounds for `Item` --> $DIR/associated-types-overridden-binding.rs:10:13 | LL | trait I32Iterator = Iterator; diff --git a/tests/ui/error-codes/E0719.rs b/tests/ui/error-codes/E0719.rs index 0ea6d19000bd..d7b4b876d1b7 100644 --- a/tests/ui/error-codes/E0719.rs +++ b/tests/ui/error-codes/E0719.rs @@ -1,8 +1,3 @@ -trait Foo: Iterator {} -//~^ ERROR is already specified -//~| ERROR is already specified -//~| ERROR is already specified - type Unit = (); fn test() -> Box> { diff --git a/tests/ui/error-codes/E0719.stderr b/tests/ui/error-codes/E0719.stderr index 7e8329db1f48..f48175689249 100644 --- a/tests/ui/error-codes/E0719.stderr +++ b/tests/ui/error-codes/E0719.stderr @@ -1,33 +1,5 @@ error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:1:33 - | -LL | trait Foo: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:1:33 - | -LL | trait Foo: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:1:33 - | -LL | trait Foo: Iterator {} - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:8:42 + --> $DIR/E0719.rs:3:42 | LL | fn test() -> Box> { | --------- ^^^^^^^^^^^ re-bound here @@ -35,13 +7,13 @@ LL | fn test() -> Box> { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/E0719.rs:14:38 + --> $DIR/E0719.rs:9:38 | LL | let _: &dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0719`. From e1258e79d6cb709b26ded97d32de6c55f355e2aa Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Sat, 23 Aug 2025 20:17:32 +0000 Subject: [PATCH 047/537] autodiff: Add basic TypeTree with NoTT flag Signed-off-by: Karan Janthe --- .../rustc_ast/src/expand/autodiff_attrs.rs | 17 +++- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 + compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_middle/src/error.rs | 1 - compiler/rustc_middle/src/ty/mod.rs | 80 +++++++++++++++++++ compiler/rustc_session/src/config.rs | 2 + compiler/rustc_session/src/options.rs | 3 +- tests/codegen-llvm/autodiff/typetree.rs | 33 ++++++++ .../autodiff/type-trees/nott-flag/nott.check | 3 + .../autodiff/type-trees/nott-flag/rmake.rs | 38 +++++++++ .../autodiff/type-trees/nott-flag/test.rs | 15 ++++ .../type-trees/nott-flag/with_tt.check | 3 + tests/ui/autodiff/flag_nott.rs | 19 +++++ 13 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 tests/codegen-llvm/autodiff/typetree.rs create mode 100644 tests/run-make/autodiff/type-trees/nott-flag/nott.check create mode 100644 tests/run-make/autodiff/type-trees/nott-flag/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/nott-flag/test.rs create mode 100644 tests/run-make/autodiff/type-trees/nott-flag/with_tt.check create mode 100644 tests/ui/autodiff/flag_nott.rs diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index 33451f997483..90f15753e99c 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -6,6 +6,7 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; +use crate::expand::typetree::TypeTree; use crate::expand::{Decodable, Encodable, HashStable_Generic}; use crate::{Ty, TyKind}; @@ -84,6 +85,8 @@ pub struct AutoDiffItem { /// The name of the function being generated pub target: String, pub attrs: AutoDiffAttrs, + pub inputs: Vec, + pub output: TypeTree, } #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -275,14 +278,22 @@ impl AutoDiffAttrs { !matches!(self.mode, DiffMode::Error | DiffMode::Source) } - pub fn into_item(self, source: String, target: String) -> AutoDiffItem { - AutoDiffItem { source, target, attrs: self } + pub fn into_item( + self, + source: String, + target: String, + inputs: Vec, + output: TypeTree, + ) -> AutoDiffItem { + AutoDiffItem { source, target, inputs, output, attrs: self } } } impl fmt::Display for AutoDiffItem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Differentiating {} -> {}", self.source, self.target)?; - write!(f, " with attributes: {:?}", self.attrs) + write!(f, " with attributes: {:?}", self.attrs)?; + write!(f, " with inputs: {:?}", self.inputs)?; + write!(f, " with output: {:?}", self.output) } } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 78107d95e5a7..5ac3a87c158e 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -563,6 +563,8 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { config::AutoDiff::Enable => {} // We handle this below config::AutoDiff::NoPostopt => {} + // Disables TypeTree generation + config::AutoDiff::NoTT => {} } } // This helps with handling enums for now. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7730bddc0f12..837acdadd579 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -766,6 +766,7 @@ fn test_unstable_options_tracking_hash() { tracked!(always_encode_mir, true); tracked!(assume_incomplete_release, true); tracked!(autodiff, vec![AutoDiff::Enable]); + tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); tracked!( diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index e3e1393b5f9a..ef014af7beb1 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -37,7 +37,6 @@ pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> { pub sub: TypeMismatchReason, } -// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_unsupported_union)] pub struct UnsupportedUnion { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0ffef393a33b..df42c4003175 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; @@ -2216,3 +2217,82 @@ pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [ty::Const<'tcx>], } + +/// Generate TypeTree information for autodiff. +/// This function creates TypeTree metadata that describes the memory layout +/// of function parameters and return types for Enzyme autodiff. +pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { + // Check if TypeTrees are disabled via NoTT flag + if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { + return FncTree { args: vec![], ret: TypeTree::new() }; + } + + // Check if this is actually a function type + if !fn_ty.is_fn() { + return FncTree { args: vec![], ret: TypeTree::new() }; + } + + // Get the function signature + let fn_sig = fn_ty.fn_sig(tcx); + let sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + + // Create TypeTrees for each input parameter + let mut args = vec![]; + for ty in sig.inputs().iter() { + let type_tree = typetree_from_ty(tcx, *ty); + args.push(type_tree); + } + + // Create TypeTree for return type + let ret = typetree_from_ty(tcx, sig.output()); + + FncTree { args, ret } +} + +/// Generate TypeTree for a specific type. +/// This function analyzes a Rust type and creates appropriate TypeTree metadata. +fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { + // Handle basic scalar types + if ty.is_scalar() { + let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { + (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) + } else if ty.is_floating_point() { + match ty { + x if x == tcx.types.f32 => (Kind::Float, 4), + x if x == tcx.types.f64 => (Kind::Double, 8), + _ => return TypeTree::new(), // Unknown float type + } + } else { + // TODO(KMJ-007): Handle other scalar types if needed + return TypeTree::new(); + }; + + return TypeTree(vec![Type { + offset: -1, + size, + kind, + child: TypeTree::new() + }]); + } + + // Handle references and pointers + if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { + let inner_ty = if let Some(inner) = ty.builtin_deref(true) { + inner + } else { + // TODO(KMJ-007): Handle complex pointer types + return TypeTree::new(); + }; + + let child = typetree_from_ty(tcx, inner_ty); + return TypeTree(vec![Type { + offset: -1, + size: 8, // TODO(KMJ-007): Get actual pointer size from target + kind: Kind::Pointer, + child, + }]); + } + + // TODO(KMJ-007): Handle arrays, slices, structs, and other complex types + TypeTree::new() +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 297df7c2c976..3a035fcf9e89 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -257,6 +257,8 @@ pub enum AutoDiff { LooseTypes, /// Runs Enzyme's aggressive inlining Inline, + /// Disable Type Tree + NoTT, } /// Settings for `-Z instrument-xray` flag. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69facde69368..ee53dd39bc88 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -792,7 +792,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`, `NoTT`"; pub(crate) const parse_offload: &str = "a comma separated list of settings: `Enable`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; @@ -1479,6 +1479,7 @@ pub mod parse { "PrintPasses" => AutoDiff::PrintPasses, "LooseTypes" => AutoDiff::LooseTypes, "Inline" => AutoDiff::Inline, + "NoTT" => AutoDiff::NoTT, _ => { // FIXME(ZuseZ4): print an error saying which value is not recognized return false; diff --git a/tests/codegen-llvm/autodiff/typetree.rs b/tests/codegen-llvm/autodiff/typetree.rs new file mode 100644 index 000000000000..3ad38d581b9a --- /dev/null +++ b/tests/codegen-llvm/autodiff/typetree.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// Test that basic autodiff still works with our TypeTree infrastructure +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_simple, Duplicated, Active)] +#[no_mangle] +#[inline(never)] +fn simple(x: &f64) -> f64 { + 2.0 * x +} + +// CHECK-LABEL: @simple +// CHECK: fmul double + +// The derivative function should be generated normally +// CHECK-LABEL: diffesimple +// CHECK: fadd fast double + +fn main() { + let x = std::hint::black_box(3.0); + let output = simple(&x); + assert_eq!(6.0, output); + + let mut df_dx = 0.0; + let output_ = d_simple(&x, &mut df_dx, 1.0); + assert_eq!(output, output_); + assert_eq!(2.0, df_dx); +} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/nott.check b/tests/run-make/autodiff/type-trees/nott-flag/nott.check new file mode 100644 index 000000000000..56ef2f0bdf38 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/nott-flag/nott.check @@ -0,0 +1,3 @@ +// TODO(KMJ-007): Update this test when TypeTree integration is complete +// CHECK: square - {[-1]:Float@double} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs new file mode 100644 index 000000000000..536164192dc0 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs @@ -0,0 +1,38 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Test with NoTT flag - should not generate TypeTree metadata + let output_nott = rustc() + .input("test.rs") + .arg("-Zautodiff=Enable,NoTT,PrintTAFn=square") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + // Write output for NoTT case + rfs::write("nott.stdout", output_nott.stdout_utf8()); + + // Test without NoTT flag - should generate TypeTree metadata + let output_with_tt = rustc() + .input("test.rs") + .arg("-Zautodiff=Enable,PrintTAFn=square") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + // Write output for TypeTree case + rfs::write("with_tt.stdout", output_with_tt.stdout_utf8()); + + // Verify NoTT output has minimal TypeTree info + llvm_filecheck().patterns("nott.check").stdin_buf(rfs::read("nott.stdout")).run(); + + // Verify normal output will have TypeTree info (once implemented) + llvm_filecheck().patterns("with_tt.check").stdin_buf(rfs::read("with_tt.stdout")).run(); +} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/test.rs b/tests/run-make/autodiff/type-trees/nott-flag/test.rs new file mode 100644 index 000000000000..5c634eea035d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/nott-flag/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_square, Duplicated, Active)] +#[no_mangle] +fn square(x: &f64) -> f64 { + x * x +} + +fn main() { + let x = 2.0; + let mut dx = 0.0; + let _result = d_square(&x, &mut dx, 1.0); +} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check new file mode 100644 index 000000000000..56ef2f0bdf38 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check @@ -0,0 +1,3 @@ +// TODO(KMJ-007): Update this test when TypeTree integration is complete +// CHECK: square - {[-1]:Float@double} |{[-1]:Pointer}:{} +// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} \ No newline at end of file diff --git a/tests/ui/autodiff/flag_nott.rs b/tests/ui/autodiff/flag_nott.rs new file mode 100644 index 000000000000..7a97d892cd88 --- /dev/null +++ b/tests/ui/autodiff/flag_nott.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Zautodiff=Enable,NoTT +//@ needs-enzyme +//@ check-pass + +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +// Test that NoTT flag is accepted and doesn't cause compilation errors +#[autodiff_reverse(d_square, Duplicated, Active)] +fn square(x: &f64) -> f64 { + x * x +} + +fn main() { + let x = 2.0; + let mut dx = 0.0; + let result = d_square(&x, &mut dx, 1.0); +} \ No newline at end of file From 375e14ef491ac7bfa701e269b2815625abf2fca6 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Sat, 23 Aug 2025 21:56:56 +0000 Subject: [PATCH 048/537] Add TypeTree metadata attachment for autodiff - Add F128 support to TypeTree Kind enum - Implement TypeTree FFI bindings and conversion functions - Add typetree.rs module for metadata attachment to LLVM functions - Integrate TypeTree generation with autodiff intrinsic pipeline - Support scalar types: f32, f64, integers, f16, f128 - Attach enzyme_type attributes as LLVM string metadata for Enzyme Signed-off-by: Karan Janthe --- compiler/rustc_ast/src/expand/typetree.rs | 1 + .../src/builder/autodiff.rs | 6 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 + compiler/rustc_codegen_llvm/src/lib.rs | 1 + .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 182 +++++++++++++++++- compiler/rustc_codegen_llvm/src/typetree.rs | 144 ++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 19 +- 7 files changed, 343 insertions(+), 14 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/typetree.rs diff --git a/compiler/rustc_ast/src/expand/typetree.rs b/compiler/rustc_ast/src/expand/typetree.rs index 9a2dd2e85e0d..e7b4f3aff413 100644 --- a/compiler/rustc_ast/src/expand/typetree.rs +++ b/compiler/rustc_ast/src/expand/typetree.rs @@ -31,6 +31,7 @@ pub enum Kind { Half, Float, Double, + F128, Unknown, } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b66e3dfdeec2..c3485f563916 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -1,6 +1,7 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; +use rustc_ast::expand::typetree::FncTree; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv}; @@ -294,6 +295,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( fn_args: &[&'ll Value], attrs: AutoDiffAttrs, dest: PlaceRef<'tcx, &'ll Value>, + fnc_tree: FncTree, ) { // We have to pick the name depending on whether we want forward or reverse mode autodiff. let mut ad_name: String = match attrs.mode { @@ -370,6 +372,10 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( fn_args, ); + if !fnc_tree.args.is_empty() || !fnc_tree.ret.0.is_empty() { + crate::typetree::add_tt(cx.llmod, cx.llcx, fn_to_diff, fnc_tree); + } + let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); builder.store_to_place(call, dest.val); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e7f4a3570488..3254b3186519 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1213,6 +1213,9 @@ fn codegen_autodiff<'ll, 'tcx>( &mut diff_attrs.input_activity, ); + let fnc_tree = + rustc_middle::ty::fnc_typetrees(tcx, fn_source.ty(tcx, TypingEnv::fully_monomorphized())); + // Build body generate_enzyme_call( bx, @@ -1223,6 +1226,7 @@ fn codegen_autodiff<'ll, 'tcx>( &val_arr, diff_attrs.clone(), result, + fnc_tree, ); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6fb23d098433..a5ac789285d4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -67,6 +67,7 @@ mod llvm_util; mod mono_item; mod type_; mod type_of; +mod typetree; mod va_arg; mod value; diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 695435eb6daa..12b6ffa3c0b5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -3,9 +3,35 @@ use libc::{c_char, c_uint}; use super::MetadataKindId; -use super::ffi::{AttributeKind, BasicBlock, Metadata, Module, Type, Value}; +use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value}; use crate::llvm::{Bool, Builder}; +// TypeTree types +pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub(crate) struct EnzymeTypeTree { + _unused: [u8; 0], +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[allow(non_camel_case_types)] +pub(crate) enum CConcreteType { + DT_Anything = 0, + DT_Integer = 1, + DT_Pointer = 2, + DT_Half = 3, + DT_Float = 4, + DT_Double = 5, + DT_Unknown = 6, +} + +pub(crate) struct TypeTree { + pub(crate) inner: CTypeTreeRef, +} + #[link(name = "llvm-wrapper", kind = "static")] unsafe extern "C" { // Enzyme @@ -68,10 +94,33 @@ pub(crate) mod Enzyme_AD { use libc::c_void; + use super::{CConcreteType, CTypeTreeRef, Context}; + unsafe extern "C" { pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); } + + // TypeTree functions + unsafe extern "C" { + pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef; + pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef; + pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef; + pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef); + pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool; + pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64); + pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef); + pub(crate) fn EnzymeTypeTreeShiftIndiciesEq( + arg1: CTypeTreeRef, + data_layout: *const c_char, + offset: i64, + max_size: i64, + add_offset: u64, + ); + pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; + pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); + } + unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; @@ -141,6 +190,57 @@ pub(crate) use self::Fallback_AD::*; pub(crate) mod Fallback_AD { #![allow(unused_variables)] + use libc::c_char; + + use super::{CConcreteType, CTypeTreeRef, Context}; + + // TypeTree function fallbacks + pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq( + arg1: CTypeTreeRef, + data_layout: *const c_char, + offset: i64, + max_size: i64, + add_offset: u64, + ) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) { + unimplemented!() + } + pub(crate) fn set_inline(val: bool) { unimplemented!() } @@ -169,3 +269,83 @@ pub(crate) mod Fallback_AD { unimplemented!() } } + +impl TypeTree { + pub(crate) fn new() -> TypeTree { + let inner = unsafe { EnzymeNewTypeTree() }; + TypeTree { inner } + } + + pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree { + let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) }; + TypeTree { inner } + } + + pub(crate) fn merge(self, other: Self) -> Self { + unsafe { + EnzymeMergeTypeTree(self.inner, other.inner); + } + drop(other); + self + } + + #[must_use] + pub(crate) fn shift( + self, + layout: &str, + offset: isize, + max_size: isize, + add_offset: usize, + ) -> Self { + let layout = std::ffi::CString::new(layout).unwrap(); + + unsafe { + EnzymeTypeTreeShiftIndiciesEq( + self.inner, + layout.as_ptr(), + offset as i64, + max_size as i64, + add_offset as u64, + ); + } + + self + } +} + +impl Clone for TypeTree { + fn clone(&self) -> Self { + let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) }; + TypeTree { inner } + } +} + +impl std::fmt::Display for TypeTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let ptr = unsafe { EnzymeTypeTreeToString(self.inner) }; + let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) }; + match cstr.to_str() { + Ok(x) => write!(f, "{}", x)?, + Err(err) => write!(f, "could not parse: {}", err)?, + } + + // delete C string pointer + unsafe { + EnzymeTypeTreeToStringFree(ptr); + } + + Ok(()) + } +} + +impl std::fmt::Debug for TypeTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ::fmt(self, f) + } +} + +impl Drop for TypeTree { + fn drop(&mut self) { + unsafe { EnzymeFreeTypeTree(self.inner) } + } +} diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs new file mode 100644 index 000000000000..434316464e62 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -0,0 +1,144 @@ +use std::ffi::{CString, c_char, c_uint}; + +use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree}; + +use crate::attributes; +use crate::llvm::{self, Value}; + +/// Converts a Rust TypeTree to Enzyme's internal TypeTree format +/// +/// This function takes a Rust-side TypeTree (from rustc_ast::expand::typetree) +/// and converts it to Enzyme's internal C++ TypeTree representation that +/// Enzyme can understand during differentiation analysis. +#[cfg(llvm_enzyme)] +fn to_enzyme_typetree( + rust_typetree: RustTypeTree, + data_layout: &str, + llcx: &llvm::Context, +) -> llvm::TypeTree { + // Start with an empty TypeTree + let mut enzyme_tt = llvm::TypeTree::new(); + + // Convert each Type in the Rust TypeTree to Enzyme format + for rust_type in rust_typetree.0 { + let concrete_type = match rust_type.kind { + rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything, + rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer, + rustc_ast::expand::typetree::Kind::Pointer => llvm::CConcreteType::DT_Pointer, + rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half, + rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float, + rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double, + rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_Unknown, + rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown, + }; + + // Create a TypeTree for this specific type + let type_tt = llvm::TypeTree::from_type(concrete_type, llcx); + + // Apply offset if specified + let type_tt = if rust_type.offset == -1 { + type_tt // -1 means everywhere/no specific offset + } else { + // Apply specific offset positioning + type_tt.shift(data_layout, rust_type.offset, rust_type.size as isize, 0) + }; + + // Merge this type into the main TypeTree + enzyme_tt = enzyme_tt.merge(type_tt); + } + + enzyme_tt +} + +#[cfg(not(llvm_enzyme))] +fn to_enzyme_typetree( + _rust_typetree: RustTypeTree, + _data_layout: &str, + _llcx: &llvm::Context, +) -> ! { + unimplemented!("TypeTree conversion not available without llvm_enzyme support") +} + +// Attaches TypeTree information to LLVM function as enzyme_type attributes. +#[cfg(llvm_enzyme)] +pub(crate) fn add_tt<'ll>( + llmod: &'ll llvm::Module, + llcx: &'ll llvm::Context, + fn_def: &'ll Value, + tt: FncTree, +) { + let inputs = tt.args; + let ret_tt: RustTypeTree = tt.ret; + + // Get LLVM data layout string for TypeTree conversion + let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) }; + let llvm_data_layout = + std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes()) + .expect("got a non-UTF8 data-layout from LLVM"); + + // Attribute name that Enzyme recognizes for TypeTree information + let attr_name = "enzyme_type"; + let c_attr_name = CString::new(attr_name).unwrap(); + + // Attach TypeTree attributes to each input parameter + // Enzyme uses these to understand parameter memory layouts during differentiation + for (i, input) in inputs.iter().enumerate() { + unsafe { + // Convert Rust TypeTree to Enzyme's internal format + let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx); + + // Serialize TypeTree to string format that Enzyme can parse + let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let c_str = std::ffi::CStr::from_ptr(c_str); + + // Create LLVM string attribute with TypeTree information + let attr = llvm::LLVMCreateStringAttribute( + llcx, + c_attr_name.as_ptr(), + c_attr_name.as_bytes().len() as c_uint, + c_str.as_ptr(), + c_str.to_bytes().len() as c_uint, + ); + + // Attach attribute to the specific function parameter + // Note: ArgumentPlace uses 0-based indexing, but LLVM uses 1-based for arguments + attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]); + + // Free the C string to prevent memory leaks + llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + } + } + + // Attach TypeTree attribute to the return type + // Enzyme needs this to understand how to handle return value derivatives + unsafe { + let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx); + let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let c_str = std::ffi::CStr::from_ptr(c_str); + + let ret_attr = llvm::LLVMCreateStringAttribute( + llcx, + c_attr_name.as_ptr(), + c_attr_name.as_bytes().len() as c_uint, + c_str.as_ptr(), + c_str.to_bytes().len() as c_uint, + ); + + // Attach to function return type + attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]); + + // Free the C string + llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + } +} + +// Fallback implementation when Enzyme is not available +#[cfg(not(llvm_enzyme))] +pub(crate) fn add_tt<'ll>( + _llmod: &'ll llvm::Module, + _llcx: &'ll llvm::Context, + _fn_def: &'ll Value, + _tt: FncTree, +) { + unimplemented!() +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index df42c4003175..e7130757f1db 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2251,36 +2251,29 @@ pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { /// Generate TypeTree for a specific type. /// This function analyzes a Rust type and creates appropriate TypeTree metadata. -fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { - // Handle basic scalar types +pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { if ty.is_scalar() { let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) } else if ty.is_floating_point() { match ty { + x if x == tcx.types.f16 => (Kind::Half, 2), x if x == tcx.types.f32 => (Kind::Float, 4), x if x == tcx.types.f64 => (Kind::Double, 8), - _ => return TypeTree::new(), // Unknown float type + x if x == tcx.types.f128 => (Kind::F128, 16), + _ => return TypeTree::new(), } } else { - // TODO(KMJ-007): Handle other scalar types if needed return TypeTree::new(); }; - - return TypeTree(vec![Type { - offset: -1, - size, - kind, - child: TypeTree::new() - }]); + + return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]); } - // Handle references and pointers if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { let inner_ty = if let Some(inner) = ty.builtin_deref(true) { inner } else { - // TODO(KMJ-007): Handle complex pointer types return TypeTree::new(); }; From beba6b9b8692d0db14c56292d4fb793fcd8ceb1e Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Sat, 23 Aug 2025 21:57:37 +0000 Subject: [PATCH 049/537] Update TypeTree tests to verify metadata attachment - Fix nott-flag test to emit LLVM IR and check enzyme_type attributes - Replace TODO comments with actual TypeTree metadata verification - Test that NoTT flag properly disables TypeTree generation - Test that TypeTree enabled generates proper enzyme_type attributes Signed-off-by: Karan Janthe --- .../autodiff/type-trees/nott-flag/nott.check | 8 ++-- .../autodiff/type-trees/nott-flag/rmake.rs | 42 +++++++++---------- .../type-trees/nott-flag/with_tt.check | 7 ++-- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/tests/run-make/autodiff/type-trees/nott-flag/nott.check b/tests/run-make/autodiff/type-trees/nott-flag/nott.check index 56ef2f0bdf38..8d23e2ee3195 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/nott.check +++ b/tests/run-make/autodiff/type-trees/nott-flag/nott.check @@ -1,3 +1,5 @@ -// TODO(KMJ-007): Update this test when TypeTree integration is complete -// CHECK: square - {[-1]:Float@double} |{[-1]:Pointer}:{} -// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} \ No newline at end of file +// Check that enzyme_type attributes are NOT present when NoTT flag is used +// This verifies the NoTT flag correctly disables TypeTree metadata + +CHECK: define{{.*}}@square +CHECK-NOT: "enzyme_type" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs index 536164192dc0..bab863ca9ff2 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs +++ b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs @@ -5,34 +5,32 @@ use run_make_support::{llvm_filecheck, rfs, rustc}; fn main() { // Test with NoTT flag - should not generate TypeTree metadata - let output_nott = rustc() + rustc() .input("test.rs") - .arg("-Zautodiff=Enable,NoTT,PrintTAFn=square") - .arg("-Zautodiff=NoPostopt") - .opt_level("3") - .arg("-Clto=fat") - .arg("-g") + .arg("-Zautodiff=Enable,NoTT") + .emit("llvm-ir") + .arg("-o") + .arg("nott.ll") .run(); - // Write output for NoTT case - rfs::write("nott.stdout", output_nott.stdout_utf8()); - // Test without NoTT flag - should generate TypeTree metadata - let output_with_tt = rustc() + rustc() .input("test.rs") - .arg("-Zautodiff=Enable,PrintTAFn=square") - .arg("-Zautodiff=NoPostopt") - .opt_level("3") - .arg("-Clto=fat") - .arg("-g") + .arg("-Zautodiff=Enable") + .emit("llvm-ir") + .arg("-o") + .arg("with_tt.ll") .run(); - // Write output for TypeTree case - rfs::write("with_tt.stdout", output_with_tt.stdout_utf8()); - - // Verify NoTT output has minimal TypeTree info - llvm_filecheck().patterns("nott.check").stdin_buf(rfs::read("nott.stdout")).run(); + // Verify NoTT version does NOT have enzyme_type attributes + llvm_filecheck() + .patterns("nott.check") + .stdin_buf(rfs::read("nott.ll")) + .run(); - // Verify normal output will have TypeTree info (once implemented) - llvm_filecheck().patterns("with_tt.check").stdin_buf(rfs::read("with_tt.stdout")).run(); + // Verify TypeTree version DOES have enzyme_type attributes + llvm_filecheck() + .patterns("with_tt.check") + .stdin_buf(rfs::read("with_tt.ll")) + .run(); } \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check index 56ef2f0bdf38..53eafc10a65d 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check +++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check @@ -1,3 +1,4 @@ -// TODO(KMJ-007): Update this test when TypeTree integration is complete -// CHECK: square - {[-1]:Float@double} |{[-1]:Pointer}:{} -// CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double} \ No newline at end of file +// Check that enzyme_type attributes are present when TypeTree is enabled +// This verifies our TypeTree metadata attachment is working + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file From 5d3ebc3804299503387b7ea1427f1619d410c2b2 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Sat, 23 Aug 2025 21:57:54 +0000 Subject: [PATCH 050/537] Add TypeTree tests for scalar types - Add specific tests for f32, f64, i32, f16, f128 TypeTree generation - Verify correct enzyme_type metadata for each scalar type - Ensure TypeTree metadata matches expected Enzyme format Signed-off-by: Karan Janthe --- .../scalar-types/f128-typetree/f128.check | 4 ++++ .../scalar-types/f128-typetree/rmake.rs | 12 ++++++++++++ .../type-trees/scalar-types/f128-typetree/test.rs | 15 +++++++++++++++ .../scalar-types/f16-typetree/f16.check | 4 ++++ .../type-trees/scalar-types/f16-typetree/rmake.rs | 12 ++++++++++++ .../type-trees/scalar-types/f16-typetree/test.rs | 15 +++++++++++++++ .../scalar-types/f32-typetree/f32.check | 4 ++++ .../type-trees/scalar-types/f32-typetree/rmake.rs | 12 ++++++++++++ .../type-trees/scalar-types/f32-typetree/test.rs | 15 +++++++++++++++ .../scalar-types/f64-typetree/f64.check | 4 ++++ .../type-trees/scalar-types/f64-typetree/rmake.rs | 12 ++++++++++++ .../type-trees/scalar-types/f64-typetree/test.rs | 15 +++++++++++++++ .../scalar-types/i32-typetree/i32.check | 4 ++++ .../type-trees/scalar-types/i32-typetree/rmake.rs | 12 ++++++++++++ .../type-trees/scalar-types/i32-typetree/test.rs | 14 ++++++++++++++ 15 files changed, 154 insertions(+) create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/test.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/test.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/test.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/test.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check new file mode 100644 index 000000000000..31cef113420d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check @@ -0,0 +1,4 @@ +; Check that f128 TypeTree metadata is correctly generated +; f128 maps to Unknown in our current implementation since CConcreteType doesn't have DT_F128 + +CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f128{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/rmake.rs new file mode 100644 index 000000000000..44320ecdd571 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile with TypeTree enabled and emit LLVM IR + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + + // Check that f128 TypeTree metadata is correctly generated + llvm_filecheck().patterns("f128.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/test.rs new file mode 100644 index 000000000000..5c71baa3e699 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff, f128)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_f128(x: &f128) -> f128 { + *x * *x +} + +fn main() { + let x = 2.0_f128; + let mut dx = 0.0_f128; + let _result = d_test(&x, &mut dx, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check new file mode 100644 index 000000000000..97a3964a569b --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check @@ -0,0 +1,4 @@ +; Check that f16 TypeTree metadata is correctly generated +; Should show Half for f16 values and Pointer for references + +CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f16{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/rmake.rs new file mode 100644 index 000000000000..0aebdbf55209 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile with TypeTree enabled and emit LLVM IR + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + + // Check that f16 TypeTree metadata is correctly generated + llvm_filecheck().patterns("f16.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/test.rs new file mode 100644 index 000000000000..6b68e8252f4c --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff, f16)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_f16(x: &f16) -> f16 { + *x * *x +} + +fn main() { + let x = 2.0_f16; + let mut dx = 0.0_f16; + let _result = d_test(&x, &mut dx, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check new file mode 100644 index 000000000000..b32d5086d07d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check @@ -0,0 +1,4 @@ +; Check that f32 TypeTree metadata is correctly generated +; Should show Float@float for f32 values and Pointer for references + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/rmake.rs new file mode 100644 index 000000000000..ee3ab753bf50 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile with TypeTree enabled and emit LLVM IR + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + + // Check that f32 TypeTree metadata is correctly generated + llvm_filecheck().patterns("f32.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/test.rs new file mode 100644 index 000000000000..56c118399ee4 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_f32(x: &f32) -> f32 { + x * x +} + +fn main() { + let x = 2.0_f32; + let mut dx = 0.0_f32; + let _result = d_test(&x, &mut dx, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check new file mode 100644 index 000000000000..0e9d9c03a0f8 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check @@ -0,0 +1,4 @@ +; Check that f64 TypeTree metadata is correctly generated +; Should show Float@double for f64 values and Pointer for references + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/rmake.rs new file mode 100644 index 000000000000..5fac9b23bc80 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile with TypeTree enabled and emit LLVM IR + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + + // Check that f64 TypeTree metadata is correctly generated + llvm_filecheck().patterns("f64.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/test.rs new file mode 100644 index 000000000000..235360b76b23 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_f64(x: &f64) -> f64 { + x * x +} + +fn main() { + let x = 2.0_f64; + let mut dx = 0.0_f64; + let _result = d_test(&x, &mut dx, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check new file mode 100644 index 000000000000..aa8e5223e8ed --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check @@ -0,0 +1,4 @@ +; Check that i32 TypeTree metadata is correctly generated +; Should show Integer for i32 values (integers are typically Const in autodiff) + +CHECK: define{{.*}}"enzyme_type"="{[]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[]:Integer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/rmake.rs new file mode 100644 index 000000000000..a40fd55d88ad --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/rmake.rs @@ -0,0 +1,12 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // Compile with TypeTree enabled and emit LLVM IR + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + + // Check that i32 TypeTree metadata is correctly generated + llvm_filecheck().patterns("i32.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs new file mode 100644 index 000000000000..530c137f62b9 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs @@ -0,0 +1,14 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Const, Active)] +#[no_mangle] +fn test_i32(x: i32) -> i32 { + x * x +} + +fn main() { + let x = 5_i32; + let _result = d_test(x, 1); +} From 664e83b3e76b51fb5192e74a64eef3bc5bbd4e32 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Sat, 23 Aug 2025 23:10:48 +0000 Subject: [PATCH 051/537] added typetree support for memcpy --- compiler/rustc_codegen_gcc/src/builder.rs | 1 + .../rustc_codegen_gcc/src/intrinsic/mod.rs | 1 + compiler/rustc_codegen_llvm/src/abi.rs | 1 + compiler/rustc_codegen_llvm/src/builder.rs | 15 ++++++- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 + compiler/rustc_codegen_llvm/src/typetree.rs | 20 ++++------ compiler/rustc_codegen_llvm/src/va_arg.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + .../rustc_codegen_ssa/src/mir/intrinsic.rs | 2 +- .../rustc_codegen_ssa/src/mir/statement.rs | 2 +- .../rustc_codegen_ssa/src/traits/builder.rs | 3 +- compiler/rustc_interface/src/tests.rs | 1 - compiler/rustc_middle/src/ty/mod.rs | 4 +- tests/codegen-llvm/autodiff/typetree.rs | 2 +- .../memcpy-typetree/memcpy-ir.check | 8 ++++ .../type-trees/memcpy-typetree/memcpy.check | 13 +++++++ .../type-trees/memcpy-typetree/memcpy.rs | 36 +++++++++++++++++ .../type-trees/memcpy-typetree/rmake.rs | 39 +++++++++++++++++++ .../autodiff/type-trees/nott-flag/rmake.rs | 14 ++----- .../autodiff/type-trees/nott-flag/test.rs | 2 +- tests/ui/autodiff/flag_nott.rs | 2 +- 21 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs create mode 100644 tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f7a7a3f8c7e3..5657620879ca 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1383,6 +1383,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _src_align: Align, size: RValue<'gcc>, flags: MemFlags, + _tt: Option, // Autodiff TypeTrees are LLVM-only, ignored in GCC backend ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_size_t(), false); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 84fa56cf9030..3b897a198350 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -771,6 +771,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(self.layout.size.bytes()), MemFlags::empty(), + None, ); bx.lifetime_end(scratch, scratch_size); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 11be70411679..61fadad60661 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -246,6 +246,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(copy_bytes), MemFlags::empty(), + None, ); bx.lifetime_end(llscratch, scratch_size); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0f17cc9063a8..83a9cf620f10 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2,6 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::ops::Deref; use std::{iter, ptr}; +use rustc_ast::expand::typetree::FncTree; pub(crate) mod autodiff; pub(crate) mod gpu_offload; @@ -1107,11 +1108,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align: Align, size: &'ll Value, flags: MemFlags, + tt: Option, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_isize(), false); let is_volatile = flags.contains(MemFlags::VOLATILE); - unsafe { + let memcpy = unsafe { llvm::LLVMRustBuildMemCpy( self.llbuilder, dst, @@ -1120,7 +1122,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align.bytes() as c_uint, size, is_volatile, - ); + ) + }; + + // TypeTree metadata for memcpy is especially important: when Enzyme encounters + // a memcpy during autodiff, it needs to know the structure of the data being + // copied to properly track derivatives. For example, copying an array of floats + // vs. copying a struct with mixed types requires different derivative handling. + // The TypeTree tells Enzyme exactly what memory layout to expect. + if let Some(tt) = tt { + crate::typetree::add_tt(self.cx().llmod, self.cx().llcx, memcpy, tt); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 12b6ffa3c0b5..9dd84ad9a4dc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -25,6 +25,7 @@ pub(crate) enum CConcreteType { DT_Half = 3, DT_Float = 4, DT_Double = 5, + // FIXME(KMJ-007): handle f128 using long double here(https://github.com/EnzymeAD/Enzyme/issues/1600) DT_Unknown = 6, } diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 434316464e62..8e6272a186b8 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -1,8 +1,11 @@ -use std::ffi::{CString, c_char, c_uint}; +use rustc_ast::expand::typetree::FncTree; +#[cfg(llvm_enzyme)] +use { + crate::attributes, + rustc_ast::expand::typetree::TypeTree as RustTypeTree, + std::ffi::{CString, c_char, c_uint}, +}; -use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree}; - -use crate::attributes; use crate::llvm::{self, Value}; /// Converts a Rust TypeTree to Enzyme's internal TypeTree format @@ -50,15 +53,6 @@ fn to_enzyme_typetree( enzyme_tt } -#[cfg(not(llvm_enzyme))] -fn to_enzyme_typetree( - _rust_typetree: RustTypeTree, - _data_layout: &str, - _llcx: &llvm::Context, -) -> ! { - unimplemented!("TypeTree conversion not available without llvm_enzyme support") -} - // Attaches TypeTree information to LLVM function as enzyme_type attributes. #[cfg(llvm_enzyme)] pub(crate) fn add_tt<'ll>( diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ab08125217ff..d48c7cf874a0 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -738,6 +738,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( src_align, bx.const_u32(layout.layout.size().bytes() as u32), MemFlags::empty(), + None, ); tmp } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1b218a0d3395..b2dc4fe32b0f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1626,6 +1626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { align, bx.const_usize(copy_bytes), MemFlags::empty(), + None, ); // ...and then load it with the ABI type. llval = load_cast(bx, cast, llscratch, scratch_align); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3c667b8e8820..befa00c6861e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -30,7 +30,7 @@ fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if allow_overlap { bx.memmove(dst, align, src, align, size, flags); } else { - bx.memcpy(dst, align, src, align, size, flags); + bx.memcpy(dst, align, src, align, size, flags, None); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f164e0f91237..0a50d7f18dbe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -90,7 +90,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let align = pointee_layout.align; let dst = dst_val.immediate(); let src = src_val.immediate(); - bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); + bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), None); } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 4a5694e97fa2..60296e36e0c1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -451,6 +451,7 @@ pub trait BuilderMethods<'a, 'tcx>: src_align: Align, size: Self::Value, flags: MemFlags, + tt: Option, ); fn memmove( &mut self, @@ -507,7 +508,7 @@ pub trait BuilderMethods<'a, 'tcx>: temp.val.store_with_flags(self, dst.with_type(layout), flags); } else if !layout.is_zst() { let bytes = self.const_usize(layout.size.bytes()); - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags); + self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 837acdadd579..0dc5b5af3aca 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -765,7 +765,6 @@ fn test_unstable_options_tracking_hash() { tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); tracked!(assume_incomplete_release, true); - tracked!(autodiff, vec![AutoDiff::Enable]); tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e7130757f1db..741b5d7fd4e0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2280,12 +2280,12 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { let child = typetree_from_ty(tcx, inner_ty); return TypeTree(vec![Type { offset: -1, - size: 8, // TODO(KMJ-007): Get actual pointer size from target + size: tcx.data_layout.pointer_size().bytes_usize(), kind: Kind::Pointer, child, }]); } - // TODO(KMJ-007): Handle arrays, slices, structs, and other complex types + // FIXME(KMJ-007): Handle arrays, slices, structs, and other complex types TypeTree::new() } diff --git a/tests/codegen-llvm/autodiff/typetree.rs b/tests/codegen-llvm/autodiff/typetree.rs index 3ad38d581b9a..1cb0c2fb68be 100644 --- a/tests/codegen-llvm/autodiff/typetree.rs +++ b/tests/codegen-llvm/autodiff/typetree.rs @@ -30,4 +30,4 @@ fn main() { let output_ = d_simple(&x, &mut df_dx, 1.0); assert_eq!(output, output_); assert_eq!(2.0, df_dx); -} \ No newline at end of file +} diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check new file mode 100644 index 000000000000..3a59f06dda1e --- /dev/null +++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check @@ -0,0 +1,8 @@ +; Check that enzyme_type attributes are present in the LLVM IR function definition +; This verifies our TypeTree system correctly attaches metadata for Enzyme + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[]:Pointer}" + +; Check that llvm.memcpy exists (either call or declare) +CHECK: {{(call|declare).*}}@llvm.memcpy + diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check new file mode 100644 index 000000000000..ae70830297a7 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.check @@ -0,0 +1,13 @@ +CHECK: force_memcpy + +CHECK: @llvm.memcpy.p0.p0.i64 + +CHECK: test_memcpy - {[-1]:Float@double} |{[-1]:Pointer}:{} + +CHECK-DAG: ptr %{{[0-9]+}}: {[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double, [-1,24]:Float@double} + +CHECK-DAG: load double{{.*}}: {[-1]:Float@double} + +CHECK-DAG: fmul double{{.*}}: {[-1]:Float@double} + +CHECK-DAG: fadd double{{.*}}: {[-1]:Float@double} \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs new file mode 100644 index 000000000000..3c1029190c88 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy.rs @@ -0,0 +1,36 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; +use std::ptr; + +#[inline(never)] +fn force_memcpy(src: *const f64, dst: *mut f64, count: usize) { + unsafe { + ptr::copy_nonoverlapping(src, dst, count); + } +} + +#[autodiff_reverse(d_test_memcpy, Duplicated, Active)] +#[no_mangle] +fn test_memcpy(input: &[f64; 128]) -> f64 { + let mut local_data = [0.0f64; 128]; + + // Use a separate function to prevent inlining and optimization + force_memcpy(input.as_ptr(), local_data.as_mut_ptr(), 128); + + // Sum only first few elements to keep the computation simple + local_data[0] * local_data[0] + + local_data[1] * local_data[1] + + local_data[2] * local_data[2] + + local_data[3] * local_data[3] +} + +fn main() { + let input = [1.0; 128]; + let mut d_input = [0.0; 128]; + let result = test_memcpy(&input); + let result_d = d_test_memcpy(&input, &mut d_input, 1.0); + + assert_eq!(result, result_d); + println!("Memcpy test passed: result = {}", result); +} diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs new file mode 100644 index 000000000000..b4c650330fe9 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/rmake.rs @@ -0,0 +1,39 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + // First, compile to LLVM IR to check for enzyme_type attributes + let _ir_output = rustc() + .input("memcpy.rs") + .arg("-Zautodiff=Enable") + .arg("-Zautodiff=NoPostopt") + .opt_level("0") + .arg("--emit=llvm-ir") + .arg("-o") + .arg("main.ll") + .run(); + + // Then compile with TypeTree analysis output for the existing checks + let output = rustc() + .input("memcpy.rs") + .arg("-Zautodiff=Enable,PrintTAFn=test_memcpy") + .arg("-Zautodiff=NoPostopt") + .opt_level("3") + .arg("-Clto=fat") + .arg("-g") + .run(); + + let stdout = output.stdout_utf8(); + let stderr = output.stderr_utf8(); + let ir_content = rfs::read_to_string("main.ll"); + + rfs::write("memcpy.stdout", &stdout); + rfs::write("memcpy.stderr", &stderr); + rfs::write("main.ir", &ir_content); + + llvm_filecheck().patterns("memcpy.check").stdin_buf(stdout).run(); + + llvm_filecheck().patterns("memcpy-ir.check").stdin_buf(ir_content).run(); +} diff --git a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs index bab863ca9ff2..de540b990cab 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs +++ b/tests/run-make/autodiff/type-trees/nott-flag/rmake.rs @@ -23,14 +23,8 @@ fn main() { .run(); // Verify NoTT version does NOT have enzyme_type attributes - llvm_filecheck() - .patterns("nott.check") - .stdin_buf(rfs::read("nott.ll")) - .run(); - + llvm_filecheck().patterns("nott.check").stdin_buf(rfs::read("nott.ll")).run(); + // Verify TypeTree version DOES have enzyme_type attributes - llvm_filecheck() - .patterns("with_tt.check") - .stdin_buf(rfs::read("with_tt.ll")) - .run(); -} \ No newline at end of file + llvm_filecheck().patterns("with_tt.check").stdin_buf(rfs::read("with_tt.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/nott-flag/test.rs b/tests/run-make/autodiff/type-trees/nott-flag/test.rs index 5c634eea035d..de3549c37c67 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/test.rs +++ b/tests/run-make/autodiff/type-trees/nott-flag/test.rs @@ -12,4 +12,4 @@ fn main() { let x = 2.0; let mut dx = 0.0; let _result = d_square(&x, &mut dx, 1.0); -} \ No newline at end of file +} diff --git a/tests/ui/autodiff/flag_nott.rs b/tests/ui/autodiff/flag_nott.rs index 7a97d892cd88..faa9949fe816 100644 --- a/tests/ui/autodiff/flag_nott.rs +++ b/tests/ui/autodiff/flag_nott.rs @@ -16,4 +16,4 @@ fn main() { let x = 2.0; let mut dx = 0.0; let result = d_square(&x, &mut dx, 1.0); -} \ No newline at end of file +} From b8bb2e8bfec298aecec54f67e8ea3deda471eafa Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 27 Aug 2025 05:58:42 +0000 Subject: [PATCH 052/537] typo: allow EnzymeTypeTreeShiftIndiciesEq --- typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/typos.toml b/typos.toml index b0ff48f8fa28..c7d5b0000b9d 100644 --- a/typos.toml +++ b/typos.toml @@ -53,6 +53,7 @@ ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC" ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED" ERRNO_ACCES = "ERRNO_ACCES" tolen = "tolen" +EnzymeTypeTreeShiftIndiciesEq = "EnzymeTypeTreeShiftIndiciesEq" [default] extend-ignore-words-re = [ From d89ee858ab80f2c922c117c95b20264be8b84e3c Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 27 Aug 2025 18:19:55 +0000 Subject: [PATCH 053/537] enzyme submodule updated --- src/llvm-project | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm-project b/src/llvm-project index 333793696b0a..2a22c8014390 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 333793696b0a08002acac6af983adc7a5233fc56 +Subproject commit 2a22c8014390bdf387d8ed26005fee3187fb98bd diff --git a/src/tools/cargo b/src/tools/cargo index 966f94733bbc..a4bd03c92d3b 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 966f94733bbc94ca51ff9f1e4c49ad250ebbdc50 +Subproject commit a4bd03c92d3b977909953d06cc45e263bd7ca7d8 From 54f9376660707d4ca9fce51fd423658f75128ac4 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 27 Aug 2025 18:23:54 +0000 Subject: [PATCH 054/537] autodiff: f128 support added for typetree --- compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 2 +- compiler/rustc_codegen_llvm/src/typetree.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 9dd84ad9a4dc..1596dc483797 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -25,8 +25,8 @@ pub(crate) enum CConcreteType { DT_Half = 3, DT_Float = 4, DT_Double = 5, - // FIXME(KMJ-007): handle f128 using long double here(https://github.com/EnzymeAD/Enzyme/issues/1600) DT_Unknown = 6, + DT_FP128 = 9, } pub(crate) struct TypeTree { diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 8e6272a186b8..8c0d255bba84 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -31,7 +31,7 @@ fn to_enzyme_typetree( rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half, rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float, rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double, - rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_Unknown, + rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_FP128, rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown, }; From 31541feb6f7e46c23141bdeb3e35ecd305bf8762 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Mon, 1 Sep 2025 05:05:49 +0000 Subject: [PATCH 055/537] autodiff: add TypeTree support for arrays --- compiler/rustc_middle/src/ty/mod.rs | 42 ++++++++++++++++++- .../type-trees/array-typetree/array.check | 4 ++ .../type-trees/array-typetree/rmake.rs | 9 ++++ .../type-trees/array-typetree/test.rs | 15 +++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/autodiff/type-trees/array-typetree/array.check create mode 100644 tests/run-make/autodiff/type-trees/array-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/array-typetree/test.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 741b5d7fd4e0..02a4e4e2b159 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2286,6 +2286,46 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { }]); } - // FIXME(KMJ-007): Handle arrays, slices, structs, and other complex types + if ty.is_array() { + if let ty::Array(element_ty, len_const) = ty.kind() { + let len = len_const.try_to_target_usize(tcx).unwrap_or(0); + if len == 0 { + return TypeTree::new(); + } + + let element_tree = typetree_from_ty(tcx, *element_ty); + + let element_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*element_ty)) + .ok() + .map(|layout| layout.size.bytes_usize()) + .unwrap_or(0); + + if element_layout == 0 { + return TypeTree::new(); + } + + let mut types = Vec::new(); + for i in 0..len { + let base_offset = (i as usize * element_layout) as isize; + + for elem_type in &element_tree.0 { + types.push(Type { + offset: if elem_type.offset == -1 { + base_offset + } else { + base_offset + elem_type.offset + }, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + } + + return TypeTree(types); + } + } + TypeTree::new() } diff --git a/tests/run-make/autodiff/type-trees/array-typetree/array.check b/tests/run-make/autodiff/type-trees/array-typetree/array.check new file mode 100644 index 000000000000..7513458b8ab8 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/array-typetree/array.check @@ -0,0 +1,4 @@ +; Check that array TypeTree metadata is correctly generated +; Should show Float@double at each array element offset (0, 8, 16, 24, 32 bytes) + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_array{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/array-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/array-typetree/rmake.rs new file mode 100644 index 000000000000..20b6a0669062 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/array-typetree/rmake.rs @@ -0,0 +1,9 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + llvm_filecheck().patterns("array.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/array-typetree/test.rs b/tests/run-make/autodiff/type-trees/array-typetree/test.rs new file mode 100644 index 000000000000..f54ebf5a4c7b --- /dev/null +++ b/tests/run-make/autodiff/type-trees/array-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_array(arr: &[f64; 5]) -> f64 { + arr[0] + arr[1] + arr[2] + arr[3] + arr[4] +} + +fn main() { + let arr = [1.0, 2.0, 3.0, 4.0, 5.0]; + let mut d_arr = [0.0; 5]; + let _result = d_test(&arr, &mut d_arr, 1.0); +} From be3617b04031c7d4f227ce54c4ce6ceeae00981c Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Mon, 1 Sep 2025 06:17:34 +0000 Subject: [PATCH 056/537] autodiff: slice support in typetree --- compiler/rustc_middle/src/ty/mod.rs | 7 +++++++ .../autodiff/type-trees/slice-typetree/rmake.rs | 9 +++++++++ .../type-trees/slice-typetree/slice.check | 4 ++++ .../autodiff/type-trees/slice-typetree/test.rs | 16 ++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 tests/run-make/autodiff/type-trees/slice-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/slice-typetree/slice.check create mode 100644 tests/run-make/autodiff/type-trees/slice-typetree/test.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 02a4e4e2b159..82a41f403f8b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2327,5 +2327,12 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { } } + if ty.is_slice() { + if let ty::Slice(element_ty) = ty.kind() { + let element_tree = typetree_from_ty(tcx, *element_ty); + return element_tree; + } + } + TypeTree::new() } diff --git a/tests/run-make/autodiff/type-trees/slice-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/slice-typetree/rmake.rs new file mode 100644 index 000000000000..b81fb50bf1a7 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/slice-typetree/rmake.rs @@ -0,0 +1,9 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + llvm_filecheck().patterns("slice.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/slice-typetree/slice.check b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check new file mode 100644 index 000000000000..8fc9e9c4f1b1 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check @@ -0,0 +1,4 @@ +; Check that slice TypeTree metadata is correctly generated +; Should show Float@double for slice elements + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_slice{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/slice-typetree/test.rs b/tests/run-make/autodiff/type-trees/slice-typetree/test.rs new file mode 100644 index 000000000000..7117fa3844f5 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/slice-typetree/test.rs @@ -0,0 +1,16 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_slice(slice: &[f64]) -> f64 { + slice.iter().sum() +} + +fn main() { + let arr = [1.0, 2.0, 3.0, 4.0, 5.0]; + let slice = &arr[..]; + let mut d_slice = [0.0; 5]; + let _result = d_test(slice, &mut d_slice[..], 1.0); +} From 7c5fbfbdbbb389462e0ffb936ba9b16cffbce6ed Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Mon, 1 Sep 2025 16:14:31 +0000 Subject: [PATCH 057/537] autodiff: tuple support in typetree --- compiler/rustc_middle/src/ty/mod.rs | 36 +++++++++++++++++++ .../type-trees/tuple-typetree/rmake.rs | 9 +++++ .../type-trees/tuple-typetree/test.rs | 15 ++++++++ .../type-trees/tuple-typetree/tuple.check | 4 +++ 4 files changed, 64 insertions(+) create mode 100644 tests/run-make/autodiff/type-trees/tuple-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/tuple-typetree/test.rs create mode 100644 tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 82a41f403f8b..c0a091551c9e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2334,5 +2334,41 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { } } + if let ty::Tuple(tuple_types) = ty.kind() { + if tuple_types.is_empty() { + return TypeTree::new(); + } + + let mut types = Vec::new(); + let mut current_offset = 0; + + for tuple_ty in tuple_types.iter() { + let element_tree = typetree_from_ty(tcx, tuple_ty); + + let element_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) + .ok() + .map(|layout| layout.size.bytes_usize()) + .unwrap_or(0); + + for elem_type in &element_tree.0 { + types.push(Type { + offset: if elem_type.offset == -1 { + current_offset as isize + } else { + current_offset as isize + elem_type.offset + }, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + + current_offset += element_layout; + } + + return TypeTree(types); + } + TypeTree::new() } diff --git a/tests/run-make/autodiff/type-trees/tuple-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/tuple-typetree/rmake.rs new file mode 100644 index 000000000000..76913828901c --- /dev/null +++ b/tests/run-make/autodiff/type-trees/tuple-typetree/rmake.rs @@ -0,0 +1,9 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + llvm_filecheck().patterns("tuple.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/tuple-typetree/test.rs b/tests/run-make/autodiff/type-trees/tuple-typetree/test.rs new file mode 100644 index 000000000000..32187b587a38 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/tuple-typetree/test.rs @@ -0,0 +1,15 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_tuple(tuple: &(f64, f64, f64)) -> f64 { + tuple.0 + tuple.1 * 2.0 + tuple.2 * 3.0 +} + +fn main() { + let tuple = (1.0, 2.0, 3.0); + let mut d_tuple = (0.0, 0.0, 0.0); + let _result = d_test(&tuple, &mut d_tuple, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check new file mode 100644 index 000000000000..50aa25e96aed --- /dev/null +++ b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check @@ -0,0 +1,4 @@ +; Check that tuple TypeTree metadata is correctly generated +; Should show Float@double at offsets 0, 8, 16 for (f64, f64, f64) + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_tuple{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file From 574f0b97d6f30cd6cedb165fde13cdec176611b8 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Mon, 1 Sep 2025 16:28:14 +0000 Subject: [PATCH 058/537] autodiff: struct support in typetree --- compiler/rustc_middle/src/ty/mod.rs | 32 +++++++++++++++++++ .../type-trees/struct-typetree/rmake.rs | 9 ++++++ .../type-trees/struct-typetree/struct.check | 4 +++ .../type-trees/struct-typetree/test.rs | 22 +++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 tests/run-make/autodiff/type-trees/struct-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/struct-typetree/struct.check create mode 100644 tests/run-make/autodiff/type-trees/struct-typetree/test.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c0a091551c9e..703d417f96db 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2370,5 +2370,37 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { return TypeTree(types); } + if let ty::Adt(adt_def, args) = ty.kind() { + if adt_def.is_struct() { + let struct_layout = + tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)); + if let Ok(layout) = struct_layout { + let mut types = Vec::new(); + + for (field_idx, field_def) in adt_def.all_fields().enumerate() { + let field_ty = field_def.ty(tcx, args); + let field_tree = typetree_from_ty(tcx, field_ty); + + let field_offset = layout.fields.offset(field_idx).bytes_usize(); + + for elem_type in &field_tree.0 { + types.push(Type { + offset: if elem_type.offset == -1 { + field_offset as isize + } else { + field_offset as isize + elem_type.offset + }, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + } + + return TypeTree(types); + } + } + } + TypeTree::new() } diff --git a/tests/run-make/autodiff/type-trees/struct-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/struct-typetree/rmake.rs new file mode 100644 index 000000000000..0af1b65ee181 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/struct-typetree/rmake.rs @@ -0,0 +1,9 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + llvm_filecheck().patterns("struct.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/struct-typetree/struct.check b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check new file mode 100644 index 000000000000..2f763f18c1ce --- /dev/null +++ b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check @@ -0,0 +1,4 @@ +; Check that struct TypeTree metadata is correctly generated +; Should show Float@double at offsets 0, 8, 16 for Point struct fields + +CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_struct{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/struct-typetree/test.rs b/tests/run-make/autodiff/type-trees/struct-typetree/test.rs new file mode 100644 index 000000000000..cbe7b10e4097 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/struct-typetree/test.rs @@ -0,0 +1,22 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[repr(C)] +struct Point { + x: f64, + y: f64, + z: f64, +} + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +fn test_struct(point: &Point) -> f64 { + point.x + point.y * 2.0 + point.z * 3.0 +} + +fn main() { + let point = Point { x: 1.0, y: 2.0, z: 3.0 }; + let mut d_point = Point { x: 0.0, y: 0.0, z: 0.0 }; + let _result = d_test(&point, &mut d_point, 1.0); +} From 4f3f0f48e7b1e61818b2bcbe4451f89bb4f47049 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Thu, 4 Sep 2025 11:17:34 +0000 Subject: [PATCH 059/537] autodiff: fixed test to be more precise for type tree checking --- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 23 ++++++ compiler/rustc_codegen_llvm/src/typetree.rs | 70 ++++++++----------- compiler/rustc_middle/src/ty/mod.rs | 36 +++------- .../type-trees/array-typetree/array.check | 2 +- .../memcpy-typetree/memcpy-ir.check | 2 +- .../mixed-struct-typetree/mixed.check | 2 + .../type-trees/mixed-struct-typetree/rmake.rs | 16 +++++ .../type-trees/mixed-struct-typetree/test.rs | 23 ++++++ .../type-trees/nott-flag/with_tt.check | 2 +- .../scalar-types/f128-typetree/f128.check | 4 +- .../scalar-types/f16-typetree/f16.check | 4 +- .../scalar-types/f32-typetree/f32.check | 2 +- .../scalar-types/f64-typetree/f64.check | 2 +- .../scalar-types/i32-typetree/i32.check | 4 +- .../scalar-types/i32-typetree/test.rs | 7 +- .../type-trees/slice-typetree/slice.check | 2 +- .../type-trees/struct-typetree/struct.check | 2 +- .../type-trees/tuple-typetree/tuple.check | 2 +- .../type-trees/type-analysis/vec/vec.check | 2 +- 19 files changed, 120 insertions(+), 87 deletions(-) create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 1596dc483797..e63043b21227 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -118,6 +118,13 @@ pub(crate) mod Enzyme_AD { max_size: i64, add_offset: u64, ); + pub(crate) fn EnzymeTypeTreeInsertEq( + CTT: CTypeTreeRef, + indices: *const i64, + len: usize, + ct: CConcreteType, + ctx: &Context, + ); pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); } @@ -234,6 +241,16 @@ pub(crate) mod Fallback_AD { unimplemented!() } + pub(crate) unsafe fn EnzymeTypeTreeInsertEq( + CTT: CTypeTreeRef, + indices: *const i64, + len: usize, + ct: CConcreteType, + ctx: &Context, + ) { + unimplemented!() + } + pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char { unimplemented!() } @@ -312,6 +329,12 @@ impl TypeTree { self } + + pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) { + unsafe { + EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx); + } + } } impl Clone for TypeTree { diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 8c0d255bba84..ae6a2da62b5d 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -8,22 +8,24 @@ use { use crate::llvm::{self, Value}; -/// Converts a Rust TypeTree to Enzyme's internal TypeTree format -/// -/// This function takes a Rust-side TypeTree (from rustc_ast::expand::typetree) -/// and converts it to Enzyme's internal C++ TypeTree representation that -/// Enzyme can understand during differentiation analysis. #[cfg(llvm_enzyme)] fn to_enzyme_typetree( rust_typetree: RustTypeTree, - data_layout: &str, + _data_layout: &str, llcx: &llvm::Context, ) -> llvm::TypeTree { - // Start with an empty TypeTree let mut enzyme_tt = llvm::TypeTree::new(); - - // Convert each Type in the Rust TypeTree to Enzyme format - for rust_type in rust_typetree.0 { + process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); + enzyme_tt +} +#[cfg(llvm_enzyme)] +fn process_typetree_recursive( + enzyme_tt: &mut llvm::TypeTree, + rust_typetree: &RustTypeTree, + parent_indices: &[i64], + llcx: &llvm::Context, +) { + for rust_type in &rust_typetree.0 { let concrete_type = match rust_type.kind { rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything, rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer, @@ -35,25 +37,27 @@ fn to_enzyme_typetree( rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown, }; - // Create a TypeTree for this specific type - let type_tt = llvm::TypeTree::from_type(concrete_type, llcx); - - // Apply offset if specified - let type_tt = if rust_type.offset == -1 { - type_tt // -1 means everywhere/no specific offset + let mut indices = parent_indices.to_vec(); + if !parent_indices.is_empty() { + if rust_type.offset == -1 { + indices.push(-1); + } else { + indices.push(rust_type.offset as i64); + } + } else if rust_type.offset == -1 { + indices.push(-1); } else { - // Apply specific offset positioning - type_tt.shift(data_layout, rust_type.offset, rust_type.size as isize, 0) - }; + indices.push(rust_type.offset as i64); + } - // Merge this type into the main TypeTree - enzyme_tt = enzyme_tt.merge(type_tt); + enzyme_tt.insert(&indices, concrete_type, llcx); + + if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer && !rust_type.child.0.is_empty() { + process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx); + } } - - enzyme_tt } -// Attaches TypeTree information to LLVM function as enzyme_type attributes. #[cfg(llvm_enzyme)] pub(crate) fn add_tt<'ll>( llmod: &'ll llvm::Module, @@ -64,28 +68,20 @@ pub(crate) fn add_tt<'ll>( let inputs = tt.args; let ret_tt: RustTypeTree = tt.ret; - // Get LLVM data layout string for TypeTree conversion let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) }; let llvm_data_layout = std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes()) .expect("got a non-UTF8 data-layout from LLVM"); - // Attribute name that Enzyme recognizes for TypeTree information let attr_name = "enzyme_type"; let c_attr_name = CString::new(attr_name).unwrap(); - // Attach TypeTree attributes to each input parameter - // Enzyme uses these to understand parameter memory layouts during differentiation for (i, input) in inputs.iter().enumerate() { unsafe { - // Convert Rust TypeTree to Enzyme's internal format let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx); - - // Serialize TypeTree to string format that Enzyme can parse let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); let c_str = std::ffi::CStr::from_ptr(c_str); - // Create LLVM string attribute with TypeTree information let attr = llvm::LLVMCreateStringAttribute( llcx, c_attr_name.as_ptr(), @@ -94,17 +90,11 @@ pub(crate) fn add_tt<'ll>( c_str.to_bytes().len() as c_uint, ); - // Attach attribute to the specific function parameter - // Note: ArgumentPlace uses 0-based indexing, but LLVM uses 1-based for arguments attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]); - - // Free the C string to prevent memory leaks llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); } } - // Attach TypeTree attribute to the return type - // Enzyme needs this to understand how to handle return value derivatives unsafe { let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx); let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); @@ -118,15 +108,11 @@ pub(crate) fn add_tt<'ll>( c_str.to_bytes().len() as c_uint, ); - // Attach to function return type attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]); - - // Free the C string llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); } } -// Fallback implementation when Enzyme is not available #[cfg(not(llvm_enzyme))] pub(crate) fn add_tt<'ll>( _llmod: &'ll llvm::Module, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 703d417f96db..581f20e8492d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2261,10 +2261,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { x if x == tcx.types.f32 => (Kind::Float, 4), x if x == tcx.types.f64 => (Kind::Double, 8), x if x == tcx.types.f128 => (Kind::F128, 16), - _ => return TypeTree::new(), + _ => (Kind::Integer, 0), } } else { - return TypeTree::new(); + (Kind::Integer, 0) }; return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]); @@ -2295,32 +2295,14 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { let element_tree = typetree_from_ty(tcx, *element_ty); - let element_layout = tcx - .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*element_ty)) - .ok() - .map(|layout| layout.size.bytes_usize()) - .unwrap_or(0); - - if element_layout == 0 { - return TypeTree::new(); - } - let mut types = Vec::new(); - for i in 0..len { - let base_offset = (i as usize * element_layout) as isize; - - for elem_type in &element_tree.0 { - types.push(Type { - offset: if elem_type.offset == -1 { - base_offset - } else { - base_offset + elem_type.offset - }, - size: elem_type.size, - kind: elem_type.kind, - child: elem_type.child.clone(), - }); - } + for elem_type in &element_tree.0 { + types.push(Type { + offset: -1, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); } return TypeTree(types); diff --git a/tests/run-make/autodiff/type-trees/array-typetree/array.check b/tests/run-make/autodiff/type-trees/array-typetree/array.check index 7513458b8ab8..0d38bdec17e8 100644 --- a/tests/run-make/autodiff/type-trees/array-typetree/array.check +++ b/tests/run-make/autodiff/type-trees/array-typetree/array.check @@ -1,4 +1,4 @@ ; Check that array TypeTree metadata is correctly generated ; Should show Float@double at each array element offset (0, 8, 16, 24, 32 bytes) -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_array{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_array{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check index 3a59f06dda1e..0e6351ac4d39 100644 --- a/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check +++ b/tests/run-make/autodiff/type-trees/memcpy-typetree/memcpy-ir.check @@ -1,7 +1,7 @@ ; Check that enzyme_type attributes are present in the LLVM IR function definition ; This verifies our TypeTree system correctly attaches metadata for Enzyme -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[]:Pointer}" +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_memcpy({{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" ; Check that llvm.memcpy exists (either call or declare) CHECK: {{(call|declare).*}}@llvm.memcpy diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check new file mode 100644 index 000000000000..584f58408435 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/mixed.check @@ -0,0 +1,2 @@ +; Check that mixed struct with large array generates correct detailed type tree +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_mixed_struct{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer, [-1,8]:Float@float}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs new file mode 100644 index 000000000000..1c19963bc361 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/rmake.rs @@ -0,0 +1,16 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc() + .input("test.rs") + .arg("-Zautodiff=Enable") + .arg("-Zautodiff=NoPostopt") + .opt_level("0") + .emit("llvm-ir") + .run(); + + llvm_filecheck().patterns("mixed.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs new file mode 100644 index 000000000000..7a734980e617 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/mixed-struct-typetree/test.rs @@ -0,0 +1,23 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +#[repr(C)] +struct Container { + header: i64, + data: [f32; 1000], +} + +#[autodiff_reverse(d_test, Duplicated, Active)] +#[no_mangle] +#[inline(never)] +fn test_mixed_struct(container: &Container) -> f32 { + container.data[0] + container.data[999] +} + +fn main() { + let container = Container { header: 42, data: [1.0; 1000] }; + let mut d_container = Container { header: 0, data: [0.0; 1000] }; + let result = d_test(&container, &mut d_container, 1.0); + std::hint::black_box(result); +} diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check index 53eafc10a65d..3c02003c8828 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check +++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check @@ -1,4 +1,4 @@ // Check that enzyme_type attributes are present when TypeTree is enabled // This verifies our TypeTree metadata attachment is working -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check index 31cef113420d..733e46aa45a5 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check @@ -1,4 +1,4 @@ ; Check that f128 TypeTree metadata is correctly generated -; f128 maps to Unknown in our current implementation since CConcreteType doesn't have DT_F128 +; Should show Float@fp128 for f128 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f128{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@fp128}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check index 97a3964a569b..9caca26b5cf5 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check @@ -1,4 +1,4 @@ ; Check that f16 TypeTree metadata is correctly generated -; Should show Half for f16 values and Pointer for references +; Should show Float@half for f16 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"={{.*}}@test_f16{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@half}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check index b32d5086d07d..ec12ba6b2348 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check @@ -1,4 +1,4 @@ ; Check that f32 TypeTree metadata is correctly generated ; Should show Float@float for f32 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check index 0e9d9c03a0f8..f1af270824d5 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check @@ -1,4 +1,4 @@ ; Check that f64 TypeTree metadata is correctly generated ; Should show Float@double for f64 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check index aa8e5223e8ed..fd9a94be8100 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check @@ -1,4 +1,4 @@ ; Check that i32 TypeTree metadata is correctly generated -; Should show Integer for i32 values (integers are typically Const in autodiff) +; Should show Integer for i32 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[]:Integer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs index 530c137f62b9..249803c5d9f7 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/test.rs @@ -2,13 +2,14 @@ use std::autodiff::autodiff_reverse; -#[autodiff_reverse(d_test, Const, Active)] +#[autodiff_reverse(d_test, Duplicated, Active)] #[no_mangle] -fn test_i32(x: i32) -> i32 { +fn test_i32(x: &i32) -> i32 { x * x } fn main() { let x = 5_i32; - let _result = d_test(x, 1); + let mut dx = 0_i32; + let _result = d_test(&x, &mut dx, 1); } diff --git a/tests/run-make/autodiff/type-trees/slice-typetree/slice.check b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check index 8fc9e9c4f1b1..6543b6161153 100644 --- a/tests/run-make/autodiff/type-trees/slice-typetree/slice.check +++ b/tests/run-make/autodiff/type-trees/slice-typetree/slice.check @@ -1,4 +1,4 @@ ; Check that slice TypeTree metadata is correctly generated ; Should show Float@double for slice elements -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_slice{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_slice{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/struct-typetree/struct.check b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check index 2f763f18c1ce..54956317e1e9 100644 --- a/tests/run-make/autodiff/type-trees/struct-typetree/struct.check +++ b/tests/run-make/autodiff/type-trees/struct-typetree/struct.check @@ -1,4 +1,4 @@ ; Check that struct TypeTree metadata is correctly generated ; Should show Float@double at offsets 0, 8, 16 for Point struct fields -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_struct{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_struct{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check index 50aa25e96aed..47647e78cc35 100644 --- a/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check +++ b/tests/run-make/autodiff/type-trees/tuple-typetree/tuple.check @@ -1,4 +1,4 @@ ; Check that tuple TypeTree metadata is correctly generated ; Should show Float@double at offsets 0, 8, 16 for (f64, f64, f64) -CHECK: define{{.*}}"enzyme_type"="{[]:Float@double}"{{.*}}@test_tuple{{.*}}"enzyme_type"="{[]:Pointer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_tuple{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double, [-1,8]:Float@double, [-1,16]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check index dcf9508b69d6..cdb70eb83fc1 100644 --- a/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check +++ b/tests/run-make/autodiff/type-trees/type-analysis/vec/vec.check @@ -1,7 +1,7 @@ // CHECK: callee - {[-1]:Float@float} |{[-1]:Pointer}:{} // CHECK: ptr %{{[0-9]+}}: {[-1]:Pointer} // CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 8, !dbg !{{[0-9]+}}: {[-1]:Pointer} -// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !102, !noundef !{{[0-9]+}}: {} +// CHECK-DAG: %{{[0-9]+}} = load ptr, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}: {} // CHECK-DAG: %{{[0-9]+}} = getelementptr inbounds nuw i8, ptr %{{[0-9]+}}, i64 16, !dbg !{{[0-9]+}}: {[-1]:Pointer} // CHECK-DAG: %{{[0-9]+}} = load i64, ptr %{{[0-9]+}}, align 8, !dbg !{{[0-9]+}}, !noundef !{{[0-9]+}}: {} // CHECK-DAG: %{{[0-9]+}} = icmp eq i64 %{{[0-9]+}}, 0, !dbg !{{[0-9]+}}: {[-1]:Integer} From 4520926bb527bd43edbf0de84c2b0c6a9c5fc5ce Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Thu, 11 Sep 2025 07:30:35 +0000 Subject: [PATCH 060/537] autodiff: recurion added for typetree --- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 + compiler/rustc_codegen_llvm/src/typetree.rs | 10 +- compiler/rustc_middle/src/ty/mod.rs | 76 +++++++++++-- .../type-trees/nott-flag/with_tt.check | 2 +- .../recursion-typetree/recursion.check | 3 + .../type-trees/recursion-typetree/rmake.rs | 9 ++ .../type-trees/recursion-typetree/test.rs | 100 ++++++++++++++++++ .../scalar-types/f128-typetree/f128.check | 2 +- .../scalar-types/f16-typetree/f16.check | 2 +- .../scalar-types/f32-typetree/f32.check | 2 +- .../scalar-types/f64-typetree/f64.check | 2 +- .../scalar-types/i32-typetree/i32.check | 2 +- 12 files changed, 191 insertions(+), 20 deletions(-) create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/recursion-typetree/test.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index e63043b21227..b604f5139c8c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -127,6 +127,7 @@ pub(crate) mod Enzyme_AD { ); pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); + pub(crate) fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint; } unsafe extern "C" { diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index ae6a2da62b5d..1a54884f6c5a 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -39,11 +39,7 @@ fn process_typetree_recursive( let mut indices = parent_indices.to_vec(); if !parent_indices.is_empty() { - if rust_type.offset == -1 { - indices.push(-1); - } else { - indices.push(rust_type.offset as i64); - } + indices.push(rust_type.offset as i64); } else if rust_type.offset == -1 { indices.push(-1); } else { @@ -52,7 +48,9 @@ fn process_typetree_recursive( enzyme_tt.insert(&indices, concrete_type, llcx); - if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer && !rust_type.child.0.is_empty() { + if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer + && !rust_type.child.0.is_empty() + { process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx); } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 581f20e8492d..7ca2355947ad 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2252,6 +2252,61 @@ pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { /// Generate TypeTree for a specific type. /// This function analyzes a Rust type and creates appropriate TypeTree metadata. pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { + let mut visited = Vec::new(); + typetree_from_ty_inner(tcx, ty, 0, &mut visited) +} + +/// Internal recursive function for TypeTree generation with cycle detection and depth limiting. +fn typetree_from_ty_inner<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec>, +) -> TypeTree { + #[cfg(llvm_enzyme)] + { + unsafe extern "C" { + fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint; + } + let max_depth = unsafe { EnzymeGetMaxTypeDepth() } as usize; + if depth > max_depth { + return TypeTree::new(); + } + } + + #[cfg(not(llvm_enzyme))] + if depth > 6 { + return TypeTree::new(); + } + + if visited.contains(&ty) { + return TypeTree::new(); + } + + visited.push(ty); + let result = typetree_from_ty_impl(tcx, ty, depth, visited); + visited.pop(); + result +} + +/// Implementation of TypeTree generation logic. +fn typetree_from_ty_impl<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec>, +) -> TypeTree { + typetree_from_ty_impl_inner(tcx, ty, depth, visited, false) +} + +/// Internal implementation with context about whether this is for a reference target. +fn typetree_from_ty_impl_inner<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec>, + is_reference_target: bool, +) -> TypeTree { if ty.is_scalar() { let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) @@ -2267,7 +2322,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { (Kind::Integer, 0) }; - return TypeTree(vec![Type { offset: -1, size, kind, child: TypeTree::new() }]); + // Use offset 0 for scalars that are direct targets of references (like &f64) + // Use offset -1 for scalars used directly (like function return types) + let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; + return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); } if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { @@ -2277,7 +2335,7 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { return TypeTree::new(); }; - let child = typetree_from_ty(tcx, inner_ty); + let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); return TypeTree(vec![Type { offset: -1, size: tcx.data_layout.pointer_size().bytes_usize(), @@ -2292,9 +2350,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { if len == 0 { return TypeTree::new(); } - - let element_tree = typetree_from_ty(tcx, *element_ty); - + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); let mut types = Vec::new(); for elem_type in &element_tree.0 { types.push(Type { @@ -2311,7 +2368,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { if ty.is_slice() { if let ty::Slice(element_ty) = ty.kind() { - let element_tree = typetree_from_ty(tcx, *element_ty); + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); return element_tree; } } @@ -2325,7 +2383,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { let mut current_offset = 0; for tuple_ty in tuple_types.iter() { - let element_tree = typetree_from_ty(tcx, tuple_ty); + let element_tree = + typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); let element_layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) @@ -2361,7 +2420,8 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { for (field_idx, field_def) in adt_def.all_fields().enumerate() { let field_ty = field_def.ty(tcx, args); - let field_tree = typetree_from_ty(tcx, field_ty); + let field_tree = + typetree_from_ty_impl_inner(tcx, field_ty, depth + 1, visited, false); let field_offset = layout.fields.offset(field_idx).bytes_usize(); diff --git a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check index 3c02003c8828..0b4c91191798 100644 --- a/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check +++ b/tests/run-make/autodiff/type-trees/nott-flag/with_tt.check @@ -1,4 +1,4 @@ // Check that enzyme_type attributes are present when TypeTree is enabled // This verifies our TypeTree metadata attachment is working -CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@square{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check b/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check new file mode 100644 index 000000000000..1960e7b816c5 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/recursion-typetree/recursion.check @@ -0,0 +1,3 @@ +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_deep{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}" +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_graph{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer, [-1,8]:Integer, [-1,16]:Integer, [-1,24]:Float@double}" +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_node{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs b/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs new file mode 100644 index 000000000000..78718f3a2159 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/recursion-typetree/rmake.rs @@ -0,0 +1,9 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +fn main() { + rustc().input("test.rs").arg("-Zautodiff=Enable").emit("llvm-ir").run(); + llvm_filecheck().patterns("recursion.check").stdin_buf(rfs::read("test.ll")).run(); +} diff --git a/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs b/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs new file mode 100644 index 000000000000..9d40bec1bf1d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/recursion-typetree/test.rs @@ -0,0 +1,100 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +// Self-referential struct to test recursion detection +#[derive(Clone)] +struct Node { + value: f64, + next: Option>, +} + +// Mutually recursive structs to test cycle detection +#[derive(Clone)] +struct GraphNodeA { + value: f64, + connections: Vec, +} + +#[derive(Clone)] +struct GraphNodeB { + weight: f64, + target: Option>, +} + +#[autodiff_reverse(d_test_node, Duplicated, Active)] +#[no_mangle] +fn test_node(node: &Node) -> f64 { + node.value * 2.0 +} + +#[autodiff_reverse(d_test_graph, Duplicated, Active)] +#[no_mangle] +fn test_graph(a: &GraphNodeA) -> f64 { + a.value * 3.0 +} + +// Simple depth test - deeply nested but not circular +#[derive(Clone)] +struct Level1 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level2 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level3 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level4 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level5 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level6 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level7 { + val: f64, + next: Option>, +} +#[derive(Clone)] +struct Level8 { + val: f64, +} + +#[autodiff_reverse(d_test_deep, Duplicated, Active)] +#[no_mangle] +fn test_deep(deep: &Level1) -> f64 { + deep.val * 4.0 +} + +fn main() { + let node = Node { value: 1.0, next: None }; + + let graph = GraphNodeA { value: 2.0, connections: vec![] }; + + let deep = Level1 { val: 5.0, next: None }; + + let mut d_node = Node { value: 0.0, next: None }; + + let mut d_graph = GraphNodeA { value: 0.0, connections: vec![] }; + + let mut d_deep = Level1 { val: 0.0, next: None }; + + let _result1 = d_test_node(&node, &mut d_node, 1.0); + let _result2 = d_test_graph(&graph, &mut d_graph, 1.0); + let _result3 = d_test_deep(&deep, &mut d_deep, 1.0); +} diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check index 733e46aa45a5..23db64eea52a 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f128-typetree/f128.check @@ -1,4 +1,4 @@ ; Check that f128 TypeTree metadata is correctly generated ; Should show Float@fp128 for f128 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@fp128}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@fp128}"{{.*}}@test_f128{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@fp128}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check index 9caca26b5cf5..9adff68d36f3 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f16-typetree/f16.check @@ -1,4 +1,4 @@ ; Check that f16 TypeTree metadata is correctly generated ; Should show Float@half for f16 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@half}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@half}"{{.*}}@test_f16{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@half}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check index ec12ba6b2348..176630f57e8f 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f32-typetree/f32.check @@ -1,4 +1,4 @@ ; Check that f32 TypeTree metadata is correctly generated ; Should show Float@float for f32 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@float}"{{.*}}@test_f32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check index f1af270824d5..929cd379694a 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/f64-typetree/f64.check @@ -1,4 +1,4 @@ ; Check that f64 TypeTree metadata is correctly generated ; Should show Float@double for f64 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@double}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Float@double}"{{.*}}@test_f64{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@double}" \ No newline at end of file diff --git a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check index fd9a94be8100..dee4aa5bbb6b 100644 --- a/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check +++ b/tests/run-make/autodiff/type-trees/scalar-types/i32-typetree/i32.check @@ -1,4 +1,4 @@ ; Check that i32 TypeTree metadata is correctly generated ; Should show Integer for i32 values and Pointer for references -CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}" \ No newline at end of file +CHECK: define{{.*}}"enzyme_type"="{[-1]:Integer}"{{.*}}@test_i32{{.*}}"enzyme_type"="{[-1]:Pointer, [-1,0]:Integer}" \ No newline at end of file From b1a9f231fea0459356f751ad6c1704b55f541118 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 19 Sep 2025 14:41:18 +1000 Subject: [PATCH 061/537] Use `LLVMDIBuilderGetOrCreateSubrange` --- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 +++++++-------- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 ------ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index aa8b8bd152dc..c3712e5b7447 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -117,7 +117,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( .try_to_target_usize(cx.tcx) .expect("expected monomorphic const in codegen") as c_longlong; - let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; + let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; let subscripts = &[subrange]; let di_node = unsafe { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1124ebc3d44b..d125c1c9c297 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -25,7 +25,7 @@ use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, - DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange, + DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, }; use crate::llvm; @@ -890,7 +890,6 @@ pub(crate) mod debuginfo { pub(crate) type DIVariable = DIDescriptor; pub(crate) type DIGlobalVariableExpression = DIDescriptor; pub(crate) type DIArray = DIDescriptor; - pub(crate) type DISubrange = DIDescriptor; pub(crate) type DIEnumerator = DIDescriptor; pub(crate) type DITemplateTypeParameter = DIDescriptor; @@ -1989,6 +1988,12 @@ unsafe extern "C" { Scope: Option<&'ll Metadata>, AlignInBits: u32, // (optional; default is 0) ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderGetOrCreateSubrange<'ll>( + Builder: &DIBuilder<'ll>, + LowerBound: i64, + Count: i64, + ) -> &'ll Metadata; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2370,12 +2375,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIVariable; - pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>( - Builder: &DIBuilder<'a>, - Lo: i64, - Count: i64, - ) -> &'a DISubrange; - pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>( Builder: &DIBuilder<'a>, Ptr: *const Option<&'a DIDescriptor>, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 64151962321f..de79c3e6861c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1142,12 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( } } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, - int64_t Count) { - return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, LLVMMetadataRef *Ptr, unsigned Count) { From a6d261712ee546fc1fc1b7b7c0ee0782aa827b8b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 19 Sep 2025 14:44:54 +1000 Subject: [PATCH 062/537] Use `LLVMDIBuilderGetOrCreateArray` --- compiler/rustc_codegen_llvm/src/debuginfo/utils.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 12 ++++++------ compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 9 --------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index cc1d504b4301..7e1e49310f61 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -28,7 +28,7 @@ pub(crate) fn create_DIArray<'ll>( builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor>], ) -> &'ll DIArray { - unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) } + unsafe { llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len()) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d125c1c9c297..290dbda77f6f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1994,6 +1994,12 @@ unsafe extern "C" { LowerBound: i64, Count: i64, ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderGetOrCreateArray<'ll>( + Builder: &DIBuilder<'ll>, + Data: *const Option<&'ll Metadata>, + NumElements: size_t, + ) -> &'ll Metadata; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2375,12 +2381,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIVariable; - pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>( - Builder: &DIBuilder<'a>, - Ptr: *const Option<&'a DIDescriptor>, - Count: c_uint, - ) -> &'a DIArray; - pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>( Builder: &DIBuilder<'a>, Val: &'a Value, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index de79c3e6861c..b78786921760 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1142,15 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( } } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, - LLVMMetadataRef *Ptr, unsigned Count) { - Metadata **DataValue = unwrap(Ptr); - return wrap(unwrap(Builder) - ->getOrCreateArray(ArrayRef(DataValue, Count)) - .get()); -} - extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, uint64_t *AddrOps, From 5a043cef02229eb6eb777277745cd7e12b350311 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 19 Sep 2025 13:35:34 +0800 Subject: [PATCH 063/537] Fix extract_variable on LetExpr Example --- ```rust fn main() { if $0let$0 Some(x) = Some(2+2) {} } ``` **Before this PR**: ```rust fn main() { let $0var_name = let Some(x) = Some(2+2); if var_name {} } ``` **After this PR**: ```rust fn main() { let $0var_name = Some(2+2); if let Some(x) = var_name {} } ``` --- .../src/handlers/extract_variable.rs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index bd88e8b09ced..da596262962c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -285,7 +285,7 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr { /// In general that's true for any expression, but in some cases that would produce invalid code. fn valid_target_expr(node: SyntaxNode) -> Option { match node.kind() { - SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR => None, + SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None, SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()), SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), SyntaxKind::BLOCK_EXPR => { @@ -1403,6 +1403,25 @@ fn main() { ); } + #[test] + fn extract_var_let_expr() { + check_assist_by_label( + extract_variable, + r#" +fn main() { + if $0let$0 Some(x) = Some(2+2) {} +} +"#, + r#" +fn main() { + let $0var_name = Some(2+2); + if let Some(x) = var_name {} +} +"#, + "Extract into variable", + ); + } + #[test] fn extract_var_for_cast() { check_assist_by_label( @@ -1738,6 +1757,14 @@ fn main() { check_assist_not_applicable(extract_variable, "fn main() { loop { $0break$0; }; }"); } + #[test] + fn extract_var_for_let_expr_not_applicable() { + check_assist_not_applicable( + extract_variable, + "fn main() { if $0let Some(x) = Some(2+2) {} }", + ); + } + #[test] fn extract_var_unit_expr_not_applicable() { check_assist_not_applicable( From 3ba5f19182bf7144c54cbbd0b7af3d4fe76b5317 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Fri, 12 Sep 2025 06:11:18 +0000 Subject: [PATCH 064/537] autodiff: typetree recursive depth query from enzyme with fallback Signed-off-by: Karan Janthe --- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 1 - compiler/rustc_codegen_llvm/src/typetree.rs | 10 ++++----- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 +++++++++++ compiler/rustc_middle/src/ty/mod.rs | 21 +++++++------------ src/llvm-project | 2 +- src/tools/cargo | 2 +- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index b604f5139c8c..e63043b21227 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -127,7 +127,6 @@ pub(crate) mod Enzyme_AD { ); pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); - pub(crate) fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint; } unsafe extern "C" { diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 1a54884f6c5a..7e2635037008 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -1,5 +1,5 @@ use rustc_ast::expand::typetree::FncTree; -#[cfg(llvm_enzyme)] +#[cfg(feature = "llvm_enzyme")] use { crate::attributes, rustc_ast::expand::typetree::TypeTree as RustTypeTree, @@ -8,7 +8,7 @@ use { use crate::llvm::{self, Value}; -#[cfg(llvm_enzyme)] +#[cfg(feature = "llvm_enzyme")] fn to_enzyme_typetree( rust_typetree: RustTypeTree, _data_layout: &str, @@ -18,7 +18,7 @@ fn to_enzyme_typetree( process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); enzyme_tt } -#[cfg(llvm_enzyme)] +#[cfg(feature = "llvm_enzyme")] fn process_typetree_recursive( enzyme_tt: &mut llvm::TypeTree, rust_typetree: &RustTypeTree, @@ -56,7 +56,7 @@ fn process_typetree_recursive( } } -#[cfg(llvm_enzyme)] +#[cfg(feature = "llvm_enzyme")] pub(crate) fn add_tt<'ll>( llmod: &'ll llvm::Module, llcx: &'ll llvm::Context, @@ -111,7 +111,7 @@ pub(crate) fn add_tt<'ll>( } } -#[cfg(not(llvm_enzyme))] +#[cfg(not(feature = "llvm_enzyme"))] pub(crate) fn add_tt<'ll>( _llmod: &'ll llvm::Module, _llcx: &'ll llvm::Context, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 64151962321f..c1a924a87e41 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1847,3 +1847,15 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { MD.NoHWAddress = true; GV.setSanitizerMetadata(MD); } + +#ifdef ENZYME +extern "C" { +extern llvm::cl::opt EnzymeMaxTypeDepth; +} + +extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; } +#else +extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { + return 6; // Default fallback depth +} +#endif diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7ca2355947ad..ce4de6b95e0b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -63,7 +63,7 @@ pub use rustc_type_ir::solve::SizedTraitKind; pub use rustc_type_ir::*; #[allow(hidden_glob_reexports, unused_imports)] use rustc_type_ir::{InferCtxtLike, Interner}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; pub use vtable::*; use {rustc_ast as ast, rustc_hir as hir}; @@ -2256,6 +2256,10 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { typetree_from_ty_inner(tcx, ty, 0, &mut visited) } +/// Maximum recursion depth for TypeTree generation to prevent stack overflow +/// from pathological deeply nested types. Combined with cycle detection. +const MAX_TYPETREE_DEPTH: usize = 6; + /// Internal recursive function for TypeTree generation with cycle detection and depth limiting. fn typetree_from_ty_inner<'tcx>( tcx: TyCtxt<'tcx>, @@ -2263,19 +2267,8 @@ fn typetree_from_ty_inner<'tcx>( depth: usize, visited: &mut Vec>, ) -> TypeTree { - #[cfg(llvm_enzyme)] - { - unsafe extern "C" { - fn EnzymeGetMaxTypeDepth() -> ::std::os::raw::c_uint; - } - let max_depth = unsafe { EnzymeGetMaxTypeDepth() } as usize; - if depth > max_depth { - return TypeTree::new(); - } - } - - #[cfg(not(llvm_enzyme))] - if depth > 6 { + if depth >= MAX_TYPETREE_DEPTH { + trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty); return TypeTree::new(); } diff --git a/src/llvm-project b/src/llvm-project index 2a22c8014390..333793696b0a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 2a22c8014390bdf387d8ed26005fee3187fb98bd +Subproject commit 333793696b0a08002acac6af983adc7a5233fc56 diff --git a/src/tools/cargo b/src/tools/cargo index a4bd03c92d3b..966f94733bbc 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a4bd03c92d3b977909953d06cc45e263bd7ca7d8 +Subproject commit 966f94733bbc94ca51ff9f1e4c49ad250ebbdc50 From 9daa026cadca6de0d932ddb6f6ddbfa5411a25e3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 19 Sep 2025 16:56:28 +1000 Subject: [PATCH 065/537] Use `LLVMDIBuilder(CreateExpression|InsertDeclareRecordAtEnd)` --- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 15 ++++++----- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 27 ++++++++++++------- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 --------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 126082aa3aa6..dc36ed17875e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -191,18 +191,21 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { addr_ops.push((fragment.end - fragment.start).bits() as u64); } + let di_builder = DIB(self.cx()); + let addr_expr = unsafe { + llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) + }; unsafe { // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`. - llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(self.cx()), + llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( + di_builder, variable_alloca, dbg_var, - addr_ops.as_ptr(), - addr_ops.len() as c_uint, + addr_expr, dbg_loc, self.llbb(), - ); - } + ) + }; } fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 290dbda77f6f..11de4ed96530 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -806,6 +806,8 @@ unsafe extern "C" { pub(crate) type Metadata; pub(crate) type BasicBlock; pub(crate) type Comdat; + /// `&'ll DbgRecord` represents `LLVMDbgRecordRef`. + pub(crate) type DbgRecord; } #[repr(C)] pub(crate) struct Builder<'a>(InvariantOpaque<'a>); @@ -2000,6 +2002,21 @@ unsafe extern "C" { Data: *const Option<&'ll Metadata>, NumElements: size_t, ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateExpression<'ll>( + Builder: &DIBuilder<'ll>, + Addr: *const u64, + Length: size_t, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>( + Builder: &DIBuilder<'ll>, + Storage: &'ll Value, + VarInfo: &'ll Metadata, + Expr: &'ll Metadata, + DebugLoc: &'ll Metadata, + Block: &'ll BasicBlock, + ) -> &'ll DbgRecord; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2381,16 +2398,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIVariable; - pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>( - Builder: &DIBuilder<'a>, - Val: &'a Value, - VarInfo: &'a DIVariable, - AddrOps: *const u64, - AddrOpsCount: c_uint, - DL: &'a DILocation, - InsertAtEnd: &'a BasicBlock, - ); - pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, Name: *const c_char, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b78786921760..fc79cb9d473e 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1142,18 +1142,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( } } -extern "C" void -LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, - LLVMMetadataRef VarInfo, uint64_t *AddrOps, - unsigned AddrOpsCount, LLVMMetadataRef DL, - LLVMBasicBlockRef InsertAtEnd) { - unwrap(Builder)->insertDeclare( - unwrap(V), unwrap(VarInfo), - unwrap(Builder)->createExpression( - llvm::ArrayRef(AddrOps, AddrOpsCount)), - DebugLoc(cast(unwrap(DL))), unwrap(InsertAtEnd)); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], From 7506352af077b316c12be32e0f9782a0cfd73b1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Sep 2025 10:41:56 +0200 Subject: [PATCH 066/537] fix clippy warning --- src/tools/miri/src/concurrency/sync.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 15d486c27e36..e4e7fb1d725f 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -381,8 +381,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We need to drop our mutex borrow before unblock_thread // because it will be borrowed again in the unblock callback. drop(mutex); - if thread_id.is_some() { - this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?; + if let Some(thread_id) = thread_id { + this.unblock_thread(thread_id, BlockReason::Mutex)?; } } Some(old_lock_count) From e39e5a0d157a56680cdc10a77551af225b797787 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 19 Sep 2025 16:14:35 +1000 Subject: [PATCH 067/537] Use `LLVMDIBuilderCreate(Auto|Parameter)Variable` --- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 58 ++++++++++--------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 43 +++++++++----- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 18 ------ 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index dc36ed17875e..66b963436afb 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -52,15 +52,6 @@ mod utils; use self::create_scope_map::compute_mir_scopes; pub(crate) use self::metadata::build_global_var_di_node; -// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were -// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp` -// to decide which C++ API to call. Instead, we should just have two separate -// FFI functions and choose the correct one on the Rust side. -#[allow(non_upper_case_globals)] -const DW_TAG_auto_variable: c_uint = 0x100; -#[allow(non_upper_case_globals)] -const DW_TAG_arg_variable: c_uint = 0x101; - /// A context object for maintaining all state needed by the debuginfo module. pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { llmod: &'ll llvm::Module, @@ -633,28 +624,39 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let type_metadata = spanned_type_di_node(self, variable_type, span); - let (argument_index, dwarf_tag) = match variable_kind { - ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), - LocalVariable => (0, DW_TAG_auto_variable), - }; let align = self.align_of(variable_type); let name = variable_name.as_str(); - unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(self), - dwarf_tag, - scope_metadata, - name.as_c_char_ptr(), - name.len(), - file_metadata, - loc.line, - type_metadata, - true, - DIFlags::FlagZero, - argument_index, - align.bits() as u32, - ) + + match variable_kind { + ArgumentVariable(arg_index) => unsafe { + llvm::LLVMDIBuilderCreateParameterVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + arg_index as c_uint, + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + ) + }, + LocalVariable => unsafe { + llvm::LLVMDIBuilderCreateAutoVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + align.bits() as u32, + ) + }, } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 11de4ed96530..b0388594f27d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -26,7 +26,7 @@ use super::RustString; use super::debuginfo::{ DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, - DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, + DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind, }; use crate::llvm; @@ -2017,6 +2017,32 @@ unsafe extern "C" { DebugLoc: &'ll Metadata, Block: &'ll BasicBlock, ) -> &'ll DbgRecord; + + pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>( + Builder: &DIBuilder<'ll>, + Scope: &'ll Metadata, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + File: &'ll Metadata, + LineNo: c_uint, + Ty: &'ll Metadata, + AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations." + Flags: DIFlags, + AlignInBits: u32, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateParameterVariable<'ll>( + Builder: &DIBuilder<'ll>, + Scope: &'ll Metadata, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + ArgNo: c_uint, + File: &'ll Metadata, + LineNo: c_uint, + Ty: &'ll Metadata, + AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations." + Flags: DIFlags, + ) -> &'ll Metadata; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2383,21 +2409,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIGlobalVariableExpression; - pub(crate) fn LLVMRustDIBuilderCreateVariable<'a>( - Builder: &DIBuilder<'a>, - Tag: c_uint, - Scope: &'a DIDescriptor, - Name: *const c_char, - NameLen: size_t, - File: &'a DIFile, - LineNo: c_uint, - Ty: &'a DIType, - AlwaysPreserve: bool, - Flags: DIFlags, - ArgNo: c_uint, - AlignInBits: u32, - ) -> &'a DIVariable; - pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, Name: *const c_char, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index fc79cb9d473e..c7fa26f18e14 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1124,24 +1124,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( return wrap(VarExpr); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( - LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo, - uint32_t AlignInBits) { - if (Tag == 0x100) { // DW_TAG_auto_variable - return wrap(unwrap(Builder)->createAutoVariable( - unwrapDI(Scope), StringRef(Name, NameLen), - unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, - fromRust(Flags), AlignInBits)); - } else { - return wrap(unwrap(Builder)->createParameterVariable( - unwrapDI(Scope), StringRef(Name, NameLen), ArgNo, - unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, - fromRust(Flags))); - } -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], From 272d336f0f89610bc18bc276b5f89dc163c69d24 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 19 Sep 2025 17:25:16 +1000 Subject: [PATCH 068/537] Remove some unnecessary `as u64` casts In each of these casts, the LHS is already `u64`. --- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 66b963436afb..af64e4ebed0f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -165,21 +165,21 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { if direct_offset.bytes() > 0 { addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(direct_offset.bytes() as u64); + addr_ops.push(direct_offset.bytes()); } for &offset in indirect_offsets { addr_ops.push(DW_OP_deref); if offset.bytes() > 0 { addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(offset.bytes() as u64); + addr_ops.push(offset.bytes()); } } if let Some(fragment) = fragment { // `DW_OP_LLVM_fragment` takes as arguments the fragment's // offset and size, both of them in bits. addr_ops.push(DW_OP_LLVM_fragment); - addr_ops.push(fragment.start.bits() as u64); - addr_ops.push((fragment.end - fragment.start).bits() as u64); + addr_ops.push(fragment.start.bits()); + addr_ops.push((fragment.end - fragment.start).bits()); } let di_builder = DIB(self.cx()); From 024ea0274d0ac4c938712653e2f8e2e7fec619f2 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 19 Sep 2025 19:55:02 +0800 Subject: [PATCH 069/537] Fix `else` completion before else keyword Example --- ```rust fn foo() { let x = if true { 1 } el$0 else { 2 }; } ``` **Before this PR**: ```text else~ k [LS] else if~ k [LS] ``` **After this PR**: ```text else if~ k [LS] ``` --- .../ide-completion/src/completions/expr.rs | 3 +- .../crates/ide-completion/src/context.rs | 1 + .../ide-completion/src/context/analysis.rs | 4 +- .../ide-completion/src/tests/expression.rs | 128 +++++++++++++++++- 4 files changed, 133 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index a7df0ab3863b..080875e01632 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -59,6 +59,7 @@ pub(crate) fn complete_expr_path( in_block_expr, in_breakable, after_if_expr, + before_else_kw, in_condition, incomplete_let, after_incomplete_let, @@ -386,7 +387,7 @@ pub(crate) fn complete_expr_path( add_keyword("let", "let $1 = $0;"); } - if after_if_expr || after_incomplete_let { + if !before_else_kw && (after_if_expr || after_incomplete_let) { add_keyword("else", "else {\n $0\n}"); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 007475688d20..9deaaf663127 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -144,6 +144,7 @@ pub(crate) struct PathExprCtx<'db> { pub(crate) in_block_expr: bool, pub(crate) in_breakable: BreakableKind, pub(crate) after_if_expr: bool, + pub(crate) before_else_kw: bool, /// Whether this expression is the direct condition of an if or while expression pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index b33a547dee97..7b78a9700ec5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1282,11 +1282,12 @@ fn classify_name_ref<'db>( let after_incomplete_let = after_incomplete_let(it.clone()).is_some(); let incomplete_expr_stmt = it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none()); + let before_else_kw = before_else_kw(it); let incomplete_let = it .parent() .and_then(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()) - || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it); + || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw; let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); @@ -1302,6 +1303,7 @@ fn classify_name_ref<'db>( in_block_expr, in_breakable: in_loop_body, after_if_expr, + before_else_kw, in_condition, ref_expr_parent, after_amp, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 79137104b568..db9a7b2efe17 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1673,7 +1673,133 @@ fn foo() { let x = if foo {} $0 else {}; } kw async kw const kw crate:: - kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 else if true {}; } +"#, + expect![[r#" + fn foo fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} el$0 else if true {} else {}; } +"#, + expect![[r#" + fn foo() fn() + lc x () + bt u32 u32 + kw async + kw const + kw crate:: + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 else if true {} else {}; } +"#, + expect![[r#" + fn foo fn() + bt u32 u32 + kw async + kw const + kw crate:: kw else if kw enum kw extern From 4320de6424626cb7cd798973e22aef15dae3ba58 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 19 Sep 2025 14:22:26 +0000 Subject: [PATCH 070/537] fixes for numerous clippy warnings --- compiler/rustc_hir_typeck/src/pat.rs | 72 +++++++++++++--------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f735c0a41609..46accb76a184 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -47,7 +47,7 @@ You can read more about trait objects in the Trait Objects section of the Refere https://doc.rust-lang.org/reference/types.html#trait-objects"; fn is_number(text: &str) -> bool { - text.chars().all(|c: char| c.is_digit(10)) + text.chars().all(|c: char| c.is_ascii_digit()) } /// Information about the expected type at the top level of type checking a pattern. @@ -262,8 +262,9 @@ enum InheritedRefMatchRule { /// pattern matches a given type: /// - If the underlying type is not a reference, a reference pattern may eat the inherited reference; /// - If the underlying type is a reference, a reference pattern matches if it can eat either one - /// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the - /// underlying type is `&mut` or the inherited reference is `&mut`. + /// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the + /// underlying type is `&mut` or the inherited reference is `&mut`. + /// /// If `false`, a reference pattern is only matched against the underlying type. /// This is `false` for stable Rust and `true` for both the `ref_pat_eat_one_layer_2024` and /// `ref_pat_eat_one_layer_2024_structural` feature gates. @@ -1069,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { if !self.tcx.features().mut_ref() { feature_err( - &self.tcx.sess, + self.tcx.sess, sym::mut_ref, pat.span.until(ident.span), "binding cannot be both mutable and by-reference", @@ -1487,31 +1488,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_def_id: Option, ident: Ident, ) -> bool { - match opt_def_id { - Some(def_id) => match self.tcx.hir_get_if_local(def_id) { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, _, _, body_id), - .. - })) => match self.tcx.hir_node(body_id.hir_id) { - hir::Node::Expr(expr) => { - if hir::is_range_literal(expr) { - let span = self.tcx.hir_span(body_id.hir_id); - if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { - e.span_suggestion_verbose( - ident.span, - "you may want to move the range into the match block", - snip, - Applicability::MachineApplicable, - ); - return true; - } - } - } - _ => (), - }, - _ => (), - }, - _ => (), + if let Some(def_id) = opt_def_id + && let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, _, _, body_id), + .. + })) = self.tcx.hir_get_if_local(def_id) + && let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id) + && hir::is_range_literal(expr) + { + let span = self.tcx.hir_span(body_id.hir_id); + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { + e.span_suggestion_verbose( + ident.span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable, + ); + return true; + } } false } @@ -1529,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = self.tcx.hir_res_span(pat_res) { e.span_label(span, format!("{} defined here", res.descr())); - if let [hir::PathSegment { ident, .. }] = &*segments { + if let [hir::PathSegment { ident, .. }] = segments { e.span_label( pat_span, format!( @@ -1557,17 +1551,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (None, None), }; - let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) { + let is_range = matches!( + type_def_id.and_then(|id| self.tcx.as_lang_item(id)), Some( LangItem::Range - | LangItem::RangeFrom - | LangItem::RangeTo - | LangItem::RangeFull - | LangItem::RangeInclusiveStruct - | LangItem::RangeToInclusive, - ) => true, - _ => false, - }; + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) + ); if is_range { if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { let msg = "constants only support matching by type, \ From 3ba0c221aea356b73376784de50cf604ead1b441 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 18 Sep 2025 03:21:01 +0900 Subject: [PATCH 071/537] fix: Make flycheck clearing dependency-aware --- .../project-model/src/build_dependencies.rs | 11 +- .../project-model/src/cargo_workspace.rs | 57 ++++++++- .../crates/rust-analyzer/src/diagnostics.rs | 23 ++++ .../crates/rust-analyzer/src/flycheck.rs | 110 ++++++++++++++---- .../crates/rust-analyzer/src/global_state.rs | 23 ++++ .../src/handlers/notification.rs | 10 +- .../crates/rust-analyzer/src/main_loop.rs | 19 +-- .../crates/rust-analyzer/src/target_spec.rs | 3 + 8 files changed, 213 insertions(+), 43 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index 203173c11be4..5eda5af3ace0 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -9,7 +9,7 @@ use std::{cell::RefCell, io, mem, process::Command}; use base_db::Env; -use cargo_metadata::{Message, camino::Utf8Path}; +use cargo_metadata::{Message, PackageId, camino::Utf8Path}; use cfg::CfgAtom; use itertools::Itertools; use la_arena::ArenaMap; @@ -18,6 +18,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use serde::Deserialize as _; use stdx::never; use toolchain::Tool; +use triomphe::Arc; use crate::{ CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, @@ -284,7 +285,7 @@ impl WorkspaceBuildScripts { // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are // exactly those from `config`. - let mut by_id: FxHashMap = FxHashMap::default(); + let mut by_id: FxHashMap, Package> = FxHashMap::default(); for package in workspace.packages() { outputs.insert(package, BuildScriptOutput::default()); by_id.insert(workspace[package].id.clone(), package); @@ -323,7 +324,7 @@ impl WorkspaceBuildScripts { // ideally this would be something like: // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)), // but owned trait objects aren't a thing - mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)), + mut with_output_for: impl FnMut(&PackageId, &mut dyn FnMut(&str, &mut BuildScriptOutput)), progress: &dyn Fn(String), ) -> io::Result> { let errors = RefCell::new(String::new()); @@ -346,7 +347,7 @@ impl WorkspaceBuildScripts { match message { Message::BuildScriptExecuted(mut message) => { - with_output_for(&message.package_id.repr, &mut |name, data| { + with_output_for(&message.package_id, &mut |name, data| { progress(format!("build script {name} run")); let cfgs = { let mut acc = Vec::new(); @@ -377,7 +378,7 @@ impl WorkspaceBuildScripts { }); } Message::CompilerArtifact(message) => { - with_output_for(&message.package_id.repr, &mut |name, data| { + with_output_for(&message.package_id, &mut |name, data| { progress(format!("proc-macro {name} built")); if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt { data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro; diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index e613fd590c70..adc0cc509416 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -5,7 +5,7 @@ use std::str::from_utf8; use anyhow::Context; use base_db::Env; -use cargo_metadata::{CargoOpt, MetadataCommand}; +use cargo_metadata::{CargoOpt, MetadataCommand, PackageId}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -14,6 +14,7 @@ use serde_json::from_value; use span::Edition; use stdx::process::spawn_with_streaming_output; use toolchain::Tool; +use triomphe::Arc; use crate::cargo_config_file::make_lockfile_copy; use crate::{CfgOverrides, InvocationStrategy}; @@ -155,8 +156,8 @@ pub struct PackageData { pub features: FxHashMap>, /// List of features enabled on this package pub active_features: Vec, - /// String representation of package id - pub id: String, + /// Package id + pub id: Arc, /// Authors as given in the `Cargo.toml` pub authors: Vec, /// Description as given in the `Cargo.toml` @@ -173,6 +174,10 @@ pub struct PackageData { pub rust_version: Option, /// The contents of [package.metadata.rust-analyzer] pub metadata: RustAnalyzerPackageMetaData, + /// If this package is a member of the workspace, store all direct and transitive + /// dependencies as long as they are workspace members, to track dependency relationships + /// between members. + pub all_member_deps: Option>, } #[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)] @@ -334,6 +339,8 @@ impl CargoWorkspace { let mut is_virtual_workspace = true; let mut requires_rustc_private = false; + let mut members = FxHashSet::default(); + meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); for meta_pkg in meta.packages { let cargo_metadata::Package { @@ -356,6 +363,7 @@ impl CargoWorkspace { rust_version, .. } = meta_pkg; + let id = Arc::new(id); let meta = from_value::(metadata).unwrap_or_default(); let edition = match edition { cargo_metadata::Edition::E2015 => Edition::Edition2015, @@ -375,7 +383,7 @@ impl CargoWorkspace { let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap(); is_virtual_workspace &= manifest != ws_manifest_path; let pkg = packages.alloc(PackageData { - id: id.repr.clone(), + id: id.clone(), name: name.to_string(), version, manifest: manifest.clone(), @@ -395,7 +403,11 @@ impl CargoWorkspace { features: features.into_iter().collect(), active_features: Vec::new(), metadata: meta.rust_analyzer.unwrap_or_default(), + all_member_deps: None, }); + if is_member { + members.insert(pkg); + } let pkg_data = &mut packages[pkg]; requires_rustc_private |= pkg_data.metadata.rustc_private; pkg_by_id.insert(id, pkg); @@ -440,6 +452,43 @@ impl CargoWorkspace { .extend(node.features.into_iter().map(|it| it.to_string())); } + fn saturate_all_member_deps( + packages: &mut Arena, + to_visit: Package, + visited: &mut FxHashSet, + members: &FxHashSet, + ) { + let pkg_data = &mut packages[to_visit]; + + if !visited.insert(to_visit) { + return; + } + + let deps: Vec<_> = pkg_data + .dependencies + .iter() + .filter_map(|dep| { + let pkg = dep.pkg; + if members.contains(&pkg) { Some(pkg) } else { None } + }) + .collect(); + + let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied()); + for dep in deps { + saturate_all_member_deps(packages, dep, visited, members); + if let Some(transitives) = &packages[dep].all_member_deps { + all_member_deps.extend(transitives); + } + } + + packages[to_visit].all_member_deps = Some(all_member_deps); + } + + let mut visited = FxHashSet::default(); + for member in members.iter() { + saturate_all_member_deps(&mut packages, *member, &mut visited, &members); + } + CargoWorkspace { packages, targets, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index ee50237c405e..4bfad98b3997 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -120,6 +120,29 @@ impl DiagnosticCollection { } } + pub(crate) fn clear_check_older_than_for_package( + &mut self, + flycheck_id: usize, + package_id: Arc, + generation: DiagnosticsGeneration, + ) { + let Some(check) = self.check.get_mut(flycheck_id) else { + return; + }; + let package_id = Some(package_id); + let Some((_, checks)) = check + .per_package + .extract_if(|k, v| *k == package_id && v.generation < generation) + .next() + else { + return; + }; + self.changes.extend(checks.per_file.into_keys()); + if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { + fixes.remove(&package_id); + } + } + pub(crate) fn clear_native_for(&mut self, file_id: FileId) { self.native_syntax.remove(&file_id); self.native_semantic.remove(&file_id); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 315c45d5b639..cded34be14a2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -180,17 +180,27 @@ impl FlycheckHandle { pub(crate) fn restart_workspace(&self, saved_file: Option) { let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; self.sender - .send(StateChange::Restart { generation, package: None, saved_file, target: None }) + .send(StateChange::Restart { + generation, + scope: FlycheckScope::Workspace, + saved_file, + target: None, + }) .unwrap(); } /// Schedule a re-start of the cargo check worker to do a package wide check. - pub(crate) fn restart_for_package(&self, package: String, target: Option) { + pub(crate) fn restart_for_package( + &self, + package: Arc, + target: Option, + workspace_deps: Option>>, + ) { let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; self.sender .send(StateChange::Restart { generation, - package: Some(package), + scope: FlycheckScope::Package { package, workspace_deps }, saved_file: None, target, }) @@ -213,8 +223,13 @@ impl FlycheckHandle { #[derive(Debug)] pub(crate) enum ClearDiagnosticsKind { - All, - OlderThan(DiagnosticsGeneration), + All(ClearScope), + OlderThan(DiagnosticsGeneration, ClearScope), +} + +#[derive(Debug)] +pub(crate) enum ClearScope { + Workspace, Package(Arc), } @@ -275,10 +290,15 @@ pub(crate) enum Progress { DidFailToRestart(String), } +enum FlycheckScope { + Workspace, + Package { package: Arc, workspace_deps: Option>> }, +} + enum StateChange { Restart { generation: DiagnosticsGeneration, - package: Option, + scope: FlycheckScope, saved_file: Option, target: Option, }, @@ -298,6 +318,7 @@ struct FlycheckActor { /// or the project root of the project. root: Arc, sysroot_root: Option, + scope: FlycheckScope, /// CargoHandle exists to wrap around the communication needed to be able to /// run `cargo check` without blocking. Currently the Rust standard library /// doesn't provide a way to read sub-process output without blocking, so we @@ -343,6 +364,7 @@ impl FlycheckActor { config, sysroot_root, root: Arc::new(workspace_root), + scope: FlycheckScope::Workspace, manifest_path, command_handle: None, command_receiver: None, @@ -376,7 +398,7 @@ impl FlycheckActor { } Event::RequestStateChange(StateChange::Restart { generation, - package, + scope, saved_file, target, }) => { @@ -389,11 +411,11 @@ impl FlycheckActor { } } + let command = self.check_command(&scope, saved_file.as_deref(), target); + self.scope = scope; self.generation = generation; - let Some(command) = - self.check_command(package.as_deref(), saved_file.as_deref(), target) - else { + let Some(command) = command else { continue; }; @@ -435,19 +457,55 @@ impl FlycheckActor { tracing::trace!(flycheck_id = self.id, "clearing diagnostics"); // We finished without receiving any diagnostics. // Clear everything for good measure - self.send(FlycheckMessage::ClearDiagnostics { - id: self.id, - kind: ClearDiagnosticsKind::All, - }); + match &self.scope { + FlycheckScope::Workspace => { + self.send(FlycheckMessage::ClearDiagnostics { + id: self.id, + kind: ClearDiagnosticsKind::All(ClearScope::Workspace), + }); + } + FlycheckScope::Package { package, workspace_deps } => { + for pkg in + std::iter::once(package).chain(workspace_deps.iter().flatten()) + { + self.send(FlycheckMessage::ClearDiagnostics { + id: self.id, + kind: ClearDiagnosticsKind::All(ClearScope::Package( + pkg.clone(), + )), + }); + } + } + } } else if res.is_ok() { // We clear diagnostics for packages on // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where // cargo may not report an artifact to our runner at all. To handle such // cases, clear stale diagnostics when flycheck completes successfully. - self.send(FlycheckMessage::ClearDiagnostics { - id: self.id, - kind: ClearDiagnosticsKind::OlderThan(self.generation), - }); + match &self.scope { + FlycheckScope::Workspace => { + self.send(FlycheckMessage::ClearDiagnostics { + id: self.id, + kind: ClearDiagnosticsKind::OlderThan( + self.generation, + ClearScope::Workspace, + ), + }); + } + FlycheckScope::Package { package, workspace_deps } => { + for pkg in + std::iter::once(package).chain(workspace_deps.iter().flatten()) + { + self.send(FlycheckMessage::ClearDiagnostics { + id: self.id, + kind: ClearDiagnosticsKind::OlderThan( + self.generation, + ClearScope::Package(pkg.clone()), + ), + }); + } + } + } } self.clear_diagnostics_state(); @@ -475,7 +533,7 @@ impl FlycheckActor { ); self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - kind: ClearDiagnosticsKind::Package(package_id), + kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)), }); } } @@ -498,7 +556,9 @@ impl FlycheckActor { ); self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - kind: ClearDiagnosticsKind::Package(package_id.clone()), + kind: ClearDiagnosticsKind::All(ClearScope::Package( + package_id.clone(), + )), }); } } else if self.diagnostics_received @@ -507,7 +567,7 @@ impl FlycheckActor { self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll; self.send(FlycheckMessage::ClearDiagnostics { id: self.id, - kind: ClearDiagnosticsKind::All, + kind: ClearDiagnosticsKind::All(ClearScope::Workspace), }); } self.send(FlycheckMessage::AddDiagnostic { @@ -548,7 +608,7 @@ impl FlycheckActor { /// return None. fn check_command( &self, - package: Option<&str>, + scope: &FlycheckScope, saved_file: Option<&AbsPath>, target: Option, ) -> Option { @@ -564,9 +624,9 @@ impl FlycheckActor { } cmd.arg(command); - match package { - Some(pkg) => cmd.arg("-p").arg(pkg), - None => cmd.arg("--workspace"), + match scope { + FlycheckScope::Workspace => cmd.arg("--workspace"), + FlycheckScope::Package { package, .. } => cmd.arg("-p").arg(&package.repr), }; if let Some(tgt) = target { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 89d6fb8edc2e..ce6644f725ca 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -9,6 +9,7 @@ use std::{ time::{Duration, Instant}, }; +use cargo_metadata::PackageId; use crossbeam_channel::{Receiver, Sender, unbounded}; use hir::ChangeWithProcMacros; use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; @@ -784,6 +785,7 @@ impl GlobalStateSnapshot { cargo_toml: package_data.manifest.clone(), crate_id, package: cargo.package_flag(package_data), + package_id: package_data.id.clone(), target: target_data.name.clone(), target_kind: target_data.kind, required_features: target_data.required_features.clone(), @@ -812,6 +814,27 @@ impl GlobalStateSnapshot { None } + pub(crate) fn all_workspace_dependencies_for_package( + &self, + package: &Arc, + ) -> Option>> { + for workspace in self.workspaces.iter() { + match &workspace.kind { + ProjectWorkspaceKind::Cargo { cargo, .. } + | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => { + let package = cargo.packages().find(|p| cargo[*p].id == *package)?; + + return cargo[package] + .all_member_deps + .as_ref() + .map(|deps| deps.iter().map(|dep| cargo[*dep].id.clone()).collect()); + } + _ => {} + } + } + None + } + pub(crate) fn file_exists(&self, file_id: FileId) -> bool { self.vfs.read().0.exists(file_id) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 68c91a653940..87be09dcbd27 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -331,7 +331,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { let tgt_kind = it.target_kind(); let (tgt_name, root, package) = match it { - TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package), + TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package_id), _ => return None, }; @@ -368,7 +368,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { _ => false, }); if let Some(idx) = package_workspace_idx { - world.flycheck[idx].restart_for_package(package, target); + let workspace_deps = + world.all_workspace_dependencies_for_package(&package); + world.flycheck[idx].restart_for_package( + package, + target, + workspace_deps, + ); } } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index c6762f318326..3e80e8b7bdfb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -20,7 +20,7 @@ use crate::{ config::Config, diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics}, discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, - flycheck::{self, ClearDiagnosticsKind, FlycheckMessage}, + flycheck::{self, ClearDiagnosticsKind, ClearScope, FlycheckMessage}, global_state::{ FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, file_id_to_url, url_to_file_id, @@ -1042,17 +1042,22 @@ impl GlobalState { }; } } - FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => { - self.diagnostics.clear_check(id) - } FlycheckMessage::ClearDiagnostics { id, - kind: ClearDiagnosticsKind::OlderThan(generation), + kind: ClearDiagnosticsKind::All(ClearScope::Workspace), + } => self.diagnostics.clear_check(id), + FlycheckMessage::ClearDiagnostics { + id, + kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)), + } => self.diagnostics.clear_check_for_package(id, package_id), + FlycheckMessage::ClearDiagnostics { + id, + kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Workspace), } => self.diagnostics.clear_check_older_than(id, generation), FlycheckMessage::ClearDiagnostics { id, - kind: ClearDiagnosticsKind::Package(package_id), - } => self.diagnostics.clear_check_for_package(id, package_id), + kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Package(package_id)), + } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation), FlycheckMessage::Progress { id, progress } => { let (state, message) = match progress { flycheck::Progress::DidStart => (Progress::Begin, None), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 7132e09146eb..e532d155536c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -2,12 +2,14 @@ use std::mem; +use cargo_metadata::PackageId; use cfg::{CfgAtom, CfgExpr}; use hir::sym; use ide::{Cancellable, Crate, FileId, RunnableKind, TestId}; use project_model::project_json::Runnable; use project_model::{CargoFeatures, ManifestPath, TargetKind}; use rustc_hash::FxHashSet; +use triomphe::Arc; use vfs::AbsPathBuf; use crate::global_state::GlobalStateSnapshot; @@ -52,6 +54,7 @@ pub(crate) struct CargoTargetSpec { pub(crate) workspace_root: AbsPathBuf, pub(crate) cargo_toml: ManifestPath, pub(crate) package: String, + pub(crate) package_id: Arc, pub(crate) target: String, pub(crate) target_kind: TargetKind, pub(crate) crate_id: Crate, From 7eea65f8e0544d3e51ce383513c0108e9d02e874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 19 Sep 2025 10:57:03 +0200 Subject: [PATCH 072/537] Stop linking rs{begin,end} on x86_64-*-windows-gnu Until now, x86_64-pc-windows-gnu linked `rsbegin.o` and `rsend.o` just like i686-pc-windows-gnu, even though they were no-ops for it. This was likely done for the simplicity back when it was introduced. Today the things are different and these startup/end objects harm other features, like `build-std`. Given the demotion of i686-pc-windows-gnu from tier 1, there is no point in hurting x86_64-pc-windows-gnu, which remains a tier 1. The files are still shipped in case downstream crates expect them, as in case of the unmaintained `xargo`. --- .../rustc_target/src/spec/base/windows_gnu.rs | 3 --- compiler/rustc_target/src/spec/crt_objects.rs | 17 ++++++++++++++--- .../src/spec/targets/i686_pc_windows_gnu.rs | 8 +++++++- src/bootstrap/src/core/build_steps/compile.rs | 2 ++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index 4ba110219884..2867428e42f7 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -93,10 +93,7 @@ pub(crate) fn opts() -> TargetOptions { binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, - pre_link_objects: crt_objects::pre_mingw(), - post_link_objects: crt_objects::post_mingw(), pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(), - post_link_objects_self_contained: crt_objects::post_mingw_self_contained(), link_self_contained: LinkSelfContainedDefault::InferredForMingw, late_link_args, late_link_args_dynamic, diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs index e3b6430a4637..2d84e78f2557 100644 --- a/compiler/rustc_target/src/spec/crt_objects.rs +++ b/compiler/rustc_target/src/spec/crt_objects.rs @@ -85,6 +85,17 @@ pub(super) fn post_musl_self_contained() -> CrtObjects { } pub(super) fn pre_mingw_self_contained() -> CrtObjects { + new(&[ + (LinkOutputKind::DynamicNoPicExe, &["crt2.o"]), + (LinkOutputKind::DynamicPicExe, &["crt2.o"]), + (LinkOutputKind::StaticNoPicExe, &["crt2.o"]), + (LinkOutputKind::StaticPicExe, &["crt2.o"]), + (LinkOutputKind::DynamicDylib, &["dllcrt2.o"]), + (LinkOutputKind::StaticDylib, &["dllcrt2.o"]), + ]) +} + +pub(super) fn pre_i686_mingw_self_contained() -> CrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]), (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]), @@ -95,15 +106,15 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects { ]) } -pub(super) fn post_mingw_self_contained() -> CrtObjects { +pub(super) fn post_i686_mingw_self_contained() -> CrtObjects { all("rsend.o") } -pub(super) fn pre_mingw() -> CrtObjects { +pub(super) fn pre_i686_mingw() -> CrtObjects { all("rsbegin.o") } -pub(super) fn post_mingw() -> CrtObjects { +pub(super) fn post_i686_mingw() -> CrtObjects { all("rsend.o") } diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index e775c8fc524c..a0d403bd05e6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base}; +use crate::spec::{ + Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, crt_objects, +}; pub(crate) fn target() -> Target { let mut base = base::windows_gnu::opts(); @@ -15,6 +17,10 @@ pub(crate) fn target() -> Target { &["-m", "i386pe", "--large-address-aware"], ); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]); + base.pre_link_objects = crt_objects::pre_i686_mingw(); + base.post_link_objects = crt_objects::post_i686_mingw(); + base.pre_link_objects_self_contained = crt_objects::pre_i686_mingw_self_contained(); + base.post_link_objects_self_contained = crt_objects::post_i686_mingw_self_contained(); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 14104d7d1d78..6daf82d4e683 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -895,6 +895,8 @@ impl Step for StartupObjects { fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { let for_compiler = self.compiler; let target = self.target; + // Even though no longer necessary on x86_64, they are kept for now to + // avoid potential issues in downstream crates. if !target.is_windows_gnu() { return vec![]; } From e32b975e840e99748b947884505b74ebe4bd23b9 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 18 Sep 2025 14:23:43 -0400 Subject: [PATCH 073/537] tests: relax expectations after llvm change 902ddda120a5 LLVM 22 is able to drop assumes that seem to not help further optimizations, which actually seems to dramatically _help_ further optimizations in some of our small test cases. --- .../issues/issue-122600-ptr-discriminant-update.rs | 7 +++++-- tests/codegen-llvm/vec_pop_push_noop.rs | 5 ++++- tests/codegen-llvm/vecdeque_pop_push.rs | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs index 853a1ff36b10..631468d8c217 100644 --- a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs +++ b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs @@ -1,4 +1,7 @@ //@ compile-flags: -Copt-level=3 +//@ revisions: new old +//@ [old] ignore-llvm-version: 22 - 99 +//@ [new] min-llvm-version: 22 #![crate_type = "lib"] @@ -22,8 +25,8 @@ pub unsafe fn update(s: *mut State) { // CHECK-NOT: memcpy // CHECK-NOT: 75{{3|4}} - // CHECK: %[[TAG:.+]] = load i8, ptr %s, align 1 - // CHECK-NEXT: trunc nuw i8 %[[TAG]] to i1 + // old: %[[TAG:.+]] = load i8, ptr %s, align 1 + // old-NEXT: trunc nuw i8 %[[TAG]] to i1 // CHECK-NOT: load // CHECK-NOT: store diff --git a/tests/codegen-llvm/vec_pop_push_noop.rs b/tests/codegen-llvm/vec_pop_push_noop.rs index 3e375219fe01..fadc6e99dc7a 100644 --- a/tests/codegen-llvm/vec_pop_push_noop.rs +++ b/tests/codegen-llvm/vec_pop_push_noop.rs @@ -1,4 +1,7 @@ //@ compile-flags: -Copt-level=3 +//@ revisions: new old +//@ [old] ignore-llvm-version: 22 - 99 +//@ [new] min-llvm-version: 22 #![crate_type = "lib"] @@ -7,7 +10,7 @@ pub fn noop(v: &mut Vec) { // CHECK-NOT: grow_one // CHECK-NOT: call - // CHECK: tail call void @llvm.assume + // old: tail call void @llvm.assume // CHECK-NOT: grow_one // CHECK-NOT: call // CHECK: {{ret|[}]}} diff --git a/tests/codegen-llvm/vecdeque_pop_push.rs b/tests/codegen-llvm/vecdeque_pop_push.rs index 5afa1b2248b0..7886db3fedeb 100644 --- a/tests/codegen-llvm/vecdeque_pop_push.rs +++ b/tests/codegen-llvm/vecdeque_pop_push.rs @@ -1,4 +1,7 @@ //@ compile-flags: -Copt-level=3 +//@ revisions: new old +//@ [old] ignore-llvm-version: 22 - 99 +//@ [new] min-llvm-version: 22 #![crate_type = "lib"] @@ -8,7 +11,7 @@ use std::collections::VecDeque; // CHECK-LABEL: @noop_back( pub fn noop_back(v: &mut VecDeque) { // CHECK-NOT: grow - // CHECK: tail call void @llvm.assume + // old: tail call void @llvm.assume // CHECK-NOT: grow // CHECK: ret if let Some(x) = v.pop_back() { From 696add0d477a65d6a79d97c6b8e0f4ab9268bb89 Mon Sep 17 00:00:00 2001 From: sysrex <769991+sysrex@users.noreply.github.com> Date: Fri, 19 Sep 2025 19:04:48 +0100 Subject: [PATCH 074/537] chore: fixes #146756 --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aadc7c48ea83..5b52c3dfff61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,8 +31,8 @@ bootstrapping, the compiler architecture, source code representation, and more. ## [Getting help](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) -There are many ways you can get help when you're stuck. Rust has many platforms for this: -[internals], [rust-zulip], and [rust-discord]. It is recommended to ask for help on +There are many ways you can get help when you're stuck. Rust has two platforms for this: +[internals] and [rust-zulip]. It is recommended to ask for help on the [rust-zulip], but any of these platforms are great ways to seek help and even find a mentor! You can learn more about asking questions and getting help in the [Asking Questions](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) chapter of the [rustc-dev-guide]. From 82eed00d3979b74315f66201c6bf4d3f00d38c25 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 16 Sep 2025 01:48:24 -0600 Subject: [PATCH 075/537] chore(compiletest): Use newest anstyle-svg version --- Cargo.lock | 6 +++--- src/tools/compiletest/Cargo.toml | 2 +- tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg | 4 ++-- tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg | 4 ++-- tests/ui/diagnostic-flags/colored-session-opt-error.svg | 4 ++-- tests/ui/error-emitter/E0308-clarification.svg | 2 +- tests/ui/error-emitter/highlighting.svg | 2 +- tests/ui/error-emitter/highlighting.windows.svg | 2 +- tests/ui/error-emitter/multiline-multipart-suggestion.svg | 2 +- .../multiline-multipart-suggestion.windows.svg | 2 +- tests/ui/error-emitter/multiline-removal-suggestion.svg | 4 ++-- tests/ui/error-emitter/unicode-output.svg | 2 +- ...ht-difference-between-expected-trait-and-found-trait.svg | 4 ++-- tests/ui/suggestions/incorrect-variant-literal.svg | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d39cfefea0c7..71343a48be77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "anstyle-svg" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc03a770ef506fe1396c0e476120ac0e6523cf14b74218dd5f18cd6833326fa9" +checksum = "26b9ec8c976eada1b0f9747a3d7cc4eae3bef10613e443746e7487f26c872fde" dependencies = [ "anstyle", "anstyle-lossy", @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width 0.2.1", ] [[package]] diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index cdada5a22306..6597c3c70f69 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -12,7 +12,7 @@ path = "src/bin/main.rs" [dependencies] # tidy-alphabetical-start -anstyle-svg = "0.1.3" +anstyle-svg = "0.1.11" build_helper = { path = "../../build_helper" } camino = "1" colored = "2" diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg b/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg index 1cedbf75e4bf..7ffbc64b074b 100644 --- a/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg +++ b/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg @@ -1,7 +1,7 @@ - + u.field; &u.field; - &raw const u.field; + &raw const u.field; // this should be safe! let Union { field: _ }; // but not these From 1dcba116f57014454282f8cf0997682e3769003d Mon Sep 17 00:00:00 2001 From: "Igor S. Gerasimov" Date: Sun, 21 Sep 2025 04:19:10 +0200 Subject: [PATCH 096/537] Update list of good combinations (inc. beta + nightly) --- src/doc/rustc/src/linker-plugin-lto.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index ab95aa2e5a19..32e712a48d76 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -144,7 +144,7 @@ def minor_version(version): INSTALL_TOOLCHAIN = ["rustup", "toolchain", "install", "--profile", "minimal"] subprocess.run(INSTALL_TOOLCHAIN + ["nightly"]) -LOWER_BOUND = 73 +LOWER_BOUND = 87 NIGHTLY_VERSION = minor_version(subprocess.run( ["rustc", "+nightly", "--version"], capture_output=True, @@ -201,6 +201,9 @@ The following table shows known good combinations of toolchain versions. | 1.65 - 1.69 | 15 | | 1.70 - 1.72 | 16 | | 1.73 - 1.77 | 17 | -| 1.78 | 18 | +| 1.78 - 1.81 | 18 | +| 1.82 - 1.86 | 19 | +| 1.87 - 1.90 | 20 | +| 1.91 - 1.92 | 21 | Note that the compatibility policy for this feature might change in the future. From 1525bf3e8dcd1e800ec5602030bf01e39dcd6137 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 21 Sep 2025 11:00:00 +0800 Subject: [PATCH 097/537] Fix not applicable on trailing comma for remove_dbg `remove_dbg` not applicable for whitespaces after trailing comma Example --- ```rust fn foo() { dbg!( bar(), ); } ``` **Before this PR**: Assist not applicable **After this PR**: ```rust fn foo() { bar(); } ``` --- .../ide-assists/src/handlers/remove_dbg.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 414f6746d440..08779a3ed1f7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -83,7 +83,9 @@ fn compute_dbg_replacement( let input_expressions = input_expressions .into_iter() .filter_map(|(is_sep, group)| (!is_sep).then_some(group)) - .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""), Edition::CURRENT)) + .map(|tokens| tokens.collect::>()) + .filter(|tokens| !tokens.iter().all(|it| it.kind().is_trivia())) + .map(|tokens| syntax::hacks::parse_expr_from_str(&tokens.iter().join(""), Edition::CURRENT)) .collect::>>()?; let parent = macro_expr.syntax().parent()?; @@ -268,6 +270,8 @@ fn foo() { dbg!('x'); dbg!(&n); dbg!(n); + dbg!(n,); + dbg!(n, ); // needless comment dbg!("foo");$0 } @@ -281,6 +285,17 @@ fn foo() { ); } + #[test] + fn test_remove_trailing_comma_dbg() { + check("$0dbg!(1 + 1,)", "1 + 1"); + check("$0dbg!(1 + 1, )", "1 + 1"); + check("$0dbg!(1 + 1,\n)", "1 + 1"); + check("$0dbg!(1 + 1, 2 + 3)", "(1 + 1, 2 + 3)"); + check("$0dbg!(1 + 1, 2 + 3 )", "(1 + 1, 2 + 3)"); + check("$0dbg!(1 + 1, 2 + 3, )", "(1 + 1, 2 + 3)"); + check("$0dbg!(1 + 1, 2 + 3 ,)", "(1 + 1, 2 + 3)"); + } + #[test] fn test_remove_dbg_not_applicable() { check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}"); From b441b801fa72dac0886b98dc68b02993dc07649e Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sun, 21 Sep 2025 11:43:36 +0800 Subject: [PATCH 098/537] fix a crash in rustdoc merge finalize without input file --- src/librustdoc/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9871066b9eb5..904972f52d01 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -835,8 +835,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { config::InputMode::NoInputMergeFinalize => { return wrap_return( dcx, - run_merge_finalize(render_options) - .map_err(|e| format!("could not write merged cross-crate info: {e}")), + rustc_span::create_session_globals_then(options.edition, &[], None, || { + run_merge_finalize(render_options) + .map_err(|e| format!("could not write merged cross-crate info: {e}")) + }), ); } }; From f4b876867d609404be8a78220c0d5117303bb0f8 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 21 Sep 2025 13:48:22 +0900 Subject: [PATCH 099/537] Support ctr and lr as clobber-only registers in PowerPC inline assembly --- compiler/rustc_codegen_gcc/src/asm.rs | 16 +- compiler/rustc_codegen_llvm/src/asm.rs | 14 +- compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_target/src/asm/mod.rs | 5 +- compiler/rustc_target/src/asm/powerpc.rs | 12 +- .../asm-experimental-arch.md | 6 +- tests/codegen-llvm/asm/powerpc-clobbers.rs | 8 +- tests/ui/asm/powerpc/bad-reg.aix64.stderr | 162 ++++++++++++---- tests/ui/asm/powerpc/bad-reg.powerpc.stderr | 176 +++++++++++++----- tests/ui/asm/powerpc/bad-reg.powerpc64.stderr | 168 ++++++++++++----- .../ui/asm/powerpc/bad-reg.powerpc64le.stderr | 162 ++++++++++++---- tests/ui/asm/powerpc/bad-reg.rs | 30 ++- 12 files changed, 572 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 17e2e028b16f..a14881c502cf 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -698,8 +698,12 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -777,8 +781,12 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { cx.type_vector(cx.type_i32(), 4) } - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b79176e90981..197ca7e0ba66 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -662,7 +662,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", PowerPC(PowerPCInlineAsmRegClass::freg) => "f", PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -830,7 +835,12 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4), - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fef65f46b1f..a6ae58f87dcc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -794,6 +794,7 @@ symbols! { ctlz, ctlz_nonzero, ctpop, + ctr, cttz, cttz_nonzero, custom_attribute, @@ -1333,6 +1334,7 @@ symbols! { loongarch_target_feature, loop_break_value, loop_match, + lr, lt, m68k_target_feature, macro_at_most_once_rep, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index e06f881e4b1c..0601613567ea 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -1260,11 +1260,12 @@ impl InlineAsmClobberAbi { v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - // cr0-cr1, cr5-cr7, xer + // cr0-cr1, cr5-cr7, ctr, lr, xer cr0, cr1, cr5, cr6, cr7, + ctr, + lr, xer, - // lr and ctr are reserved } }, InlineAsmClobberAbi::S390x => clobbered_regs! { diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index f3934afa6d94..2348a0fd202e 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -13,6 +13,8 @@ def_reg_class! { freg, vreg, cr, + ctr, + lr, xer, } } @@ -56,7 +58,7 @@ impl PowerPCInlineAsmRegClass { altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4); vsx: F32, F64, VecI64(2), VecF64(2); }, - Self::cr | Self::xer => &[], + Self::cr | Self::ctr | Self::lr | Self::xer => &[], } } } @@ -195,6 +197,8 @@ def_regs! { cr5: cr = ["cr5"], cr6: cr = ["cr6"], cr7: cr = ["cr7"], + ctr: ctr = ["ctr"], + lr: lr = ["lr"], xer: xer = ["xer"], #error = ["r1", "1", "sp"] => "the stack pointer cannot be used as an operand for inline asm", @@ -206,10 +210,6 @@ def_regs! { "r30 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r31", "31", "fp"] => "the frame pointer cannot be used as an operand for inline asm", - #error = ["lr"] => - "the link register cannot be used as an operand for inline asm", - #error = ["ctr"] => - "the counter register cannot be used as an operand for inline asm", #error = ["vrsave"] => "the vrsave register cannot be used as an operand for inline asm", } @@ -247,6 +247,8 @@ impl PowerPCInlineAsmReg { (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31"); (cr, "cr"); (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); + (ctr, "ctr"); + (lr, "lr"); (xer, "xer"); } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index d9566c9f55c5..9434868dc08e 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -36,6 +36,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `freg` | `f[0-31]` | `f` | | PowerPC | `vreg` | `v[0-31]` | `v` | | PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | +| PowerPC | `ctr` | `ctr` | Only clobbers | +| PowerPC | `lr` | `lr` | Only clobbers | | PowerPC | `xer` | `xer` | Only clobbers | | wasm32 | `local` | None\* | `r` | | BPF | `reg` | `r[0-10]` | `r` | @@ -78,6 +80,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `vreg` | `altivec` | `i8x16`, `i16x8`, `i32x4`, `f32x4` | | PowerPC | `vreg` | `vsx` | `f32`, `f64`, `i64x2`, `f64x2` | | PowerPC | `cr` | N/A | Only clobbers | +| PowerPC | `ctr` | N/A | Only clobbers | +| PowerPC | `lr` | N/A | Only clobbers | | PowerPC | `xer` | N/A | Only clobbers | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | | BPF | `reg` | None | `i8` `i16` `i32` `i64` | @@ -150,8 +154,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | | PowerPC | `r2`, `r13` | These are system reserved registers. | -| PowerPC | `lr` | The link register cannot be used as an input or output. | -| PowerPC | `ctr` | The counter register cannot be used as an input or output. | | PowerPC | `vrsave` | The vrsave register cannot be used as an input or output. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs index f7fc7eea5d50..10d7ae4dba40 100644 --- a/tests/codegen-llvm/asm/powerpc-clobbers.rs +++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs @@ -58,10 +58,10 @@ pub unsafe fn v0_clobber() { // Output format depends on the availability of altivec. // CHECK-LABEL: @clobber_abi -// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() -// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() +// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"() #[no_mangle] pub unsafe fn clobber_abi() { asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr index 124013f89afa..82faba8d167f 100644 --- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr @@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for LL | asm!("", out("fp") _); | ^^^^^^^^^^^ -error: invalid register `lr`: the link register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 - | -LL | asm!("", out("lr") _); - | ^^^^^^^^^^^ - -error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:50:18 - | -LL | asm!("", out("ctr") _); - | ^^^^^^^^^^^^ - error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:52:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:96:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:103:18 + --> $DIR/bad-reg.rs:99:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:106:26 + --> $DIR/bad-reg.rs:102:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:109:26 + --> $DIR/bad-reg.rs:105:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:109:18 + | +LL | asm!("", in("ctr") x); + | ^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:112:18 + | +LL | asm!("", out("ctr") x); + | ^^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:115:26 + | +LL | asm!("/* {} */", in(ctr) x); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:118:26 + | +LL | asm!("/* {} */", out(ctr) _); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:122:18 + | +LL | asm!("", in("lr") x); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:125:18 + | +LL | asm!("", out("lr") x); + | ^^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:128:26 + | +LL | asm!("/* {} */", in(lr) x); + | ^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:131:26 + | +LL | asm!("/* {} */", out(lr) _); + | ^^^^^^^^^ + error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:113:18 + --> $DIR/bad-reg.rs:135:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:116:18 + --> $DIR/bad-reg.rs:138:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:119:26 + --> $DIR/bad-reg.rs:141:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:122:26 + --> $DIR/bad-reg.rs:144:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:126:31 + --> $DIR/bad-reg.rs:148:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -103,7 +139,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:128:31 + --> $DIR/bad-reg.rs:150:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -111,7 +147,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:130:31 + --> $DIR/bad-reg.rs:152:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -119,7 +155,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:132:31 + --> $DIR/bad-reg.rs:154:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -127,7 +163,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:134:31 + --> $DIR/bad-reg.rs:156:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -135,7 +171,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:136:31 + --> $DIR/bad-reg.rs:158:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -143,7 +179,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:138:31 + --> $DIR/bad-reg.rs:160:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -151,7 +187,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:140:31 + --> $DIR/bad-reg.rs:162:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -165,7 +201,7 @@ LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:67:27 + --> $DIR/bad-reg.rs:63:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -173,7 +209,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:70:28 + --> $DIR/bad-reg.rs:66:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -181,7 +217,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:78:35 + --> $DIR/bad-reg.rs:74:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -189,7 +225,7 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:100:27 + --> $DIR/bad-reg.rs:96:27 | LL | asm!("", in("cr") x); | ^ @@ -197,7 +233,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:103:28 + --> $DIR/bad-reg.rs:99:28 | LL | asm!("", out("cr") x); | ^ @@ -205,7 +241,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:106:33 + --> $DIR/bad-reg.rs:102:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -213,7 +249,55 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:113:28 + --> $DIR/bad-reg.rs:109:28 + | +LL | asm!("", in("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:112:29 + | +LL | asm!("", out("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:115:34 + | +LL | asm!("/* {} */", in(ctr) x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:122:27 + | +LL | asm!("", in("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:125:28 + | +LL | asm!("", out("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:128:33 + | +LL | asm!("/* {} */", in(lr) x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:135:28 | LL | asm!("", in("xer") x); | ^ @@ -221,7 +305,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:116:29 + --> $DIR/bad-reg.rs:138:29 | LL | asm!("", out("xer") x); | ^ @@ -229,12 +313,12 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:119:34 + --> $DIR/bad-reg.rs:141:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 34 previous errors +error: aborting due to 46 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr index b11c946f80da..fac70ea77cb3 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr @@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for LL | asm!("", out("fp") _); | ^^^^^^^^^^^ -error: invalid register `lr`: the link register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 - | -LL | asm!("", out("lr") _); - | ^^^^^^^^^^^ - -error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:50:18 - | -LL | asm!("", out("ctr") _); - | ^^^^^^^^^^^^ - error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:52:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:96:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:103:18 + --> $DIR/bad-reg.rs:99:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:106:26 + --> $DIR/bad-reg.rs:102:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:109:26 + --> $DIR/bad-reg.rs:105:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:109:18 + | +LL | asm!("", in("ctr") x); + | ^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:112:18 + | +LL | asm!("", out("ctr") x); + | ^^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:115:26 + | +LL | asm!("/* {} */", in(ctr) x); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:118:26 + | +LL | asm!("/* {} */", out(ctr) _); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:122:18 + | +LL | asm!("", in("lr") x); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:125:18 + | +LL | asm!("", out("lr") x); + | ^^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:128:26 + | +LL | asm!("/* {} */", in(lr) x); + | ^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:131:26 + | +LL | asm!("/* {} */", out(lr) _); + | ^^^^^^^^^ + error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:113:18 + --> $DIR/bad-reg.rs:135:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:116:18 + --> $DIR/bad-reg.rs:138:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:119:26 + --> $DIR/bad-reg.rs:141:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:122:26 + --> $DIR/bad-reg.rs:144:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:126:31 + --> $DIR/bad-reg.rs:148:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -103,7 +139,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:128:31 + --> $DIR/bad-reg.rs:150:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -111,7 +147,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:130:31 + --> $DIR/bad-reg.rs:152:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -119,7 +155,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:132:31 + --> $DIR/bad-reg.rs:154:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -127,7 +163,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:134:31 + --> $DIR/bad-reg.rs:156:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -135,7 +171,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:136:31 + --> $DIR/bad-reg.rs:158:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -143,7 +179,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:138:31 + --> $DIR/bad-reg.rs:160:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -151,7 +187,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:140:31 + --> $DIR/bad-reg.rs:162:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -165,67 +201,67 @@ LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:57:18 + --> $DIR/bad-reg.rs:53:18 | LL | asm!("", in("v0") v32x4); // requires altivec | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:59:18 + --> $DIR/bad-reg.rs:55:18 | LL | asm!("", out("v0") v32x4); // requires altivec | ^^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:61:18 + --> $DIR/bad-reg.rs:57:18 | LL | asm!("", in("v0") v64x2); // requires vsx | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:64:18 + --> $DIR/bad-reg.rs:60:18 | LL | asm!("", out("v0") v64x2); // requires vsx | ^^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:67:18 + --> $DIR/bad-reg.rs:63:18 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:70:18 + --> $DIR/bad-reg.rs:66:18 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:73:26 + --> $DIR/bad-reg.rs:69:26 | LL | asm!("/* {} */", in(vreg) v32x4); // requires altivec | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:75:26 + --> $DIR/bad-reg.rs:71:26 | LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx | ^^^^^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:78:26 + --> $DIR/bad-reg.rs:74:26 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^^^^^^^^^^ error: register class `vreg` requires at least one of the following target features: altivec, vsx - --> $DIR/bad-reg.rs:81:26 + --> $DIR/bad-reg.rs:77:26 | LL | asm!("/* {} */", out(vreg) _); // requires altivec | ^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:100:27 + --> $DIR/bad-reg.rs:96:27 | LL | asm!("", in("cr") x); | ^ @@ -233,7 +269,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:103:28 + --> $DIR/bad-reg.rs:99:28 | LL | asm!("", out("cr") x); | ^ @@ -241,7 +277,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:106:33 + --> $DIR/bad-reg.rs:102:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -249,7 +285,55 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:113:28 + --> $DIR/bad-reg.rs:109:28 + | +LL | asm!("", in("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:112:29 + | +LL | asm!("", out("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:115:34 + | +LL | asm!("/* {} */", in(ctr) x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:122:27 + | +LL | asm!("", in("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:125:28 + | +LL | asm!("", out("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:128:33 + | +LL | asm!("/* {} */", in(lr) x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:135:28 | LL | asm!("", in("xer") x); | ^ @@ -257,7 +341,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:116:29 + --> $DIR/bad-reg.rs:138:29 | LL | asm!("", out("xer") x); | ^ @@ -265,12 +349,12 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:119:34 + --> $DIR/bad-reg.rs:141:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 41 previous errors +error: aborting due to 53 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr index a93b2b018df0..42a59448f425 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr @@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for LL | asm!("", out("fp") _); | ^^^^^^^^^^^ -error: invalid register `lr`: the link register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 - | -LL | asm!("", out("lr") _); - | ^^^^^^^^^^^ - -error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:50:18 - | -LL | asm!("", out("ctr") _); - | ^^^^^^^^^^^^ - error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:52:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:96:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:103:18 + --> $DIR/bad-reg.rs:99:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:106:26 + --> $DIR/bad-reg.rs:102:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:109:26 + --> $DIR/bad-reg.rs:105:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:109:18 + | +LL | asm!("", in("ctr") x); + | ^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:112:18 + | +LL | asm!("", out("ctr") x); + | ^^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:115:26 + | +LL | asm!("/* {} */", in(ctr) x); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:118:26 + | +LL | asm!("/* {} */", out(ctr) _); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:122:18 + | +LL | asm!("", in("lr") x); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:125:18 + | +LL | asm!("", out("lr") x); + | ^^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:128:26 + | +LL | asm!("/* {} */", in(lr) x); + | ^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:131:26 + | +LL | asm!("/* {} */", out(lr) _); + | ^^^^^^^^^ + error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:113:18 + --> $DIR/bad-reg.rs:135:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:116:18 + --> $DIR/bad-reg.rs:138:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:119:26 + --> $DIR/bad-reg.rs:141:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:122:26 + --> $DIR/bad-reg.rs:144:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:126:31 + --> $DIR/bad-reg.rs:148:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -103,7 +139,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:128:31 + --> $DIR/bad-reg.rs:150:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -111,7 +147,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:130:31 + --> $DIR/bad-reg.rs:152:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -119,7 +155,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:132:31 + --> $DIR/bad-reg.rs:154:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -127,7 +163,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:134:31 + --> $DIR/bad-reg.rs:156:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -135,7 +171,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:136:31 + --> $DIR/bad-reg.rs:158:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -143,7 +179,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:138:31 + --> $DIR/bad-reg.rs:160:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -151,7 +187,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:140:31 + --> $DIR/bad-reg.rs:162:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -165,7 +201,7 @@ LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:61:27 + --> $DIR/bad-reg.rs:57:27 | LL | asm!("", in("v0") v64x2); // requires vsx | ^^^^^ @@ -173,7 +209,7 @@ LL | asm!("", in("v0") v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:64:28 + --> $DIR/bad-reg.rs:60:28 | LL | asm!("", out("v0") v64x2); // requires vsx | ^^^^^ @@ -181,7 +217,7 @@ LL | asm!("", out("v0") v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:67:27 + --> $DIR/bad-reg.rs:63:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -189,7 +225,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:70:28 + --> $DIR/bad-reg.rs:66:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -197,7 +233,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: `vsx` target feature is not enabled - --> $DIR/bad-reg.rs:75:35 + --> $DIR/bad-reg.rs:71:35 | LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx | ^^^^^ @@ -205,7 +241,7 @@ LL | asm!("/* {} */", in(vreg) v64x2); // requires vsx = note: this is required to use type `i64x2` with register class `vreg` error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:78:35 + --> $DIR/bad-reg.rs:74:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -213,7 +249,7 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:100:27 + --> $DIR/bad-reg.rs:96:27 | LL | asm!("", in("cr") x); | ^ @@ -221,7 +257,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:103:28 + --> $DIR/bad-reg.rs:99:28 | LL | asm!("", out("cr") x); | ^ @@ -229,7 +265,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:106:33 + --> $DIR/bad-reg.rs:102:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -237,7 +273,55 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:113:28 + --> $DIR/bad-reg.rs:109:28 + | +LL | asm!("", in("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:112:29 + | +LL | asm!("", out("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:115:34 + | +LL | asm!("/* {} */", in(ctr) x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:122:27 + | +LL | asm!("", in("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:125:28 + | +LL | asm!("", out("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:128:33 + | +LL | asm!("/* {} */", in(lr) x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:135:28 | LL | asm!("", in("xer") x); | ^ @@ -245,7 +329,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:116:29 + --> $DIR/bad-reg.rs:138:29 | LL | asm!("", out("xer") x); | ^ @@ -253,12 +337,12 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:119:34 + --> $DIR/bad-reg.rs:141:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 37 previous errors +error: aborting due to 49 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr index 124013f89afa..82faba8d167f 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr @@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for LL | asm!("", out("fp") _); | ^^^^^^^^^^^ -error: invalid register `lr`: the link register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:48:18 - | -LL | asm!("", out("lr") _); - | ^^^^^^^^^^^ - -error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:50:18 - | -LL | asm!("", out("ctr") _); - | ^^^^^^^^^^^^ - error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:52:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", out("vrsave") _); | ^^^^^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:100:18 + --> $DIR/bad-reg.rs:96:18 | LL | asm!("", in("cr") x); | ^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:103:18 + --> $DIR/bad-reg.rs:99:18 | LL | asm!("", out("cr") x); | ^^^^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:106:26 + --> $DIR/bad-reg.rs:102:26 | LL | asm!("/* {} */", in(cr) x); | ^^^^^^^^ error: register class `cr` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:109:26 + --> $DIR/bad-reg.rs:105:26 | LL | asm!("/* {} */", out(cr) _); | ^^^^^^^^^ +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:109:18 + | +LL | asm!("", in("ctr") x); + | ^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:112:18 + | +LL | asm!("", out("ctr") x); + | ^^^^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:115:26 + | +LL | asm!("/* {} */", in(ctr) x); + | ^^^^^^^^^ + +error: register class `ctr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:118:26 + | +LL | asm!("/* {} */", out(ctr) _); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:122:18 + | +LL | asm!("", in("lr") x); + | ^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:125:18 + | +LL | asm!("", out("lr") x); + | ^^^^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:128:26 + | +LL | asm!("/* {} */", in(lr) x); + | ^^^^^^^^ + +error: register class `lr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:131:26 + | +LL | asm!("/* {} */", out(lr) _); + | ^^^^^^^^^ + error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:113:18 + --> $DIR/bad-reg.rs:135:18 | LL | asm!("", in("xer") x); | ^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:116:18 + --> $DIR/bad-reg.rs:138:18 | LL | asm!("", out("xer") x); | ^^^^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:119:26 + --> $DIR/bad-reg.rs:141:26 | LL | asm!("/* {} */", in(xer) x); | ^^^^^^^^^ error: register class `xer` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:122:26 + --> $DIR/bad-reg.rs:144:26 | LL | asm!("/* {} */", out(xer) _); | ^^^^^^^^^^ error: register `cr0` conflicts with register `cr` - --> $DIR/bad-reg.rs:126:31 + --> $DIR/bad-reg.rs:148:31 | LL | asm!("", out("cr") _, out("cr0") _); | ----------- ^^^^^^^^^^^^ register `cr0` @@ -103,7 +139,7 @@ LL | asm!("", out("cr") _, out("cr0") _); | register `cr` error: register `cr1` conflicts with register `cr` - --> $DIR/bad-reg.rs:128:31 + --> $DIR/bad-reg.rs:150:31 | LL | asm!("", out("cr") _, out("cr1") _); | ----------- ^^^^^^^^^^^^ register `cr1` @@ -111,7 +147,7 @@ LL | asm!("", out("cr") _, out("cr1") _); | register `cr` error: register `cr2` conflicts with register `cr` - --> $DIR/bad-reg.rs:130:31 + --> $DIR/bad-reg.rs:152:31 | LL | asm!("", out("cr") _, out("cr2") _); | ----------- ^^^^^^^^^^^^ register `cr2` @@ -119,7 +155,7 @@ LL | asm!("", out("cr") _, out("cr2") _); | register `cr` error: register `cr3` conflicts with register `cr` - --> $DIR/bad-reg.rs:132:31 + --> $DIR/bad-reg.rs:154:31 | LL | asm!("", out("cr") _, out("cr3") _); | ----------- ^^^^^^^^^^^^ register `cr3` @@ -127,7 +163,7 @@ LL | asm!("", out("cr") _, out("cr3") _); | register `cr` error: register `cr4` conflicts with register `cr` - --> $DIR/bad-reg.rs:134:31 + --> $DIR/bad-reg.rs:156:31 | LL | asm!("", out("cr") _, out("cr4") _); | ----------- ^^^^^^^^^^^^ register `cr4` @@ -135,7 +171,7 @@ LL | asm!("", out("cr") _, out("cr4") _); | register `cr` error: register `cr5` conflicts with register `cr` - --> $DIR/bad-reg.rs:136:31 + --> $DIR/bad-reg.rs:158:31 | LL | asm!("", out("cr") _, out("cr5") _); | ----------- ^^^^^^^^^^^^ register `cr5` @@ -143,7 +179,7 @@ LL | asm!("", out("cr") _, out("cr5") _); | register `cr` error: register `cr6` conflicts with register `cr` - --> $DIR/bad-reg.rs:138:31 + --> $DIR/bad-reg.rs:160:31 | LL | asm!("", out("cr") _, out("cr6") _); | ----------- ^^^^^^^^^^^^ register `cr6` @@ -151,7 +187,7 @@ LL | asm!("", out("cr") _, out("cr6") _); | register `cr` error: register `cr7` conflicts with register `cr` - --> $DIR/bad-reg.rs:140:31 + --> $DIR/bad-reg.rs:162:31 | LL | asm!("", out("cr") _, out("cr7") _); | ----------- ^^^^^^^^^^^^ register `cr7` @@ -165,7 +201,7 @@ LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:67:27 + --> $DIR/bad-reg.rs:63:27 | LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -173,7 +209,7 @@ LL | asm!("", in("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:70:28 + --> $DIR/bad-reg.rs:66:28 | LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available | ^ @@ -181,7 +217,7 @@ LL | asm!("", out("v0") x); // FIXME: should be ok if vsx is available = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:78:35 + --> $DIR/bad-reg.rs:74:35 | LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available | ^ @@ -189,7 +225,7 @@ LL | asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:100:27 + --> $DIR/bad-reg.rs:96:27 | LL | asm!("", in("cr") x); | ^ @@ -197,7 +233,7 @@ LL | asm!("", in("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:103:28 + --> $DIR/bad-reg.rs:99:28 | LL | asm!("", out("cr") x); | ^ @@ -205,7 +241,7 @@ LL | asm!("", out("cr") x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:106:33 + --> $DIR/bad-reg.rs:102:33 | LL | asm!("/* {} */", in(cr) x); | ^ @@ -213,7 +249,55 @@ LL | asm!("/* {} */", in(cr) x); = note: register class `cr` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:113:28 + --> $DIR/bad-reg.rs:109:28 + | +LL | asm!("", in("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:112:29 + | +LL | asm!("", out("ctr") x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:115:34 + | +LL | asm!("/* {} */", in(ctr) x); + | ^ + | + = note: register class `ctr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:122:27 + | +LL | asm!("", in("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:125:28 + | +LL | asm!("", out("lr") x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:128:33 + | +LL | asm!("/* {} */", in(lr) x); + | ^ + | + = note: register class `lr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:135:28 | LL | asm!("", in("xer") x); | ^ @@ -221,7 +305,7 @@ LL | asm!("", in("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:116:29 + --> $DIR/bad-reg.rs:138:29 | LL | asm!("", out("xer") x); | ^ @@ -229,12 +313,12 @@ LL | asm!("", out("xer") x); = note: register class `xer` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:119:34 + --> $DIR/bad-reg.rs:141:34 | LL | asm!("/* {} */", in(xer) x); | ^ | = note: register class `xer` supports these types: -error: aborting due to 34 previous errors +error: aborting due to 46 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs index 5598f8379603..21ea451934ed 100644 --- a/tests/ui/asm/powerpc/bad-reg.rs +++ b/tests/ui/asm/powerpc/bad-reg.rs @@ -45,10 +45,6 @@ fn f() { //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("fp") _); //~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm - asm!("", out("lr") _); - //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm - asm!("", out("ctr") _); - //~^ ERROR invalid register `ctr`: the counter register cannot be used as an operand for inline asm asm!("", out("vrsave") _); //~^ ERROR invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm @@ -108,6 +104,32 @@ fn f() { //~| ERROR type `i32` cannot be used with this register class asm!("/* {} */", out(cr) _); //~^ ERROR can only be used as a clobber + // ctr + asm!("", out("ctr") _); // ok + asm!("", in("ctr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("ctr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(ctr) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(ctr) _); + //~^ ERROR can only be used as a clobber + // lr + asm!("", out("lr") _); // ok + asm!("", in("lr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("lr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(lr) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(lr) _); + //~^ ERROR can only be used as a clobber // xer asm!("", out("xer") _); // ok asm!("", in("xer") x); From b17fb70d0437b90fc9ada0ac2d924cce06eb8828 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 21 Sep 2025 20:50:44 +1000 Subject: [PATCH 100/537] Add self-profile events for target-machine creation These code paths are surprisingly hot in the `large-workspace` benchmark; it would be handy to see some detailed timings and execution counts. --- compiler/rustc_codegen_llvm/src/back/write.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c4881f0aafc8..1950b8288d14 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -204,6 +204,9 @@ pub(crate) fn target_machine_factory( optlvl: config::OptLevel, target_features: &[String], ) -> TargetMachineFactoryFn { + // Self-profile timer for creating a _factory_. + let _prof_timer = sess.prof.generic_activity("target_machine_factory"); + let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); @@ -259,6 +262,9 @@ pub(crate) fn target_machine_factory( .into_string() .unwrap_or_default(); let command_line_args = quote_command_line_args(&sess.expanded_args); + // Self-profile counter for the number of bytes produced by command-line quoting. + // Values are summed, so the summary result is cumulative across all TM factories. + sess.prof.artifact_size("quoted_command_line_args", "-", command_line_args.len() as u64); let debuginfo_compression = sess.opts.debuginfo_compression.to_string(); match sess.opts.debuginfo_compression { @@ -281,7 +287,11 @@ pub(crate) fn target_machine_factory( let use_wasm_eh = wants_wasm_eh(sess); + let prof = SelfProfilerRef::clone(&sess.prof); Arc::new(move |config: TargetMachineFactoryConfig| { + // Self-profile timer for invoking a factory to create a target machine. + let _prof_timer = prof.generic_activity("target_machine_factory_inner"); + let path_to_cstring_helper = |path: Option| -> CString { let path = path.unwrap_or_default(); let path = path_mapping From 2dfcd0948e0dc1608a04e35d2f1812a21cf45b7a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 21 Sep 2025 12:05:09 +0000 Subject: [PATCH 101/537] btree InternalNode::new safety comments --- library/alloc/src/collections/btree/node.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index b233e1740b7b..2b8103c8b778 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -117,10 +117,11 @@ impl InternalNode { /// initialized and valid edge. This function does not set up /// such an edge. unsafe fn new(alloc: A) -> Box { + let mut node = Box::::new_uninit_in(alloc); unsafe { - let mut node = Box::::new_uninit_in(alloc); - // We only need to initialize the data; the edges are MaybeUninit. + // SAFETY: argument points to the `node.data` `LeafNode` LeafNode::init(&raw mut (*node.as_mut_ptr()).data); + // SAFETY: `node.data` was just initialized and `node.edges` is MaybeUninit. node.assume_init() } } From 1bc19932e6f0a5ce098af6f3d59e28a61abbc631 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 15 Sep 2025 19:08:55 +0530 Subject: [PATCH 102/537] make cargo test work for bootstrap self test --- src/bootstrap/src/core/config/config.rs | 24 ++++----- src/bootstrap/src/core/config/tests.rs | 62 ++---------------------- src/bootstrap/src/utils/helpers/tests.rs | 4 +- 3 files changed, 17 insertions(+), 73 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index dd2d5a1fd533..19fcaeaaa24d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -630,19 +630,9 @@ impl Config { let llvm_assertions = llvm_assertions.unwrap_or(false); let mut target_config = HashMap::new(); let mut channel = "dev".to_string(); - let out = flags_build_dir.or(build_build_dir.map(PathBuf::from)).unwrap_or_else(|| { - if cfg!(test) { - // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. - Path::new( - &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), - ) - .parent() - .unwrap() - .to_path_buf() - } else { - PathBuf::from("build") - } - }); + let out = flags_build_dir + .or(build_build_dir.map(PathBuf::from)) + .unwrap_or_else(|| PathBuf::from("build")); // NOTE: Bootstrap spawns various commands with different working directories. // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. @@ -693,8 +683,14 @@ impl Config { }; let initial_rustc = build_rustc.unwrap_or_else(|| { + let out = if cfg!(test) { Path::new("../../build").to_path_buf() } else { out.clone() }; + download_beta_toolchain(&dwn_ctx, &out); - out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) + + out.join(if cfg!(test) { get_host_target() } else { host_target }) + .join("stage0") + .join("bin") + .join(exe("rustc", host_target)) }); let initial_sysroot = t!(PathBuf::from_str( diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index e93525fbd09c..46d05fbc0686 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -39,7 +39,11 @@ fn prepare_test_specific_dir() -> PathBuf { // Replace "::" with "_" to make it safe for directory names on Windows systems let test_path = current.name().unwrap().replace("::", "_"); - let testdir = parse("").tempdir().join(test_path); + let testdir = crate::utils::tests::TestCtx::new() + .config("check") + .create_config() + .tempdir() + .join(test_path); // clean up any old test files let _ = fs::remove_dir_all(&testdir); @@ -64,62 +68,6 @@ fn download_ci_llvm() { } } -// FIXME(onur-ozkan): extend scope of the test -// refs: -// - https://github.com/rust-lang/rust/issues/109120 -// - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487 -#[test] -fn detect_src_and_out() { - fn test(cfg: Config, build_dir: Option<&str>) { - // This will bring absolute form of `src/bootstrap` path - let current_dir = std::env::current_dir().unwrap(); - - // get `src` by moving into project root path - let expected_src = current_dir.ancestors().nth(2).unwrap(); - assert_eq!(&cfg.src, expected_src); - - // Sanity check for `src` - let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - let expected_src = manifest_dir.ancestors().nth(2).unwrap(); - assert_eq!(&cfg.src, expected_src); - - // test if build-dir was manually given in bootstrap.toml - if let Some(custom_build_dir) = build_dir { - assert_eq!(&cfg.out, Path::new(custom_build_dir)); - } - // test the native bootstrap way - else { - // This should bring output path of bootstrap in absolute form - let cargo_target_dir = env::var_os("CARGO_TARGET_DIR").expect( - "CARGO_TARGET_DIR must been provided for the test environment from bootstrap", - ); - - // Move to `build` from `build/bootstrap` - let expected_out = Path::new(&cargo_target_dir).parent().unwrap(); - assert_eq!(&cfg.out, expected_out); - - let args: Vec = env::args().collect(); - - // Another test for `out` as a sanity check - // - // This will bring something similar to: - // `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804` - // `{build-dir}` can be anywhere, not just in the rust project directory. - let dep = Path::new(args.first().unwrap()); - let expected_out = dep.ancestors().nth(5).unwrap(); - - assert_eq!(&cfg.out, expected_out); - } - } - - test(parse(""), None); - - { - let build_dir = if cfg!(windows) { "C:\\tmp" } else { "/tmp" }; - test(parse(&format!("build.build-dir = '{build_dir}'")), Some(build_dir)); - } -} - #[test] fn clap_verify() { Flags::command().debug_assert(); diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index 9030ca2820a8..e586fe77b4f6 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -6,6 +6,7 @@ use crate::utils::helpers::{ check_cfg_arg, extract_beta_rev, hex_encode, make, set_file_times, submodule_path_of, symlink_dir, }; +use crate::utils::tests::TestCtx; use crate::{Config, Flags}; #[test] @@ -80,8 +81,7 @@ fn test_symlink_dir() { #[test] fn test_set_file_times_sanity_check() { - let config = - Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()])); + let config = TestCtx::new().config("check").create_config(); let tempfile = config.tempdir().join(".tmp-file"); { From a12969e0d10387ad17755879e98cf5097a937473 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 15 Sep 2025 19:20:05 +0530 Subject: [PATCH 103/537] walk up the ancestors --- src/bootstrap/src/core/config/config.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 19fcaeaaa24d..003cf3f2f9c3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -683,14 +683,15 @@ impl Config { }; let initial_rustc = build_rustc.unwrap_or_else(|| { - let out = if cfg!(test) { Path::new("../../build").to_path_buf() } else { out.clone() }; - + let out = if cfg!(test) { + std::env::current_dir().unwrap().ancestors().nth(2).unwrap().join("build") + } else { + out.clone() + }; download_beta_toolchain(&dwn_ctx, &out); + let target = if cfg!(test) { get_host_target() } else { host_target }; - out.join(if cfg!(test) { get_host_target() } else { host_target }) - .join("stage0") - .join("bin") - .join(exe("rustc", host_target)) + out.join(target).join("stage0").join("bin").join(exe("rustc", host_target)) }); let initial_sysroot = t!(PathBuf::from_str( From 6c79f547f9ecf72ff8b9748dc0001d92217dff71 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:16:29 +0530 Subject: [PATCH 104/537] add an API in ConfigBuilder to point to config file for toml parsing --- src/bootstrap/src/utils/tests/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 3332187e2a85..ff84bfdb4cde 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -98,6 +98,14 @@ impl ConfigBuilder { self } + pub fn config_toml(mut self, config_toml: &str) -> Self { + let toml_path = self.directory.join("bootstrap.toml"); + std::fs::write(&toml_path, config_toml).unwrap(); + self.args.push("--config".to_string()); + self.args.push(toml_path.display().to_string()); + self + } + pub fn create_config(mut self) -> Config { // Run in dry-check, otherwise the test would be too slow self.args.push("--dry-run".to_string()); From d488d33fd6f7d4832cab12d0dece896bf1b975c0 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:17:15 +0530 Subject: [PATCH 105/537] let verify method run in test settings --- src/bootstrap/src/core/download.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 2f3c80559c0e..ce3f49a35b9e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -857,7 +857,7 @@ pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) - println!("verifying {}", path.display()); }); - if exec_ctx.dry_run() { + if exec_ctx.dry_run() && !cfg!(test) { return false; } From ce4604e34e6f29740b41306806c6bd7947e103a4 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:18:35 +0530 Subject: [PATCH 106/537] remove using default toml config for test in get_toml, we handle it via using the temp directory created via the testCtx --- src/bootstrap/src/core/config/toml/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs index 7af22432ef8c..f6dc5b67e101 100644 --- a/src/bootstrap/src/core/config/toml/mod.rs +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -152,10 +152,6 @@ impl Config { } pub(crate) fn get_toml(file: &Path) -> Result { - #[cfg(test)] - return Ok(TomlConfig::default()); - - #[cfg(not(test))] Self::get_toml_inner(file) } From 24ed1a0455ced62f48402f6740effbf818f45269 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:18:58 +0530 Subject: [PATCH 107/537] allow symlinking during test --- src/bootstrap/src/utils/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index e802c0214ddc..0561f343a8c1 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -160,7 +160,7 @@ impl Drop for TimeIt { /// Symlinks two directories, using junctions on Windows and normal symlinks on /// Unix. pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<()> { - if config.dry_run() { + if config.dry_run() && !cfg!(test) { return Ok(()); } let _ = fs::remove_dir_all(link); From 05131bd5f11812390018dddc29fb9a36c4657ed2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:19:29 +0530 Subject: [PATCH 108/537] move most of the test to new testCtx --- src/bootstrap/src/core/builder/tests.rs | 31 +-- src/bootstrap/src/core/config/tests.rs | 295 ++++++++++------------- src/bootstrap/src/utils/helpers/tests.rs | 7 +- 3 files changed, 147 insertions(+), 186 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 229adf714598..a3cb4660ffc5 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -218,18 +218,16 @@ fn prepare_rustc_checkout(ctx: &mut GitCtx) { /// Parses a Config directory from `path`, with the given value of `download_rustc`. fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) -> Config { - Config::parse_inner( - Flags::parse(&[ - "build".to_owned(), - "--dry-run".to_owned(), - "--ci".to_owned(), - if ci { "true" } else { "false" }.to_owned(), - format!("--set=rust.download-rustc='{download_rustc}'"), - "--src".to_owned(), - path.to_str().unwrap().to_owned(), - ]), - |&_| Ok(Default::default()), - ) + TestCtx::new() + .config("build") + .args(&[ + "--ci", + if ci { "true" } else { "false" }, + format!("--set=rust.download-rustc='{download_rustc}'").as_str(), + "--src", + path.to_str().unwrap(), + ]) + .create_config_without_ci_llvm_override() } mod dist { @@ -359,14 +357,7 @@ fn test_test_coverage() { #[test] fn test_prebuilt_llvm_config_path_resolution() { fn configure(config: &str) -> Config { - Config::parse_inner( - Flags::parse(&[ - "build".to_string(), - "--dry-run".to_string(), - "--config=/does/not/exist".to_string(), - ]), - |&_| toml::from_str(&config), - ) + TestCtx::new().config("build").config_toml(config).create_config() } // Removes Windows disk prefix if present diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 46d05fbc0686..68859c6545e1 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -14,17 +14,15 @@ use super::toml::change_id::ChangeIdWrapper; use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; -use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; +use crate::core::build_steps::{llvm, test}; use crate::core::config::toml::TomlConfig; use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection}; +use crate::utils::tests::TestCtx; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { - Config::parse_inner( - Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]), - |&_| toml::from_str(&config), - ) + TestCtx::new().config("check").config_toml(config).create_config() } fn get_toml(file: &Path) -> Result { @@ -54,10 +52,14 @@ fn prepare_test_specific_dir() -> PathBuf { #[test] fn download_ci_llvm() { - let config = parse("llvm.download-ci-llvm = false"); + let config = TestCtx::new().config("check").create_config(); assert!(!config.llvm_from_ci); - let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\""); + // this doesn't make sense, as we are overriding it later. + let if_unchanged_config = TestCtx::new() + .config("check") + .config_toml("llvm.download-ci-llvm = \"if-unchanged\"") + .create_config(); if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci { let has_changes = if_unchanged_config.has_changes_from_upstream(LLVM_INVALIDATION_PATHS); @@ -75,54 +77,51 @@ fn clap_verify() { #[test] fn override_toml() { - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--config=/does/not/exist".to_owned(), - "--set=change-id=1".to_owned(), - "--set=rust.lto=fat".to_owned(), - "--set=rust.deny-warnings=false".to_owned(), - "--set=build.optimized-compiler-builtins=true".to_owned(), - "--set=build.gdb=\"bar\"".to_owned(), - "--set=build.tools=[\"cargo\"]".to_owned(), - "--set=llvm.build-config={\"foo\" = \"bar\"}".to_owned(), - "--set=target.x86_64-unknown-linux-gnu.runner=bar".to_owned(), - "--set=target.x86_64-unknown-linux-gnu.rpath=false".to_owned(), - "--set=target.aarch64-unknown-linux-gnu.sanitizers=false".to_owned(), - "--set=target.aarch64-apple-darwin.runner=apple".to_owned(), - "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false".to_owned(), - ]), - |&_| { - toml::from_str( - r#" -change-id = 0 -[rust] -lto = "off" -deny-warnings = true -download-rustc=false + let config_toml: &str = r#" + change-id = 0 -[build] -gdb = "foo" -tools = [] + [rust] + lto = "off" + deny-warnings = true + download-rustc = false -[llvm] -download-ci-llvm = false -build-config = {} + [build] + gdb = "foo" + tools = [] -[target.aarch64-unknown-linux-gnu] -sanitizers = true -rpath = true -runner = "aarch64-runner" + [llvm] + download-ci-llvm = false + build-config = {} -[target.x86_64-unknown-linux-gnu] -sanitizers = true -rpath = true -runner = "x86_64-runner" + [target.aarch64-unknown-linux-gnu] + sanitizers = true + rpath = true + runner = "aarch64-runner" + + [target.x86_64-unknown-linux-gnu] + sanitizers = true + rpath = true + runner = "x86_64-runner" + "#; + + let args = [ + "--set=change-id=1", + "--set=rust.lto=fat", + "--set=rust.deny-warnings=false", + "--set=build.optimized-compiler-builtins=true", + "--set=build.gdb=\"bar\"", + "--set=build.tools=[\"cargo\"]", + "--set=llvm.build-config={\"foo\" = \"bar\"}", + "--set=target.x86_64-unknown-linux-gnu.runner=bar", + "--set=target.x86_64-unknown-linux-gnu.rpath=false", + "--set=target.aarch64-unknown-linux-gnu.sanitizers=false", + "--set=target.aarch64-apple-darwin.runner=apple", + "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false", + ]; + + let config = + TestCtx::new().config("check").config_toml(config_toml).args(&args).create_config(); - "#, - ) - }, - ); assert_eq!(config.change_id, Some(ChangeId::Id(1)), "setting top-level value"); assert_eq!( config.rust_lto, @@ -181,15 +180,14 @@ runner = "x86_64-runner" #[test] #[should_panic] fn override_toml_duplicate() { - Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--config=/does/not/exist".to_string(), - "--set=change-id=1".to_owned(), - "--set=change-id=2".to_owned(), - ]), - |&_| toml::from_str("change-id = 0"), - ); + TestCtx::new() + .config("check") + .config_toml("change-id = 0") + .arg("--set") + .arg("change-id=1") + .arg("--set") + .arg("change-id=2") + .create_config(); } #[test] @@ -225,12 +223,12 @@ fn rust_optimize() { #[test] #[should_panic] fn invalid_rust_optimize() { - parse("rust.optimize = \"a\""); + TestCtx::new().config("check").config_toml("rust.optimize = \"a\"").create_config(); } #[test] fn verify_file_integrity() { - let config = parse(""); + let config = TestCtx::new().config("check").create_config(); let tempfile = config.tempdir().join(".tmp-test-file"); File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap(); @@ -272,22 +270,23 @@ fn parse_change_id_with_unknown_field() { #[test] fn order_of_clippy_rules() { - let args = vec![ - "clippy".to_string(), - "--fix".to_string(), - "--allow-dirty".to_string(), - "--allow-staged".to_string(), - "-Aclippy:all".to_string(), - "-Wclippy::style".to_string(), - "-Aclippy::foo1".to_string(), - "-Aclippy::foo2".to_string(), + let args = [ + "clippy", + "--fix", + "--allow-dirty", + "--allow-staged", + "-Aclippy:all", + "-Wclippy::style", + "-Aclippy::foo1", + "-Aclippy::foo2", ]; - let config = Config::parse(Flags::parse(&args)); + let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config(); let actual = match config.cmd.clone() { crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => { let cfg = LintConfig { allow, deny, warn, forbid }; - get_clippy_rules_in_order(&args, &cfg) + let args_vec: Vec = args.iter().map(|s| s.to_string()).collect(); + get_clippy_rules_in_order(&args_vec, &cfg) } _ => panic!("invalid subcommand"), }; @@ -304,14 +303,14 @@ fn order_of_clippy_rules() { #[test] fn clippy_rule_separate_prefix() { - let args = - vec!["clippy".to_string(), "-A clippy:all".to_string(), "-W clippy::style".to_string()]; - let config = Config::parse(Flags::parse(&args)); + let args = ["clippy", "-A clippy:all", "-W clippy::style"]; + let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config(); let actual = match config.cmd.clone() { crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => { let cfg = LintConfig { allow, deny, warn, forbid }; - get_clippy_rules_in_order(&args, &cfg) + let args_vec: Vec = args.iter().map(|s| s.to_string()).collect(); + get_clippy_rules_in_order(&args_vec, &cfg) } _ => panic!("invalid subcommand"), }; @@ -331,7 +330,10 @@ fn verbose_tests_default_value() { #[test] fn parse_rust_std_features() { - let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]"); + let config = TestCtx::new() + .config("check") + .config_toml("rust.std-features = [\"panic-unwind\", \"backtrace\"]") + .create_config(); let expected_features: BTreeSet = ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect(); assert_eq!(config.rust_std_features, expected_features); @@ -339,7 +341,8 @@ fn parse_rust_std_features() { #[test] fn parse_rust_std_features_empty() { - let config = parse("rust.std-features = []"); + let config = + TestCtx::new().config("check").config_toml("rust.std-features = []").create_config(); let expected_features: BTreeSet = BTreeSet::new(); assert_eq!(config.rust_std_features, expected_features); } @@ -347,70 +350,58 @@ fn parse_rust_std_features_empty() { #[test] #[should_panic] fn parse_rust_std_features_invalid() { - parse("rust.std-features = \"backtrace\""); + TestCtx::new().config("check").config_toml("rust.std-features = \"backtrace\"").create_config(); } #[test] fn parse_jobs() { - assert_eq!(parse("build.jobs = 1").jobs, Some(1)); + assert_eq!( + TestCtx::new().config("check").config_toml("build.jobs = 1").create_config().jobs, + Some(1) + ); } #[test] fn jobs_precedence() { // `--jobs` should take precedence over using `--set build.jobs`. - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--config=/does/not/exist".to_owned(), - "--jobs=67890".to_owned(), - "--set=build.jobs=12345".to_owned(), - ]), - |&_| toml::from_str(""), - ); + let config = TestCtx::new() + .config("check") + .args(&["--jobs=67890", "--set=build.jobs=12345"]) + .create_config(); assert_eq!(config.jobs, Some(67890)); // `--set build.jobs` should take precedence over `bootstrap.toml`. - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--config=/does/not/exist".to_owned(), - "--set=build.jobs=12345".to_owned(), - ]), - |&_| { - toml::from_str( - r#" - [build] - jobs = 67890 - "#, - ) - }, - ); + let config = TestCtx::new() + .config("check") + .args(&["--set=build.jobs=12345"]) + .config_toml( + r#" + [build] + jobs = 67890 + "#, + ) + .create_config(); + assert_eq!(config.jobs, Some(12345)); // `--jobs` > `--set build.jobs` > `bootstrap.toml` - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--jobs=123".to_owned(), - "--config=/does/not/exist".to_owned(), - "--set=build.jobs=456".to_owned(), - ]), - |&_| { - toml::from_str( - r#" - [build] - jobs = 789 - "#, - ) - }, - ); + let config = TestCtx::new() + .config("check") + .args(&["--jobs=123", "--set=build.jobs=456"]) + .config_toml( + r#" + [build] + jobs = 789 + "#, + ) + .create_config(); assert_eq!(config.jobs, Some(123)); } #[test] fn check_rustc_if_unchanged_paths() { - let config = parse(""); + let config = TestCtx::new().config("check").create_config(); let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS .iter() .map(|t| { @@ -425,59 +416,42 @@ fn check_rustc_if_unchanged_paths() { #[test] fn test_explicit_stage() { - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]), - |&_| { - toml::from_str( - r#" + let config = TestCtx::new() + .config("check") + .config_toml( + r#" [build] test-stage = 1 "#, - ) - }, - ); + ) + .create_config(); assert!(!config.explicit_stage_from_cli); assert!(config.explicit_stage_from_config); assert!(config.is_explicit_stage()); - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--stage=2".to_owned(), - "--config=/does/not/exist".to_owned(), - ]), - |&_| toml::from_str(""), - ); + let config = TestCtx::new().config("check").stage(2).create_config(); assert!(config.explicit_stage_from_cli); assert!(!config.explicit_stage_from_config); assert!(config.is_explicit_stage()); - let config = Config::parse_inner( - Flags::parse(&[ - "check".to_owned(), - "--stage=2".to_owned(), - "--config=/does/not/exist".to_owned(), - ]), - |&_| { - toml::from_str( - r#" + let config = TestCtx::new() + .config("check") + .stage(2) + .config_toml( + r#" [build] test-stage = 1 "#, - ) - }, - ); + ) + .create_config(); assert!(config.explicit_stage_from_cli); assert!(config.explicit_stage_from_config); assert!(config.is_explicit_stage()); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]), - |&_| toml::from_str(""), - ); + let config = TestCtx::new().config("check").create_config(); assert!(!config.explicit_stage_from_cli); assert!(!config.explicit_stage_from_config); @@ -487,7 +461,10 @@ fn test_explicit_stage() { #[test] fn test_exclude() { let exclude_path = "compiler"; - let config = parse(&format!("build.exclude=[\"{}\"]", exclude_path)); + let config = TestCtx::new() + .config("check") + .config_toml(&format!("build.exclude=[\"{}\"]", exclude_path)) + .create_config(); let first_excluded = config .skip @@ -501,17 +478,13 @@ fn test_exclude() { #[test] fn test_ci_flag() { - let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=false".into()]), |&_| { - toml::from_str("") - }); + let config = TestCtx::new().config("check").arg("--ci").arg("false").create_config(); assert!(!config.is_running_on_ci); - let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=true".into()]), |&_| { - toml::from_str("") - }); + let config = TestCtx::new().config("check").arg("--ci").arg("true").create_config(); assert!(config.is_running_on_ci); - let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str("")); + let config = TestCtx::new().config("check").create_config(); assert_eq!(config.is_running_on_ci, CiEnv::is_ci()); } diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index e586fe77b4f6..ec99743d1ed8 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -60,8 +60,7 @@ fn test_check_cfg_arg() { #[test] fn test_symlink_dir() { - let config = - Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()])); + let config = TestCtx::new().config("check").create_config(); let tempdir = config.tempdir().join(".tmp-dir"); let link_path = config.tempdir().join(".tmp-link"); @@ -102,9 +101,7 @@ fn test_set_file_times_sanity_check() { #[test] fn test_submodule_path_of() { - let config = Config::parse_inner(Flags::parse(&["build".into(), "--dry-run".into()]), |&_| { - Ok(Default::default()) - }); + let config = TestCtx::new().config("build").create_config(); let build = crate::Build::new(config.clone()); let builder = crate::core::builder::Builder::new(&build); From a29474d3ff06660071ebb5f071a7cdce0ee07646 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 16 Sep 2025 21:20:14 +0530 Subject: [PATCH 109/537] this is dicy, whether we have a method to explicitly enable_llvm_override --- src/bootstrap/src/utils/tests/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index ff84bfdb4cde..d47a224d7af5 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -125,4 +125,19 @@ impl ConfigBuilder { Config::parse(Flags::parse(&self.args)) } + + pub fn create_config_without_ci_llvm_override(mut self) -> Config { + // Run in dry-check, otherwise the test would be too slow + self.args.push("--dry-run".to_string()); + + // Ignore submodules + self.args.push("--set".to_string()); + self.args.push("build.submodules=false".to_string()); + + // Do not mess with the local rustc checkout build directory + self.args.push("--build-dir".to_string()); + self.args.push(self.directory.join("build").display().to_string()); + + Config::parse(Flags::parse(&self.args)) + } } From 0c68c82957e86c15d4a543c0d32f9e101ce74ba9 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 18:16:47 +0530 Subject: [PATCH 110/537] rename config_toml to with_default_toml_config --- src/bootstrap/src/core/builder/tests.rs | 2 +- src/bootstrap/src/core/config/tests.rs | 47 ++++++++++++++++--------- src/bootstrap/src/utils/tests/mod.rs | 2 +- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a3cb4660ffc5..7033098b79bf 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -357,7 +357,7 @@ fn test_test_coverage() { #[test] fn test_prebuilt_llvm_config_path_resolution() { fn configure(config: &str) -> Config { - TestCtx::new().config("build").config_toml(config).create_config() + TestCtx::new().config("build").with_default_toml_config(config).create_config() } // Removes Windows disk prefix if present diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 68859c6545e1..30b4c6cfc431 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -22,7 +22,7 @@ use crate::utils::tests::TestCtx; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { - TestCtx::new().config("check").config_toml(config).create_config() + TestCtx::new().config("check").with_default_toml_config(config).create_config() } fn get_toml(file: &Path) -> Result { @@ -58,7 +58,7 @@ fn download_ci_llvm() { // this doesn't make sense, as we are overriding it later. let if_unchanged_config = TestCtx::new() .config("check") - .config_toml("llvm.download-ci-llvm = \"if-unchanged\"") + .with_default_toml_config("llvm.download-ci-llvm = \"if-unchanged\"") .create_config(); if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci { let has_changes = if_unchanged_config.has_changes_from_upstream(LLVM_INVALIDATION_PATHS); @@ -119,8 +119,11 @@ fn override_toml() { "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false", ]; - let config = - TestCtx::new().config("check").config_toml(config_toml).args(&args).create_config(); + let config = TestCtx::new() + .config("check") + .with_default_toml_config(config_toml) + .args(&args) + .create_config(); assert_eq!(config.change_id, Some(ChangeId::Id(1)), "setting top-level value"); assert_eq!( @@ -182,7 +185,7 @@ fn override_toml() { fn override_toml_duplicate() { TestCtx::new() .config("check") - .config_toml("change-id = 0") + .with_default_toml_config("change-id = 0") .arg("--set") .arg("change-id=1") .arg("--set") @@ -223,7 +226,10 @@ fn rust_optimize() { #[test] #[should_panic] fn invalid_rust_optimize() { - TestCtx::new().config("check").config_toml("rust.optimize = \"a\"").create_config(); + TestCtx::new() + .config("check") + .with_default_toml_config("rust.optimize = \"a\"") + .create_config(); } #[test] @@ -332,7 +338,7 @@ fn verbose_tests_default_value() { fn parse_rust_std_features() { let config = TestCtx::new() .config("check") - .config_toml("rust.std-features = [\"panic-unwind\", \"backtrace\"]") + .with_default_toml_config("rust.std-features = [\"panic-unwind\", \"backtrace\"]") .create_config(); let expected_features: BTreeSet = ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect(); @@ -341,8 +347,10 @@ fn parse_rust_std_features() { #[test] fn parse_rust_std_features_empty() { - let config = - TestCtx::new().config("check").config_toml("rust.std-features = []").create_config(); + let config = TestCtx::new() + .config("check") + .with_default_toml_config("rust.std-features = []") + .create_config(); let expected_features: BTreeSet = BTreeSet::new(); assert_eq!(config.rust_std_features, expected_features); } @@ -350,13 +358,20 @@ fn parse_rust_std_features_empty() { #[test] #[should_panic] fn parse_rust_std_features_invalid() { - TestCtx::new().config("check").config_toml("rust.std-features = \"backtrace\"").create_config(); + TestCtx::new() + .config("check") + .with_default_toml_config("rust.std-features = \"backtrace\"") + .create_config(); } #[test] fn parse_jobs() { assert_eq!( - TestCtx::new().config("check").config_toml("build.jobs = 1").create_config().jobs, + TestCtx::new() + .config("check") + .with_default_toml_config("build.jobs = 1") + .create_config() + .jobs, Some(1) ); } @@ -375,7 +390,7 @@ fn jobs_precedence() { let config = TestCtx::new() .config("check") .args(&["--set=build.jobs=12345"]) - .config_toml( + .with_default_toml_config( r#" [build] jobs = 67890 @@ -389,7 +404,7 @@ fn jobs_precedence() { let config = TestCtx::new() .config("check") .args(&["--jobs=123", "--set=build.jobs=456"]) - .config_toml( + .with_default_toml_config( r#" [build] jobs = 789 @@ -418,7 +433,7 @@ fn check_rustc_if_unchanged_paths() { fn test_explicit_stage() { let config = TestCtx::new() .config("check") - .config_toml( + .with_default_toml_config( r#" [build] test-stage = 1 @@ -439,7 +454,7 @@ fn test_explicit_stage() { let config = TestCtx::new() .config("check") .stage(2) - .config_toml( + .with_default_toml_config( r#" [build] test-stage = 1 @@ -463,7 +478,7 @@ fn test_exclude() { let exclude_path = "compiler"; let config = TestCtx::new() .config("check") - .config_toml(&format!("build.exclude=[\"{}\"]", exclude_path)) + .with_default_toml_config(&format!("build.exclude=[\"{}\"]", exclude_path)) .create_config(); let first_excluded = config diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index d47a224d7af5..80df15939b05 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -98,7 +98,7 @@ impl ConfigBuilder { self } - pub fn config_toml(mut self, config_toml: &str) -> Self { + pub fn with_default_toml_config(mut self, config_toml: &str) -> Self { let toml_path = self.directory.join("bootstrap.toml"); std::fs::write(&toml_path, config_toml).unwrap(); self.args.push("--config".to_string()); From 9189bf79d43dd162858bc58d64c6c99da7ca0add Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 18:32:20 +0530 Subject: [PATCH 111/537] remove create_config_without_ci_llvm_override duplication --- src/bootstrap/src/core/builder/tests.rs | 3 +- src/bootstrap/src/utils/tests/mod.rs | 37 ++++++++++++------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 7033098b79bf..0bb22eccd193 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -227,7 +227,8 @@ fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) - "--src", path.to_str().unwrap(), ]) - .create_config_without_ci_llvm_override() + .no_override_download_ci_llvm() + .create_config() } mod dist { diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 80df15939b05..0ccc8e1ebb8f 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -48,11 +48,16 @@ impl TestCtx { pub struct ConfigBuilder { args: Vec, directory: PathBuf, + override_download_ci_llvm: bool, } impl ConfigBuilder { fn from_args(args: &[&str], directory: PathBuf) -> Self { - Self { args: args.iter().copied().map(String::from).collect(), directory } + Self { + args: args.iter().copied().map(String::from).collect(), + directory, + override_download_ci_llvm: true, + } } pub fn path(mut self, path: &str) -> Self { @@ -106,6 +111,11 @@ impl ConfigBuilder { self } + pub fn no_override_download_ci_llvm(mut self) -> Self { + self.override_download_ci_llvm = false; + self + } + pub fn create_config(mut self) -> Config { // Run in dry-check, otherwise the test would be too slow self.args.push("--dry-run".to_string()); @@ -114,25 +124,12 @@ impl ConfigBuilder { self.args.push("--set".to_string()); self.args.push("build.submodules=false".to_string()); - // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building - // in-tree LLVM from sources. - self.args.push("--set".to_string()); - self.args.push("llvm.download-ci-llvm=false".to_string()); - - // Do not mess with the local rustc checkout build directory - self.args.push("--build-dir".to_string()); - self.args.push(self.directory.join("build").display().to_string()); - - Config::parse(Flags::parse(&self.args)) - } - - pub fn create_config_without_ci_llvm_override(mut self) -> Config { - // Run in dry-check, otherwise the test would be too slow - self.args.push("--dry-run".to_string()); - - // Ignore submodules - self.args.push("--set".to_string()); - self.args.push("build.submodules=false".to_string()); + if self.override_download_ci_llvm { + // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building + // in-tree LLVM from sources. + self.args.push("--set".to_string()); + self.args.push("llvm.download-ci-llvm=false".to_string()); + } // Do not mess with the local rustc checkout build directory self.args.push("--build-dir".to_string()); From 671aabd4eb1a56a09b989abc021bee32750ee59b Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 19:34:49 +0530 Subject: [PATCH 112/537] add dry_run flag in config builder and remove runtime test hacks --- src/bootstrap/src/core/config/tests.rs | 2 +- src/bootstrap/src/core/download.rs | 2 +- src/bootstrap/src/utils/helpers.rs | 2 +- src/bootstrap/src/utils/helpers/tests.rs | 2 +- src/bootstrap/src/utils/tests/mod.rs | 14 +++++++++++--- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 30b4c6cfc431..a7429e07d858 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -234,7 +234,7 @@ fn invalid_rust_optimize() { #[test] fn verify_file_integrity() { - let config = TestCtx::new().config("check").create_config(); + let config = TestCtx::new().config("check").no_dry_run().create_config(); let tempfile = config.tempdir().join(".tmp-test-file"); File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap(); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index ce3f49a35b9e..2f3c80559c0e 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -857,7 +857,7 @@ pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) - println!("verifying {}", path.display()); }); - if exec_ctx.dry_run() && !cfg!(test) { + if exec_ctx.dry_run() { return false; } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 0561f343a8c1..e802c0214ddc 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -160,7 +160,7 @@ impl Drop for TimeIt { /// Symlinks two directories, using junctions on Windows and normal symlinks on /// Unix. pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<()> { - if config.dry_run() && !cfg!(test) { + if config.dry_run() { return Ok(()); } let _ = fs::remove_dir_all(link); diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index ec99743d1ed8..676fe6cbd5fe 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -60,7 +60,7 @@ fn test_check_cfg_arg() { #[test] fn test_symlink_dir() { - let config = TestCtx::new().config("check").create_config(); + let config = TestCtx::new().config("check").no_dry_run().create_config(); let tempdir = config.tempdir().join(".tmp-dir"); let link_path = config.tempdir().join(".tmp-link"); diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 0ccc8e1ebb8f..dc905969dcac 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -49,6 +49,7 @@ pub struct ConfigBuilder { args: Vec, directory: PathBuf, override_download_ci_llvm: bool, + dry_run: bool, } impl ConfigBuilder { @@ -57,6 +58,7 @@ impl ConfigBuilder { args: args.iter().copied().map(String::from).collect(), directory, override_download_ci_llvm: true, + dry_run: true, } } @@ -116,10 +118,16 @@ impl ConfigBuilder { self } - pub fn create_config(mut self) -> Config { - // Run in dry-check, otherwise the test would be too slow - self.args.push("--dry-run".to_string()); + pub fn no_dry_run(mut self) -> Self { + self.dry_run = false; + self + } + pub fn create_config(mut self) -> Config { + if self.dry_run { + // Run in dry-check, otherwise the test would be too slow + self.args.push("--dry-run".to_string()); + } // Ignore submodules self.args.push("--set".to_string()); self.args.push("build.submodules=false".to_string()); From afe380dd58170b55b100a659f05017b1149d0ec9 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 19:43:43 +0530 Subject: [PATCH 113/537] initialize out with CARGO_TARGET_DIR and then go for manifest and then for current --- src/bootstrap/src/core/config/config.rs | 27 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 003cf3f2f9c3..1f3b90d324fb 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -630,9 +630,13 @@ impl Config { let llvm_assertions = llvm_assertions.unwrap_or(false); let mut target_config = HashMap::new(); let mut channel = "dev".to_string(); - let out = flags_build_dir - .or(build_build_dir.map(PathBuf::from)) - .unwrap_or_else(|| PathBuf::from("build")); + let out = if cfg!(test) { + test_build_dir() + } else { + flags_build_dir + .or_else(|| build_build_dir.map(PathBuf::from)) + .unwrap_or_else(|| PathBuf::from("build")) + }; // NOTE: Bootstrap spawns various commands with different working directories. // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. @@ -683,11 +687,6 @@ impl Config { }; let initial_rustc = build_rustc.unwrap_or_else(|| { - let out = if cfg!(test) { - std::env::current_dir().unwrap().ancestors().nth(2).unwrap().join("build") - } else { - out.clone() - }; download_beta_toolchain(&dwn_ctx, &out); let target = if cfg!(test) { get_host_target() } else { host_target }; @@ -2481,3 +2480,15 @@ fn find_correct_section_for_field(field_name: &str) -> Vec { }) .collect() } + +fn test_build_dir() -> PathBuf { + env::var_os("CARGO_TARGET_DIR") + .map(|value| Path::new(&value).parent().unwrap().to_path_buf()) + .unwrap_or_else(|| { + let base = option_env!("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| std::env::current_dir().expect("failed to get current dir")); + + base.ancestors().nth(2).unwrap_or_else(|| Path::new(".")).join("build") + }) +} From a48cd767f634ec7461b8367e5d301a2985cfce7d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 20:03:15 +0530 Subject: [PATCH 114/537] add explicit config assignment when running the test, as the src is assigned to CARGO_MANIFEST_DIR, so the config actually use the /bootstrap.toml and the /tmp/bootstrap.toml --- src/bootstrap/src/utils/tests/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index dc905969dcac..764b89086cf2 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -50,6 +50,7 @@ pub struct ConfigBuilder { directory: PathBuf, override_download_ci_llvm: bool, dry_run: bool, + explicit_config: bool, } impl ConfigBuilder { @@ -59,6 +60,7 @@ impl ConfigBuilder { directory, override_download_ci_llvm: true, dry_run: true, + explicit_config: true, } } @@ -108,6 +110,7 @@ impl ConfigBuilder { pub fn with_default_toml_config(mut self, config_toml: &str) -> Self { let toml_path = self.directory.join("bootstrap.toml"); std::fs::write(&toml_path, config_toml).unwrap(); + self.explicit_config = false; self.args.push("--config".to_string()); self.args.push(toml_path.display().to_string()); self @@ -139,6 +142,12 @@ impl ConfigBuilder { self.args.push("llvm.download-ci-llvm=false".to_string()); } + // always use the bootstrap toml created in the + // temporary directory and not from the + if self.explicit_config { + self = self.with_default_toml_config(""); + } + // Do not mess with the local rustc checkout build directory self.args.push("--build-dir".to_string()); self.args.push(self.directory.join("build").display().to_string()); From 33e262e8cc5ec07e0d3312be2d2c2ae3404f5fbd Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 21 Sep 2025 20:52:26 +0530 Subject: [PATCH 115/537] remove prepare_test_specific_dir and update tests accordingly --- src/bootstrap/src/core/config/tests.rs | 154 +++++++++++-------------- 1 file changed, 65 insertions(+), 89 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index a7429e07d858..f277e3704f27 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -30,26 +30,6 @@ fn get_toml(file: &Path) -> Result { toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table)) } -/// Helps with debugging by using consistent test-specific directories instead of -/// random temporary directories. -fn prepare_test_specific_dir() -> PathBuf { - let current = std::thread::current(); - // Replace "::" with "_" to make it safe for directory names on Windows systems - let test_path = current.name().unwrap().replace("::", "_"); - - let testdir = crate::utils::tests::TestCtx::new() - .config("check") - .create_config() - .tempdir() - .join(test_path); - - // clean up any old test files - let _ = fs::remove_dir_all(&testdir); - let _ = fs::create_dir_all(&testdir); - - testdir -} - #[test] fn download_ci_llvm() { let config = TestCtx::new().config("check").create_config(); @@ -505,16 +485,8 @@ fn test_ci_flag() { #[test] fn test_precedence_of_includes() { - let testdir = prepare_test_specific_dir(); - - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - include = ["./extension.toml"] - - [llvm] - link-jobs = 2 - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let extension = testdir.join("extension.toml"); let extension_content = br#" @@ -535,10 +507,17 @@ fn test_precedence_of_includes() { "#; File::create(extension).unwrap().write_all(extension_content).unwrap(); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + let config = test_ctx + .config("check") + .with_default_toml_config( + r#" + include = ["./extension.toml"] + + [llvm] + link-jobs = 2 + "#, + ) + .create_config(); assert_eq!(config.change_id.unwrap(), ChangeId::Id(543)); assert_eq!(config.llvm_link_jobs.unwrap(), 2); @@ -548,36 +527,29 @@ fn test_precedence_of_includes() { #[test] #[should_panic(expected = "Cyclic inclusion detected")] fn test_cyclic_include_direct() { - let testdir = prepare_test_specific_dir(); - - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - include = ["./extension.toml"] - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); - + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let extension = testdir.join("extension.toml"); let extension_content = br#" - include = ["./config.toml"] + include = ["./bootstrap.toml"] "#; File::create(extension).unwrap().write_all(extension_content).unwrap(); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + test_ctx + .config("check") + .with_default_toml_config( + r#" + include = ["./extension.toml"] + "#, + ) + .create_config(); } #[test] #[should_panic(expected = "Cyclic inclusion detected")] fn test_cyclic_include_indirect() { - let testdir = prepare_test_specific_dir(); - - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - include = ["./extension.toml"] - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let extension = testdir.join("extension.toml"); let extension_content = br#" @@ -597,43 +569,37 @@ fn test_cyclic_include_indirect() { "#; File::create(extension).unwrap().write_all(extension_content).unwrap(); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + test_ctx + .config("check") + .with_default_toml_config( + r#" + include = ["./extension.toml"] + "#, + ) + .create_config(); } #[test] fn test_include_absolute_paths() { - let testdir = prepare_test_specific_dir(); + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let extension = testdir.join("extension.toml"); File::create(&extension).unwrap().write_all(&[]).unwrap(); - let root_config = testdir.join("config.toml"); let extension_absolute_path = extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\"); let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path); - File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap(); - - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + test_ctx.config("check").with_default_toml_config(&root_config_content).create_config(); } #[test] fn test_include_relative_paths() { - let testdir = prepare_test_specific_dir(); + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir")); - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - include = ["./subdir/extension.toml"] - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); - let extension = testdir.join("subdir/extension.toml"); let extension_content = br#" include = ["../extension2.toml"] @@ -655,22 +621,20 @@ fn test_include_relative_paths() { let extension = testdir.join("extension4.toml"); File::create(extension).unwrap().write_all(&[]).unwrap(); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + test_ctx + .config("check") + .with_default_toml_config( + r#" + include = ["./subdir/extension.toml"] + "#, + ) + .create_config(); } #[test] fn test_include_precedence_over_profile() { - let testdir = prepare_test_specific_dir(); - - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - profile = "dist" - include = ["./extension.toml"] - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + let test_ctx = TestCtx::new(); + let testdir = test_ctx.dir(); let extension = testdir.join("extension.toml"); let extension_content = br#" @@ -679,10 +643,22 @@ fn test_include_precedence_over_profile() { "#; File::create(extension).unwrap().write_all(extension_content).unwrap(); - let config = Config::parse_inner( - Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), - get_toml, - ); + let root_config = testdir.join("config.toml"); + let root_config_content = br#" + profile = "dist" + include = ["./extension.toml"] + "#; + File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); + + let config = test_ctx + .config("check") + .with_default_toml_config( + r#" + profile = "dist" + include = ["./extension.toml"] + "#, + ) + .create_config(); // "dist" profile would normally set the channel to "auto-detect", but includes should // override profile settings, so we expect this to be "dev" here. From e99e226748d3438d40a11ff556820375a762c8e1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 21 Sep 2025 23:20:20 +0800 Subject: [PATCH 116/537] Switch `dummy_bang` from `LegacyBang` to `Bang` --- compiler/rustc_expand/src/base.rs | 23 ++++++++++------------- compiler/rustc_expand/src/expand.rs | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 88f88f30a8c6..7db1be24f241 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -324,16 +324,16 @@ pub trait BangProcMacro { impl BangProcMacro for F where - F: Fn(TokenStream) -> TokenStream, + F: Fn(&mut ExtCtxt<'_>, Span, TokenStream) -> Result, { fn expand<'cx>( &self, - _ecx: &'cx mut ExtCtxt<'_>, - _span: Span, + ecx: &'cx mut ExtCtxt<'_>, + span: Span, ts: TokenStream, ) -> Result { // FIXME setup implicit context in TLS before calling self. - Ok(self(ts)) + self(ecx, span, ts) } } @@ -999,17 +999,14 @@ impl SyntaxExtension { /// A dummy bang macro `foo!()`. pub fn dummy_bang(edition: Edition) -> SyntaxExtension { - fn expander<'cx>( - cx: &'cx mut ExtCtxt<'_>, + fn expand( + ecx: &mut ExtCtxt<'_>, span: Span, - _: TokenStream, - ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(DummyResult::any( - span, - cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"), - )) + _ts: TokenStream, + ) -> Result { + Err(ecx.dcx().span_delayed_bug(span, "expanded a dummy bang macro")) } - SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Arc::new(expander)), edition) + SyntaxExtension::default(SyntaxExtensionKind::Bang(Arc::new(expand)), edition) } /// A dummy derive macro `#[derive(Foo)]`. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4c0e0bbfe26d..172bc3d1d9f8 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -971,7 +971,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }, - SyntaxExtensionKind::LegacyBang(..) => { + SyntaxExtensionKind::Bang(..) => { let msg = "expanded a dummy glob delegation"; let guar = self.cx.dcx().span_delayed_bug(span, msg); return ExpandResult::Ready(fragment_kind.dummy(span, guar)); From a1646bf90c12c168a898361d2ef34e73311eccde Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 21 Sep 2025 23:28:10 +0800 Subject: [PATCH 117/537] mbe: Switch dummy extension used for errors from `LegacyBang` to `Bang` --- compiler/rustc_expand/src/mbe/macro_rules.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 1d147a0385c6..9ed4c56efb3e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -33,8 +33,8 @@ use super::diagnostics::{FailedMacro, failed_to_match_macro}; use super::macro_parser::{NamedMatches, NamedParseResult}; use super::{SequenceRepetition, diagnostics}; use crate::base::{ - AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, - SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, + AttrProcMacro, BangProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, + MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; use crate::errors; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; @@ -267,16 +267,16 @@ impl AttrProcMacro for MacroRulesMacroExpander { } } -struct DummyExpander(ErrorGuaranteed); +struct DummyBang(ErrorGuaranteed); -impl TTMacroExpander for DummyExpander { +impl BangProcMacro for DummyBang { fn expand<'cx>( &self, _: &'cx mut ExtCtxt<'_>, - span: Span, + _: Span, _: TokenStream, - ) -> ExpandResult, ()> { - ExpandResult::Ready(DummyResult::any(span, self.0)) + ) -> Result { + Err(self.0) } } @@ -664,7 +664,7 @@ pub fn compile_declarative_macro( SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; let dummy_syn_ext = - |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0); + |guar| (mk_syn_ext(SyntaxExtensionKind::Bang(Arc::new(DummyBang(guar)))), 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; From 888679013d1f424adef06267f3630069b4cabd40 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 7 Sep 2025 12:31:35 -0400 Subject: [PATCH 118/537] Add panic=immediate-abort --- .../rustc_builtin_macros/src/test_harness.rs | 10 +-- compiler/rustc_codegen_gcc/src/base.rs | 4 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 3 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 3 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- compiler/rustc_codegen_ssa/src/back/link.rs | 10 +-- compiler/rustc_interface/messages.ftl | 2 +- compiler/rustc_interface/src/passes.rs | 3 +- compiler/rustc_metadata/messages.ftl | 7 ++ compiler/rustc_metadata/src/creader.rs | 4 + .../rustc_metadata/src/dependency_format.rs | 49 ++++++++--- compiler/rustc_metadata/src/errors.rs | 10 +++ .../rustc_middle/src/middle/lang_items.rs | 1 + compiler/rustc_middle/src/ty/layout.rs | 8 +- compiler/rustc_mir_transform/src/coroutine.rs | 3 +- .../src/ffi_unwind_calls.rs | 9 +- .../src/remove_noop_landing_pads.rs | 3 +- compiler/rustc_session/src/config.rs | 9 +- compiler/rustc_session/src/config/cfg.rs | 7 +- compiler/rustc_session/src/options.rs | 4 +- compiler/rustc_session/src/session.rs | 10 ++- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 6 ++ library/alloc/Cargo.toml | 2 - library/alloc/src/alloc.rs | 4 +- library/alloc/src/raw_vec/mod.rs | 2 +- library/alloc/src/vec/mod.rs | 8 +- library/core/Cargo.toml | 2 +- library/core/src/cell.rs | 4 +- library/core/src/num/mod.rs | 4 +- library/core/src/option.rs | 8 +- library/core/src/panicking.rs | 83 ++++++++++--------- library/core/src/result.rs | 4 +- library/core/src/slice/index.rs | 4 +- library/core/src/slice/mod.rs | 4 +- .../core/src/slice/sort/shared/smallsort.rs | 4 +- library/core/src/str/mod.rs | 4 +- library/std/Cargo.toml | 5 -- library/std/src/panicking.rs | 26 +++--- library/std/src/rt.rs | 4 +- library/std/src/thread/local.rs | 2 +- library/sysroot/Cargo.toml | 1 - src/doc/rustc/src/codegen-options/index.md | 2 + src/tools/compiletest/src/directives.rs | 19 +++++ .../src/directives/directive_names.rs | 1 + src/tools/compiletest/src/runtest.rs | 22 +++-- .../panic-immediate-abort-codegen/Cargo.toml | 12 +++ .../panic-immediate-abort-codegen/lib.rs | 65 +++++++++++++++ .../panic-immediate-abort-codegen/rmake.rs | 41 +++++++++ .../hello/Cargo.toml | 4 + .../hello/src/main.rs | 1 + .../panic-immediate-abort-works/rmake.rs | 28 +++++++ .../report-in-external-macros.cargo.stderr | 2 +- .../report-in-external-macros.rustc.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- .../ui/panic-runtime/auxiliary/needs-abort.rs | 2 + .../auxiliary/needs-immediate-abort.rs | 7 ++ .../auxiliary/needs-unwind-immediate-abort.rs | 18 ++++ tests/ui/panic-runtime/bad-panic-flag1.rs | 2 +- tests/ui/panic-runtime/bad-panic-flag1.stderr | 2 +- tests/ui/panic-runtime/bad-panic-flag2.rs | 2 +- tests/ui/panic-runtime/bad-panic-flag2.stderr | 2 +- .../immediate-abort-default-sysroot.rs | 15 ++++ .../immediate-abort-default-sysroot.stderr | 4 + .../need-abort-got-immediate-abort.rs | 21 +++++ .../need-abort-got-immediate-abort.stderr | 4 + .../need-immediate-abort-got-abort.rs | 20 +++++ .../need-immediate-abort-got-abort.stderr | 4 + .../need-immediate-abort-got-unwind.rs | 20 +++++ .../need-immediate-abort-got-unwind.stderr | 4 + .../need-unwind-got-immediate-abort.rs | 21 +++++ .../need-unwind-got-immediate-abort.stderr | 4 + tests/ui/proc-macro/panic-abort.rs | 2 +- tests/ui/proc-macro/panic-abort.stderr | 2 +- 74 files changed, 542 insertions(+), 158 deletions(-) create mode 100644 tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml create mode 100644 tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs create mode 100644 tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs create mode 100644 tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml create mode 100644 tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs create mode 100644 tests/run-make-cargo/panic-immediate-abort-works/rmake.rs create mode 100644 tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs create mode 100644 tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs create mode 100644 tests/ui/panic-runtime/immediate-abort-default-sysroot.rs create mode 100644 tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr create mode 100644 tests/ui/panic-runtime/need-abort-got-immediate-abort.rs create mode 100644 tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr create mode 100644 tests/ui/panic-runtime/need-immediate-abort-got-abort.rs create mode 100644 tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr create mode 100644 tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs create mode 100644 tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr create mode 100644 tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs create mode 100644 tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 51089e5a1d3f..82c59d5a3a20 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -63,8 +63,8 @@ pub fn inject( if sess.is_test_crate() { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { - (PanicStrategy::Abort, true) => PanicStrategy::Abort, - (PanicStrategy::Abort, false) => { + (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, true) => panic_strategy, + (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, false) => { if panic_strategy == platform_panic_strategy { // Silently allow compiling with panic=abort on these platforms, // but with old behavior (abort if a test fails). @@ -287,10 +287,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box { let ecx = &cx.ext_cx; let test_ident = Ident::new(sym::test, sp); - let runner_name = match cx.panic_strategy { - PanicStrategy::Unwind => "test_main_static", - PanicStrategy::Abort => "test_main_static_abort", - }; + let runner_name = + if cx.panic_strategy.unwinds() { "test_main_static" } else { "test_main_static_abort" }; // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| { diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index e9d72e457a08..e8672f49580b 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -15,9 +15,9 @@ use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::TyCtxt; use rustc_session::config::DebugInfo; use rustc_span::Symbol; +use rustc_target::spec::RelocModel; #[cfg(feature = "master")] use rustc_target::spec::SymbolVisibility; -use rustc_target::spec::{PanicStrategy, RelocModel}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -101,7 +101,7 @@ pub fn compile_codegen_unit( // Instantiate monomorphizations without filling out definitions yet... let context = new_context(tcx); - if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + if tcx.sess.panic_strategy().unwinds() { context.add_command_line_option("-fexceptions"); context.add_driver_option("-fexceptions"); } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 84fa56cf9030..a915f5d64188 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -29,7 +29,6 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::{ArgAbi, PassMode}; -use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] use crate::abi::FnAbiGccExt; @@ -1334,7 +1333,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( _catch_func: RValue<'gcc>, dest: PlaceRef<'tcx, RValue<'gcc>>, ) { - if bx.sess().panic_strategy() == PanicStrategy::Abort { + if !bx.sess().panic_strategy().unwinds() { bx.call(bx.type_void(), None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e7f4a3570488..50398a32142e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -18,7 +18,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; -use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -674,7 +673,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( catch_func: &'ll Value, dest: PlaceRef<'tcx, &'ll Value>, ) { - if bx.sess().panic_strategy() == PanicStrategy::Abort { + if !bx.sess().panic_strategy().unwinds() { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.call(try_func_ty, None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 45c5c9aa5514..3b920168e06d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -106,7 +106,7 @@ unsafe fn configure_llvm(sess: &Session) { if sess.target.os == "emscripten" && !sess.opts.unstable_opts.emscripten_wasm_eh - && sess.panic_strategy() == PanicStrategy::Unwind + && sess.panic_strategy().unwinds() { add("-enable-emscripten-cxx-exceptions", false); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 48b01ea2df19..327f001e1c85 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -47,8 +47,8 @@ use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, - LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, - SanitizerSet, SplitDebuginfo, + LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet, + SplitDebuginfo, }; use tracing::{debug, info, warn}; @@ -2512,10 +2512,10 @@ fn add_order_independent_options( if sess.target.os == "emscripten" { cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh { "-fwasm-exceptions" - } else if sess.panic_strategy() == PanicStrategy::Abort { - "-sDISABLE_EXCEPTION_CATCHING=1" - } else { + } else if sess.panic_strategy().unwinds() { "-sDISABLE_EXCEPTION_CATCHING=0" + } else { + "-sDISABLE_EXCEPTION_CATCHING=1" }); } diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 6f6666f8c76f..1f5c5e74d97a 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -47,7 +47,7 @@ interface_out_dir_error = failed to find or create the directory specified by `--out-dir` interface_proc_macro_crate_panic_abort = - building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic + building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6cefe8875306..761a5c809182 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -42,7 +42,6 @@ use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, }; -use rustc_target::spec::PanicStrategy; use rustc_trait_selection::{solve, traits}; use tracing::{info, instrument}; @@ -282,7 +281,7 @@ fn configure_and_expand( feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit(); } - if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort { + if is_proc_macro_crate && !sess.panic_strategy().unwinds() { sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort); } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index e104be2c4663..e624bfc5b8bd 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -98,6 +98,13 @@ metadata_full_metadata_not_found = metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait +metadata_incompatible_with_immediate_abort = + the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort` + +metadata_incompatible_with_immediate_abort_core = + the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` + .help = consider building the standard library from source with `cargo build -Zbuild-std` + metadata_incompatible_panic_in_drop_strategy = the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 9e23da88f5e1..7650acbd292d 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1027,6 +1027,10 @@ impl CStore { let name = match desired_strategy { PanicStrategy::Unwind => sym::panic_unwind, PanicStrategy::Abort => sym::panic_abort, + PanicStrategy::ImmediateAbort => { + // Immediate-aborting panics don't use a runtime. + return; + } }; info!("panic runtime not found -- loading {}", name); diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index fb9c2e23b715..8054a48d37af 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -61,11 +61,13 @@ use rustc_session::config::CrateType; use rustc_session::cstore::CrateDepKind; use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_span::sym; +use rustc_target::spec::PanicStrategy; use tracing::info; use crate::creader::CStore; use crate::errors::{ - BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired, + BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, + IncompatibleWithImmediateAbort, IncompatibleWithImmediateAbortCore, LibRequired, NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired, TwoPanicRuntimes, }; @@ -402,15 +404,43 @@ fn activate_injected_dep( /// there's only going to be one panic runtime in the output. fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { let sess = &tcx.sess; + let list: Vec<_> = list + .iter_enumerated() + .filter_map( + |(cnum, linkage)| if *linkage == Linkage::NotLinked { None } else { Some(cnum) }, + ) + .collect(); if list.is_empty() { return; } - let mut panic_runtime = None; - for (cnum, linkage) in list.iter_enumerated() { - if let Linkage::NotLinked = *linkage { - continue; - } + let desired_strategy = sess.panic_strategy(); + // If we are panic=immediate-abort, make sure everything in the dependency tree has also been + // compiled with immediate-abort. + if list + .iter() + .any(|cnum| tcx.required_panic_strategy(*cnum) == Some(PanicStrategy::ImmediateAbort)) + { + let mut invalid_crates = Vec::new(); + for cnum in list.iter().copied() { + if tcx.required_panic_strategy(cnum) != Some(PanicStrategy::ImmediateAbort) { + invalid_crates.push(cnum); + // If core is incompatible, it's very likely that we'd emit an error for every + // sysroot crate, so instead of doing that emit a single fatal error that suggests + // using build-std. + if tcx.crate_name(cnum) == sym::core { + sess.dcx().emit_fatal(IncompatibleWithImmediateAbortCore); + } + } + } + for cnum in invalid_crates { + sess.dcx() + .emit_err(IncompatibleWithImmediateAbort { crate_name: tcx.crate_name(cnum) }); + } + } + + let mut panic_runtime = None; + for cnum in list.iter().copied() { if tcx.is_panic_runtime(cnum) { if let Some((prev, _)) = panic_runtime { let prev_name = tcx.crate_name(prev); @@ -430,8 +460,6 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { // only one, but we perform validation here that all the panic strategy // compilation modes for the whole DAG are valid. if let Some((runtime_cnum, found_strategy)) = panic_runtime { - let desired_strategy = sess.panic_strategy(); - // First up, validate that our selected panic runtime is indeed exactly // our same strategy. if found_strategy != desired_strategy { @@ -445,10 +473,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { // strategy. If the dep isn't linked, we ignore it, and if our strategy // is abort then it's compatible with everything. Otherwise all crates' // panic strategy must match our own. - for (cnum, linkage) in list.iter_enumerated() { - if let Linkage::NotLinked = *linkage { - continue; - } + for cnum in list.iter().copied() { if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) { continue; } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index e5a4fd48353f..abfd078f7462 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -75,6 +75,16 @@ pub struct RequiredPanicStrategy { pub desired_strategy: PanicStrategy, } +#[derive(Diagnostic)] +#[diag(metadata_incompatible_with_immediate_abort)] +pub struct IncompatibleWithImmediateAbort { + pub crate_name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_with_immediate_abort_core)] +pub struct IncompatibleWithImmediateAbortCore; + #[derive(Diagnostic)] #[diag(metadata_incompatible_panic_in_drop_strategy)] pub struct IncompatiblePanicInDropStrategy { diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 93264f02cc25..a0e4c288c4a8 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -98,5 +98,6 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo } PanicStrategy::Unwind => true, + PanicStrategy::ImmediateAbort => false, } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c477e65f5d6b..47b45c58b9f8 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -16,7 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -1198,7 +1198,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) // // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"` // function defined in Rust is also required to abort. - if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) { + if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) { return false; } @@ -1206,7 +1206,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) // // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. - if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort + if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds() && tcx.is_lang_item(did, LangItem::DropInPlace) { return false; @@ -1245,7 +1245,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | RiscvInterruptS | RustInvalid | Unadjusted => false, - Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, + Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(), } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c1cd2788348a..c5cd06f170c4 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -86,7 +86,6 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::dummy_spanned; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::PanicStrategy; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; @@ -1149,7 +1148,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { // Nothing can unwind when landing pads are off. - if tcx.sess.panic_strategy() == PanicStrategy::Abort { + if !tcx.sess.panic_strategy().unwinds() { return false; } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index abbff1c48dd9..7c66783548ea 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -101,12 +101,15 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { } fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option { + let local_strategy = tcx.sess.panic_strategy(); + if tcx.is_panic_runtime(LOCAL_CRATE) { - return Some(tcx.sess.panic_strategy()); + return Some(local_strategy); } - if tcx.sess.panic_strategy() == PanicStrategy::Abort { - return Some(PanicStrategy::Abort); + match local_strategy { + PanicStrategy::Abort | PanicStrategy::ImmediateAbort => return Some(local_strategy), + _ => {} } for def_id in tcx.hir_body_owners() { diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 5b6d7ffb5110..b53c1f6d2020 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -1,7 +1,6 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::patch::MirPatch; @@ -13,7 +12,7 @@ pub(super) struct RemoveNoopLandingPads; impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.panic_strategy() != PanicStrategy::Abort + sess.panic_strategy().unwinds() } fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 795cb2b2cfeb..81ada79dd438 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -29,7 +29,8 @@ use rustc_span::{ SourceFileHashAlgorithm, Symbol, sym, }; use rustc_target::spec::{ - FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple, + FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo, + Target, TargetTuple, }; use tracing::debug; @@ -2799,6 +2800,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M } } + if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) { + early_dcx.early_fatal( + "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler", + ) + } + let crate_name = matches.opt_str("crate-name"); let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); // Parse any `-l` flags, which link to native libraries. diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 7e970461ab73..fc36fe9d5d76 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -125,7 +125,9 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { None | Some(_), ) => disallow(cfg, "-Z sanitizer=cfi"), (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"), - (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"), + (sym::panic, Some(sym::abort | sym::unwind | sym::immediate_abort)) => { + disallow(cfg, "-C panic") + } (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"), (sym::unix, None) | (sym::windows, None) @@ -204,6 +206,9 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { } ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); + if sess.panic_strategy() == PanicStrategy::ImmediateAbort { + ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol()); + } // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69facde69368..3b9d81177861 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -802,7 +802,7 @@ mod desc { pub(crate) const parse_threads: &str = parse_number; pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`"; pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`"; - pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`"; + pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`"; pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy; @@ -1165,6 +1165,7 @@ pub mod parse { match v { Some("unwind") => *slot = Some(PanicStrategy::Unwind), Some("abort") => *slot = Some(PanicStrategy::Abort), + Some("immediate-abort") => *slot = Some(PanicStrategy::ImmediateAbort), _ => return false, } true @@ -1174,6 +1175,7 @@ pub mod parse { match v { Some("unwind") => *slot = PanicStrategy::Unwind, Some("abort") => *slot = PanicStrategy::Abort, + Some("immediate-abort") => *slot = PanicStrategy::ImmediateAbort, _ => return false, } true diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d0dd2cdac0c4..25b46241c52d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -777,9 +777,11 @@ impl Session { // Otherwise, we can defer to the `-C force-unwind-tables=` // value, if it is provided, or disable them, if not. self.target.requires_uwtable - || self.opts.cg.force_unwind_tables.unwrap_or( - self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable, - ) + || self + .opts + .cg + .force_unwind_tables + .unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable) } /// Returns the number of query threads that should be used for this @@ -1229,7 +1231,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // KCFI requires panic=abort - if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort { + if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy().unwinds() { sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fef65f46b1f..efeb4371e4ca 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1195,6 +1195,7 @@ symbols! { if_let_rescope, if_while_or_patterns, ignore, + immediate_abort, impl_header_lifetime_elision, impl_lint_pass, impl_trait_in_assoc_type, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f705af52bd86..2299db94535d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -834,6 +834,7 @@ crate::target_spec_enum! { pub enum PanicStrategy { Unwind = "unwind", Abort = "abort", + ImmediateAbort = "immediate-abort", } parse_error_type = "panic strategy"; @@ -852,8 +853,13 @@ impl PanicStrategy { match *self { PanicStrategy::Unwind => sym::unwind, PanicStrategy::Abort => sym::abort, + PanicStrategy::ImmediateAbort => sym::immediate_abort, } } + + pub fn unwinds(self) -> bool { + matches!(self, PanicStrategy::Unwind) + } } crate::target_spec_enum! { diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 9ba7c5bd28a1..fb1f8c86dbfd 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -22,8 +22,6 @@ compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"] -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = ["core/panic_immediate_abort"] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 76630a746dd2..304b473f14df 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -408,12 +408,12 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { } } - #[cfg(not(feature = "panic_immediate_abort"))] + #[cfg(not(panic = "immediate_abort"))] { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } - #[cfg(feature = "panic_immediate_abort")] + #[cfg(panic = "immediate_abort")] ct_error(layout) } diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index b0027e964e46..4853b84a01a3 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -23,7 +23,7 @@ mod tests; // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] fn capacity_overflow() -> ! { panic!("capacity overflow"); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 10c7ee4f6c89..1a9041290ef1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2020,7 +2020,7 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2102,7 +2102,7 @@ impl Vec { #[must_use = "if you don't need a reference to the value, use `Vec::insert` instead"] pub fn insert_mut(&mut self, index: usize, element: T) -> &mut T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2166,7 +2166,7 @@ impl Vec { #[rustc_confusables("delete", "take")] pub fn remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2955,7 +2955,7 @@ impl Vec { A: Clone, { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(at: usize, len: usize) -> ! { diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 3e34e03a61e9..d094172b0765 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -16,7 +16,7 @@ test = false bench = false [features] -# Make panics and failed asserts immediately abort without formatting any message +# Issue a compile error that says to use -Cpanic=immediate-abort panic_immediate_abort = [] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = [] diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9b53b75ebee8..d7097e3b6fd4 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -778,7 +778,7 @@ impl Display for BorrowMutError { } // This ensures the panicking code is outlined from `borrow_mut` for `RefCell`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_borrowed(err: BorrowMutError) -> ! { @@ -790,7 +790,7 @@ const fn panic_already_borrowed(err: BorrowMutError) -> ! { } // This ensures the panicking code is outlined from `borrow` for `RefCell`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_mutably_borrowed(err: BorrowError) -> ! { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 54d5a63633c2..3c4bfe28aa32 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1387,8 +1387,8 @@ pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) radix <= 16 && digits.len() <= size_of::() * 2 - is_signed_ty as usize } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(panic = "immediate_abort", inline)] #[cold] #[track_caller] const fn from_ascii_radix_panic(radix: u32) -> ! { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 886d581b0a6b..10eec2cdfb6c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2161,8 +2161,8 @@ impl Option> { } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(panic = "immediate_abort", inline)] #[cold] #[track_caller] const fn unwrap_failed() -> ! { @@ -2170,8 +2170,8 @@ const fn unwrap_failed() -> ! { } // This is a separate function to reduce the code size of .expect() itself. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(panic = "immediate_abort", inline)] #[cold] #[track_caller] const fn expect_failed(msg: &str) -> ! { diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 804a12ee477b..da37d72960a6 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -33,7 +33,10 @@ use crate::intrinsics::const_eval_select; use crate::panic::{Location, PanicInfo}; #[cfg(feature = "panic_immediate_abort")] -const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort"); +compile_error!( + "panic_immediate_abort is now a real panic strategy! \ + Enable it with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`" +); // First we define the two main entry points that all panics go through. // In the end both are just convenience wrappers around `panic_impl`. @@ -44,16 +47,16 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -// If panic_immediate_abort, inline the abort call, +// If panic=immediate-abort, inline the abort call, // otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } @@ -78,8 +81,8 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { /// Like `panic_fmt`, but for non-unwinding panics. /// /// Has to be a separate function so that it can carry the `rustc_nounwind` attribute. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] // This attribute has the key side-effect that if the panic handler ignores `can_unwind` // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, @@ -94,7 +97,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. panic_fmt(fmt) } else #[track_caller] { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } @@ -123,10 +126,10 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // above. /// The underlying implementation of core's `panic!` macro when no formatting is used. -// Never inline unless panic_immediate_abort to avoid code +// Never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics @@ -158,10 +161,10 @@ macro_rules! panic_const { $( /// This is a panic called with a message that's a result of a MIR-produced Assert. // - // never inline unless panic_immediate_abort to avoid code + // never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] @@ -216,8 +219,8 @@ pub mod panic_const { /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller. /// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable @@ -226,8 +229,8 @@ pub const fn panic_nounwind(expr: &'static str) -> ! { } /// Like `panic_nounwind`, but also inhibits showing a backtrace. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[rustc_nounwind] pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); @@ -259,25 +262,25 @@ pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access fn panic_bounds_check(index: usize, len: usize) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } panic!("index out of bounds: the len is {len} but the index is {index}") } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref #[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } @@ -289,13 +292,13 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[lang = "panic_null_pointer_dereference"] // needed by codegen for panic on null pointer deref #[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind fn panic_null_pointer_dereference() -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } @@ -305,13 +308,13 @@ fn panic_null_pointer_dereference() -> ! { ) } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[lang = "panic_invalid_enum_construction"] // needed by codegen for panic on invalid enum construction. #[rustc_nounwind] // `CheckEnums` MIR pass requires this function to never unwind fn panic_invalid_enum_construction(source: u128) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { super::intrinsics::abort() } @@ -328,8 +331,8 @@ fn panic_invalid_enum_construction(source: u128) -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_cannot_unwind() -> ! { @@ -344,8 +347,8 @@ fn panic_cannot_unwind() -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_in_cleanup() -> ! { @@ -377,8 +380,8 @@ pub enum AssertKind { } /// Internal function for `assert_eq!` and `assert_ne!` macros -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_failed( @@ -395,8 +398,8 @@ where } /// Internal function for `assert_match!` -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_matches_failed( @@ -415,8 +418,8 @@ pub fn assert_matches_failed( } /// Non-generic version of the above functions, to avoid code bloat. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] fn assert_failed_inner( kind: AssertKind, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5c1f64bfe14a..742f1c19112b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1847,7 +1847,7 @@ impl Result, E> { } // This is a separate function to reduce the code size of the methods -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate_abort"))] #[inline(never)] #[cold] #[track_caller] @@ -1859,7 +1859,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { // that gets immediately thrown away, since vtables don't get cleaned up // by dead code elimination if a trait object is constructed even if it goes // unused -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate_abort")] #[inline] #[cold] #[track_caller] diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index a8147d745f3a..c1a55c1f62a2 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,8 +31,8 @@ where } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! { if start > len { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dfbb3628350a..e8b2712e147c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3858,8 +3858,8 @@ impl [T] { { // The panic code path was put into a cold function to not bloat the // call site. - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { const_panic!( diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 400daba16c1b..17858bf9f0d0 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -840,8 +840,8 @@ unsafe fn bidirectional_merge bool>( } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate_abort", inline)] fn panic_on_ord_violation() -> ! { // This is indicative of a logic bug in the user-provided comparison function or Ord // implementation. They are expected to implement a total order as explained in the Ord diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 04fdaa8143ef..910ea2948ee1 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -64,12 +64,12 @@ pub use validations::{next_code_point, utf8_char_width}; #[cold] #[track_caller] #[rustc_allow_const_fn_unstable(const_eval_select)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate_abort"))] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { crate::intrinsics::const_eval_select((s, begin, end), slice_error_fail_ct, slice_error_fail_rt) } -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate_abort")] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { slice_error_fail_ct(s, begin, end) } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d28a7f0b4602..958cafb8f3d4 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -106,11 +106,6 @@ compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = [ - "core/panic_immediate_abort", - "alloc/panic_immediate_abort", -] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8b7282c51d12..5d52bc366bd7 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -331,7 +331,7 @@ fn default_hook(info: &PanicHookInfo<'_>) { #[cfg(not(test))] #[doc(hidden)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate_abort")] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { /// A reason for forcing an immediate abort on panic. @@ -371,7 +371,7 @@ pub mod panic_count { #[cfg(not(test))] #[doc(hidden)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate_abort"))] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { use crate::cell::Cell; @@ -499,13 +499,13 @@ pub mod panic_count { pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate_abort")] pub unsafe fn catch_unwind R>(f: F) -> Result> { Ok(f()) } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate_abort"))] pub unsafe fn catch_unwind R>(f: F) -> Result> { union Data { f: ManuallyDrop, @@ -720,14 +720,14 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] #[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] // lang item for CTFE panic support -// never inline unless panic_immediate_abort to avoid code +// never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate_abort", inline)] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic(msg: M) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate_abort") { intrinsics::abort() } @@ -861,7 +861,7 @@ fn panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(panic = "immediate_abort", inline)] pub fn resume_unwind(payload: Box) -> ! { panic_count::increase(false); @@ -890,16 +890,14 @@ pub fn resume_unwind(payload: Box) -> ! { /// on which to slap yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate_abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - unsafe { - crate::intrinsics::abort(); - } + crate::intrinsics::abort(); } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 8d95cc1fb574..d98f2e692cd5 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -39,11 +39,11 @@ fn __rust_abort() { // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { - #[cfg(not(feature = "panic_immediate_abort"))] + #[cfg(not(panic = "immediate_abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } - #[cfg(feature = "panic_immediate_abort")] + #[cfg(panic = "immediate_abort")] { let _ = format_args!($($t)*); } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 797feeb2bbb5..b49de8d1b608 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -230,7 +230,7 @@ impl fmt::Display for AccessError { impl Error for AccessError {} // This ensures the panicking code is outlined from `with` for `LocalKey`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate_abort"), inline(never))] #[track_caller] #[cold] fn panic_access_error(err: AccessError) -> ! { diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 7b4aeed94e98..ee4aec61872e 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -31,7 +31,6 @@ llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] panic-unwind = ["std/panic-unwind"] -panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 445b10188e3f..0e340de4daa2 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -471,11 +471,13 @@ If not specified, overflow checks are enabled if This option lets you control what happens when the code panics. * `abort`: terminate the process upon panic +* `immediate-abort`: terminate the process upon panic, and do not call any panic hooks * `unwind`: unwind the stack upon panic If not specified, the default depends on the target. If any crate in the crate graph uses `abort`, the final binary (`bin`, `dylib`, `cdylib`, `staticlib`) must also use `abort`. +If any crate in the crate graph uses `immediate-abort`, every crate in the graph must use `immediate-abort`. If `std` is used as a `dylib` with `unwind`, the final binary must also use `unwind`. ## passes diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 1277fd225eb6..e84a22787668 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -201,6 +201,8 @@ pub struct TestProps { /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios /// that don't otherwise want/need `-Z build-std`. pub add_core_stubs: bool, + /// Add these flags to the build of `minicore`. + pub core_stubs_compile_flags: Vec, /// Whether line annotatins are required for the given error kind. pub dont_require_annotations: HashSet, /// Whether pretty printers should be disabled in gdb. @@ -253,6 +255,7 @@ mod directives { pub const FILECHECK_FLAGS: &'static str = "filecheck-flags"; pub const NO_AUTO_CHECK_CFG: &'static str = "no-auto-check-cfg"; pub const ADD_CORE_STUBS: &'static str = "add-core-stubs"; + pub const CORE_STUBS_COMPILE_FLAGS: &'static str = "core-stubs-compile-flags"; // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers"; @@ -311,6 +314,7 @@ impl TestProps { no_auto_check_cfg: false, has_enzyme: false, add_core_stubs: false, + core_stubs_compile_flags: vec![], dont_require_annotations: Default::default(), disable_gdb_pretty_printers: false, compare_output_by_lines: false, @@ -653,6 +657,21 @@ impl TestProps { self.update_add_core_stubs(ln, config); + if let Some(flags) = config.parse_name_value_directive( + ln, + directives::CORE_STUBS_COMPILE_FLAGS, + testfile, + line_number, + ) { + let flags = split_flags(&flags); + for flag in &flags { + if flag == "--edition" || flag.starts_with("--edition=") { + panic!("you must use `//@ edition` to configure the edition"); + } + } + self.core_stubs_compile_flags.extend(flags); + } + if let Some(err_kind) = config.parse_name_value_directive( ln, DONT_REQUIRE_ANNOTATIONS, diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 0ef84fb45949..4fef89925673 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -19,6 +19,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "check-test-line-numbers-match", "compare-output-by-lines", "compile-flags", + "core-stubs-compile-flags", "disable-gdb-pretty-printers", "doc-flags", "dont-check-compiler-stderr", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 89fb8eb4357b..29578acb4040 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1322,6 +1322,7 @@ impl<'test> TestCx<'test> { rustc.args(&["--crate-type", "rlib"]); rustc.arg("-Cpanic=abort"); + rustc.args(self.props.core_stubs_compile_flags.clone()); let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None); if !res.status.success() { @@ -1432,6 +1433,12 @@ impl<'test> TestCx<'test> { aux_rustc.arg("-L").arg(&aux_dir); + if aux_props.add_core_stubs { + let minicore_path = self.build_minicore(); + aux_rustc.arg("--extern"); + aux_rustc.arg(&format!("minicore={}", minicore_path)); + } + let auxres = aux_cx.compose_and_run( aux_rustc, aux_cx.config.compile_lib_path.as_path(), @@ -1858,14 +1865,13 @@ impl<'test> TestCx<'test> { } } - rustc.args(&self.props.compile_flags); - // FIXME(jieyouxu): we should report a fatal error or warning if user wrote `-Cpanic=` with - // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`, - // however, by moving this last we should override previous `-Cpanic`s and - // `-Cforce-unwind-tables`s. Note that checking here is very fragile, because we'd have to - // account for all possible compile flag splittings (they have some... intricacies and are - // not yet normalized). + // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`. + // + // We could apply these last and override any provided flags. That would ensure that the + // build works, but some tests want to exercise that mixing panic modes in specific ways is + // rejected. So we enable aborting panics and unwind tables before adding flags, just to + // change the default. // // `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics. if self.props.add_core_stubs { @@ -1873,6 +1879,8 @@ impl<'test> TestCx<'test> { rustc.arg("-Cforce-unwind-tables=yes"); } + rustc.args(&self.props.compile_flags); + rustc } diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml new file mode 100644 index 000000000000..3c61c12a84ed --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml @@ -0,0 +1,12 @@ +cargo-features = ["profile-rustflags"] + +[package] +name = "panic_scenarios" +version = "0.1.0" +edition = "2024" + +[lib] +path = "lib.rs" + +[profile.release] +rustflags = ["-Zmerge-functions=disabled", "-Zcodegen-source-order", "--emit=llvm-ir"] diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs new file mode 100644 index 000000000000..1e20da93ba80 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs @@ -0,0 +1,65 @@ +#![no_std] + +#[unsafe(no_mangle)] +pub fn panic_noarg() { + // CHECK-LABEL: @panic_noarg( + // CHECK-NEXT: start: + // CHECK-NEXT: tail call void @llvm.trap() + panic!(); +} + +#[unsafe(no_mangle)] +pub fn panic_str() { + // CHECK-LABEL: @panic_str( + // CHECK-NEXT: start: + // CHECK-NEXT: tail call void @llvm.trap() + panic!("ouch"); +} + +#[unsafe(no_mangle)] +pub fn bounds_check(x: &[u8], idx: usize) -> &u8 { + // CHECK-LABEL: @bounds_check( + // CHECK-NEXT: start: + // CHECK-NEXT: icmp ult + // CHECK-NEXT: br i1 + // CHECK: bb1: + // CHECK-NEXT: getelementptr inbounds nuw i8 + // CHECK-NEXT: ret ptr + // CHECK: panic: + // CHECK-NEXT: tail call void @llvm.trap() + &x[idx] +} + +#[unsafe(no_mangle)] +pub fn str_bounds_check(x: &str, idx: usize) -> &str { + // CHECK-LABEL: @str_bounds_check( + // CHECK-NOT: call + // CHECK: tail call void @llvm.trap() + // CHECK-NOT: call + &x[idx..] +} + +#[unsafe(no_mangle)] +pub fn unsigned_integer_div(x: u16, y: u16) -> u16 { + // CHECK-LABEL: @unsigned_integer_div( + // CHECK-NEXT: start: + // CHECK-NEXT: icmp eq i16 + // CHECK-NEXT: br i1 + // CHECK: bb1: + // CHECK-NEXT: udiv i16 + // CHECK-NEXT: ret i16 + // CHECK: panic: + // CHECK-NEXT: tail call void @llvm.trap() + x / y +} + +#[unsafe(no_mangle)] +pub fn refcell_already_borrowed() { + // CHECK-LABEL: @refcell_already_borrowed( + // CHECK-NOT: call + // CHECK: tail call void @llvm.trap() + // CHECK-NOT: call + let r = core::cell::RefCell::new(0u8); + let _guard = r.borrow_mut(); + r.borrow_mut(); +} diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs new file mode 100644 index 000000000000..e91d1db83d1d --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs @@ -0,0 +1,41 @@ +#![deny(warnings)] + +use run_make_support::{cargo, llvm_filecheck, path, rfs, target}; + +fn main() { + let target_dir = path("target"); + + cargo() + .args(&[ + "build", + "--release", + "--lib", + "--manifest-path", + "Cargo.toml", + "-Zbuild-std=core", + "--target", + &target(), + ]) + .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort") + .env("CARGO_TARGET_DIR", &target_dir) + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()) + .run(); + + let out_dir = target_dir.join(target()).join("release").join("deps"); + let ir_file = rfs::read_dir(out_dir) + .find_map(|e| { + let path = e.unwrap().path(); + let file_name = path.file_name().unwrap().to_str().unwrap(); + if file_name.starts_with("panic_scenarios") && file_name.ends_with(".ll") { + Some(path) + } else { + None + } + }) + .unwrap(); + + llvm_filecheck().patterns("lib.rs").input_file(ir_file).run(); +} diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml new file mode 100644 index 000000000000..1e278d557c08 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2024" diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs new file mode 100644 index 000000000000..a3c5877a6a19 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs @@ -0,0 +1,28 @@ +//@ needs-target-std + +#![deny(warnings)] + +use run_make_support::{cargo, path, target}; + +fn main() { + let target_dir = path("target"); + + cargo() + .current_dir("hello") + .args(&[ + "build", + "--release", + "--manifest-path", + "Cargo.toml", + "-Zbuild-std", + "--target", + &target(), + ]) + .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort") + .env("CARGO_TARGET_DIR", &target_dir) + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()) + .run(); +} diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr index 989a01f22441..b99ce169b890 100644 --- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro` diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr index 95d10e014f33..8e1760bd969a 100644 --- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 6490fc63fd76..c34c20b172d5 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -80,7 +80,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/panic-runtime/auxiliary/needs-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-abort.rs index 21f862e4b431..cba4907dbb63 100644 --- a/tests/ui/panic-runtime/auxiliary/needs-abort.rs +++ b/tests/ui/panic-runtime/auxiliary/needs-abort.rs @@ -1,5 +1,7 @@ //@ compile-flags:-C panic=abort //@ no-prefer-dynamic +#![feature(no_core)] #![crate_type = "rlib"] #![no_std] +#![no_core] diff --git a/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs new file mode 100644 index 000000000000..4a41d16faa08 --- /dev/null +++ b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs @@ -0,0 +1,7 @@ +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_std] +#![no_core] diff --git a/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs new file mode 100644 index 000000000000..295876fec527 --- /dev/null +++ b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs @@ -0,0 +1,18 @@ +//@ compile-flags:-C panic=unwind +//@ no-prefer-dynamic +//@ add-core-stubs + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate minicore; + +extern "C-unwind" fn foo() {} + +#[inline] +fn bar() { + let ptr: extern "C-unwind" fn() = foo; + ptr(); +} diff --git a/tests/ui/panic-runtime/bad-panic-flag1.rs b/tests/ui/panic-runtime/bad-panic-flag1.rs index 117935847cbd..575e30f785cf 100644 --- a/tests/ui/panic-runtime/bad-panic-flag1.rs +++ b/tests/ui/panic-runtime/bad-panic-flag1.rs @@ -2,4 +2,4 @@ fn main() {} -//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected +//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected diff --git a/tests/ui/panic-runtime/bad-panic-flag1.stderr b/tests/ui/panic-runtime/bad-panic-flag1.stderr index 013373c6f931..c30598bba538 100644 --- a/tests/ui/panic-runtime/bad-panic-flag1.stderr +++ b/tests/ui/panic-runtime/bad-panic-flag1.stderr @@ -1,2 +1,2 @@ -error: incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected +error: incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected diff --git a/tests/ui/panic-runtime/bad-panic-flag2.rs b/tests/ui/panic-runtime/bad-panic-flag2.rs index b5d0442a0332..4e34da217d7d 100644 --- a/tests/ui/panic-runtime/bad-panic-flag2.rs +++ b/tests/ui/panic-runtime/bad-panic-flag2.rs @@ -2,4 +2,4 @@ fn main() {} -//~? ERROR codegen option `panic` requires either `unwind` or `abort` +//~? ERROR codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort` diff --git a/tests/ui/panic-runtime/bad-panic-flag2.stderr b/tests/ui/panic-runtime/bad-panic-flag2.stderr index 6ab94ea704d3..c8d12749c5d9 100644 --- a/tests/ui/panic-runtime/bad-panic-flag2.stderr +++ b/tests/ui/panic-runtime/bad-panic-flag2.stderr @@ -1,2 +1,2 @@ -error: codegen option `panic` requires either `unwind` or `abort` (C panic=) +error: codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort` (C panic=) diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs new file mode 100644 index 000000000000..94dc7c5671ea --- /dev/null +++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs @@ -0,0 +1,15 @@ +//@ build-fail +//@ aux-build:needs-unwind.rs +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic + +extern crate needs_unwind; + +// immediate-abort does not require any panic runtime, so trying to build a binary crate with +// panic=immediate-abort and the precompiled sysroot will fail to link, because no panic runtime +// provides the panic entrypoints used by sysroot crates. +// This test ensures that we get a clean compile error instead of a linker error. + +fn main() {} + +//~? ERROR the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr new file mode 100644 index 000000000000..bd6bdd8b6673 --- /dev/null +++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr @@ -0,0 +1,4 @@ +error: the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs new file mode 100644 index 000000000000..78977c60be98 --- /dev/null +++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs @@ -0,0 +1,21 @@ +//@ build-fail +//@ aux-build:needs-abort.rs +//@ compile-flags:-Cpanic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Cpanic=immediate-abort -Zunstable-options + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_abort; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr new file mode 100644 index 000000000000..65a26b676b92 --- /dev/null +++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs new file mode 100644 index 000000000000..1c5f597a3f99 --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs @@ -0,0 +1,20 @@ +//@ build-fail +//@ aux-build:needs-immediate-abort.rs +//@ compile-flags:-C panic=abort +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_immediate_abort; + +extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr new file mode 100644 index 000000000000..8dcf120cb9f4 --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs new file mode 100644 index 000000000000..24d521230d49 --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs @@ -0,0 +1,20 @@ +//@ build-fail +//@ needs-unwind +//@ aux-build:needs-immediate-abort.rs +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_immediate_abort; + +extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr new file mode 100644 index 000000000000..740fc80a77df --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr @@ -0,0 +1,4 @@ +error: the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs new file mode 100644 index 000000000000..5aec028a46cf --- /dev/null +++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs @@ -0,0 +1,21 @@ +//@ build-fail +//@ aux-build:needs-unwind-immediate-abort.rs +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_unwind_immediate_abort; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr new file mode 100644 index 000000000000..8b3747d644f1 --- /dev/null +++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs index 58e1d0064330..adedba4ebca6 100644 --- a/tests/ui/proc-macro/panic-abort.rs +++ b/tests/ui/proc-macro/panic-abort.rs @@ -2,4 +2,4 @@ //@ force-host //@ check-pass -//~? WARN building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +//~? WARN building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr index a6e18614f8f0..3dd75768bc4a 100644 --- a/tests/ui/proc-macro/panic-abort.stderr +++ b/tests/ui/proc-macro/panic-abort.stderr @@ -1,4 +1,4 @@ -warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +warning: building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic warning: 1 warning emitted From df58fd8cf7710f7516c541769a141f0235978dab Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 18 Sep 2025 10:48:18 -0400 Subject: [PATCH 119/537] Change the cfg to a dash --- compiler/rustc_span/src/symbol.rs | 2 +- library/alloc/src/alloc.rs | 4 +- library/alloc/src/raw_vec/mod.rs | 2 +- library/alloc/src/vec/mod.rs | 8 +-- library/core/src/cell.rs | 4 +- library/core/src/num/mod.rs | 4 +- library/core/src/option.rs | 8 +-- library/core/src/panicking.rs | 72 +++++++++---------- library/core/src/result.rs | 4 +- library/core/src/slice/index.rs | 4 +- library/core/src/slice/mod.rs | 4 +- .../core/src/slice/sort/shared/smallsort.rs | 4 +- library/core/src/str/mod.rs | 4 +- library/std/src/panicking.rs | 20 +++--- library/std/src/rt.rs | 4 +- library/std/src/thread/local.rs | 2 +- .../report-in-external-macros.cargo.stderr | 2 +- .../report-in-external-macros.rustc.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- 19 files changed, 78 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efeb4371e4ca..a2840828b19b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1195,7 +1195,7 @@ symbols! { if_let_rescope, if_while_or_patterns, ignore, - immediate_abort, + immediate_abort: "immediate-abort", impl_header_lifetime_elision, impl_lint_pass, impl_trait_in_assoc_type, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 304b473f14df..65c8206e9d46 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -408,12 +408,12 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { } } - #[cfg(not(panic = "immediate_abort"))] + #[cfg(not(panic = "immediate-abort"))] { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } - #[cfg(panic = "immediate_abort")] + #[cfg(panic = "immediate-abort")] ct_error(layout) } diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 4853b84a01a3..b7c153b825df 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -23,7 +23,7 @@ mod tests; // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] fn capacity_overflow() -> ! { panic!("capacity overflow"); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1a9041290ef1..ebdb86f98a85 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2020,7 +2020,7 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(panic = "immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2102,7 +2102,7 @@ impl Vec { #[must_use = "if you don't need a reference to the value, use `Vec::insert` instead"] pub fn insert_mut(&mut self, index: usize, element: T) -> &mut T { #[cold] - #[cfg_attr(not(panic = "immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2166,7 +2166,7 @@ impl Vec { #[rustc_confusables("delete", "take")] pub fn remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(panic = "immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2955,7 +2955,7 @@ impl Vec { A: Clone, { #[cold] - #[cfg_attr(not(panic = "immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(at: usize, len: usize) -> ! { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d7097e3b6fd4..7d4a66640b10 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -778,7 +778,7 @@ impl Display for BorrowMutError { } // This ensures the panicking code is outlined from `borrow_mut` for `RefCell`. -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_borrowed(err: BorrowMutError) -> ! { @@ -790,7 +790,7 @@ const fn panic_already_borrowed(err: BorrowMutError) -> ! { } // This ensures the panicking code is outlined from `borrow` for `RefCell`. -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_mutably_borrowed(err: BorrowError) -> ! { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 3c4bfe28aa32..c75ee11d15ef 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1387,8 +1387,8 @@ pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) radix <= 16 && digits.len() <= size_of::() * 2 - is_signed_ty as usize } -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn from_ascii_radix_panic(radix: u32) -> ! { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 10eec2cdfb6c..430ee3470ac3 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2161,8 +2161,8 @@ impl Option> { } } -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn unwrap_failed() -> ! { @@ -2170,8 +2170,8 @@ const fn unwrap_failed() -> ! { } // This is a separate function to reduce the code size of .expect() itself. -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn expect_failed(msg: &str) -> ! { diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index da37d72960a6..3f30038dbc03 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -49,14 +49,14 @@ compile_error!( /// the actual formatting into this shared place. // If panic=immediate-abort, inline the abort call, // otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -81,8 +81,8 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { /// Like `panic_fmt`, but for non-unwinding panics. /// /// Has to be a separate function so that it can carry the `rustc_nounwind` attribute. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] // This attribute has the key side-effect that if the panic handler ignores `can_unwind` // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, @@ -97,7 +97,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. panic_fmt(fmt) } else #[track_caller] { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -128,8 +128,8 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo /// The underlying implementation of core's `panic!` macro when no formatting is used. // Never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics @@ -163,8 +163,8 @@ macro_rules! panic_const { // // never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible - #[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] - #[cfg_attr(panic = "immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] @@ -219,8 +219,8 @@ pub mod panic_const { /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller. /// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable @@ -229,8 +229,8 @@ pub const fn panic_nounwind(expr: &'static str) -> ! { } /// Like `panic_nounwind`, but also inhibits showing a backtrace. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[rustc_nounwind] pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); @@ -262,25 +262,25 @@ pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access fn panic_bounds_check(index: usize, len: usize) -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } panic!("index out of bounds: the len is {len} but the index is {index}") } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref #[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -292,13 +292,13 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_null_pointer_dereference"] // needed by codegen for panic on null pointer deref #[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind fn panic_null_pointer_dereference() -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -308,13 +308,13 @@ fn panic_null_pointer_dereference() -> ! { ) } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_invalid_enum_construction"] // needed by codegen for panic on invalid enum construction. #[rustc_nounwind] // `CheckEnums` MIR pass requires this function to never unwind fn panic_invalid_enum_construction(source: u128) -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -331,8 +331,8 @@ fn panic_invalid_enum_construction(source: u128) -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_cannot_unwind() -> ! { @@ -347,8 +347,8 @@ fn panic_cannot_unwind() -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_in_cleanup() -> ! { @@ -380,8 +380,8 @@ pub enum AssertKind { } /// Internal function for `assert_eq!` and `assert_ne!` macros -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_failed( @@ -398,8 +398,8 @@ where } /// Internal function for `assert_match!` -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_matches_failed( @@ -418,8 +418,8 @@ pub fn assert_matches_failed( } /// Non-generic version of the above functions, to avoid code bloat. -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] fn assert_failed_inner( kind: AssertKind, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 742f1c19112b..c69762a72859 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1847,7 +1847,7 @@ impl Result, E> { } // This is a separate function to reduce the code size of the methods -#[cfg(not(panic = "immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] #[inline(never)] #[cold] #[track_caller] @@ -1859,7 +1859,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { // that gets immediately thrown away, since vtables don't get cleaned up // by dead code elimination if a trait object is constructed even if it goes // unused -#[cfg(panic = "immediate_abort")] +#[cfg(panic = "immediate-abort")] #[inline] #[cold] #[track_caller] diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index c1a55c1f62a2..d3de81555c49 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,8 +31,8 @@ where } } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! { if start > len { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e8b2712e147c..f7f5ee819b2e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3858,8 +3858,8 @@ impl [T] { { // The panic code path was put into a cold function to not bloat the // call site. - #[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] - #[cfg_attr(panic = "immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { const_panic!( diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 17858bf9f0d0..e555fce44087 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -840,8 +840,8 @@ unsafe fn bidirectional_merge bool>( } } -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold)] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] fn panic_on_ord_violation() -> ! { // This is indicative of a logic bug in the user-provided comparison function or Ord // implementation. They are expected to implement a total order as explained in the Ord diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 910ea2948ee1..2e473d348b0b 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -64,12 +64,12 @@ pub use validations::{next_code_point, utf8_char_width}; #[cold] #[track_caller] #[rustc_allow_const_fn_unstable(const_eval_select)] -#[cfg(not(panic = "immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { crate::intrinsics::const_eval_select((s, begin, end), slice_error_fail_ct, slice_error_fail_rt) } -#[cfg(panic = "immediate_abort")] +#[cfg(panic = "immediate-abort")] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { slice_error_fail_ct(s, begin, end) } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 5d52bc366bd7..b7be869c4eb4 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -331,7 +331,7 @@ fn default_hook(info: &PanicHookInfo<'_>) { #[cfg(not(test))] #[doc(hidden)] -#[cfg(panic = "immediate_abort")] +#[cfg(panic = "immediate-abort")] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { /// A reason for forcing an immediate abort on panic. @@ -371,7 +371,7 @@ pub mod panic_count { #[cfg(not(test))] #[doc(hidden)] -#[cfg(not(panic = "immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { use crate::cell::Cell; @@ -499,13 +499,13 @@ pub mod panic_count { pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(panic = "immediate_abort")] +#[cfg(panic = "immediate-abort")] pub unsafe fn catch_unwind R>(f: F) -> Result> { Ok(f()) } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(not(panic = "immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] pub unsafe fn catch_unwind R>(f: F) -> Result> { union Data { f: ManuallyDrop, @@ -722,12 +722,12 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { // lang item for CTFE panic support // never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(panic = "immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic(msg: M) -> ! { - if cfg!(panic = "immediate_abort") { + if cfg!(panic = "immediate-abort") { intrinsics::abort() } @@ -861,7 +861,7 @@ fn panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. -#[cfg_attr(panic = "immediate_abort", inline)] +#[cfg_attr(panic = "immediate-abort", inline)] pub fn resume_unwind(payload: Box) -> ! { panic_count::increase(false); @@ -890,14 +890,14 @@ pub fn resume_unwind(payload: Box) -> ! { /// on which to slap yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(not(panic = "immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(panic = "immediate_abort")] +#[cfg(panic = "immediate-abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { crate::intrinsics::abort(); } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index d98f2e692cd5..2717b7b469ce 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -39,11 +39,11 @@ fn __rust_abort() { // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { - #[cfg(not(panic = "immediate_abort"))] + #[cfg(not(panic = "immediate-abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } - #[cfg(panic = "immediate_abort")] + #[cfg(panic = "immediate-abort")] { let _ = format_args!($($t)*); } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index b49de8d1b608..0a6f2e5d5088 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -230,7 +230,7 @@ impl fmt::Display for AccessError { impl Error for AccessError {} // This ensures the panicking code is outlined from `with` for `LocalKey`. -#[cfg_attr(not(panic = "immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] fn panic_access_error(err: AccessError) -> ! { diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr index b99ce169b890..4b5fc91c7eb9 100644 --- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro` diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr index 8e1760bd969a..0d99d061d28d 100644 --- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index c34c20b172d5..43dd53939cb0 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -80,7 +80,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort`, `immediate_abort`, and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From aef02fb864349a249207cbd14b51b9fe5f5691ca Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 21 Sep 2025 13:04:59 -0400 Subject: [PATCH 120/537] Explain tests and setting cfgs --- compiler/rustc_session/src/config/cfg.rs | 4 ++++ tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs | 5 +++++ tests/run-make-cargo/panic-immediate-abort-works/rmake.rs | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index fc36fe9d5d76..f3d91ce4a5dd 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -205,6 +205,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::overflow_checks); } + // We insert a cfg for the name of session's panic strategy. + // Since the ImmediateAbort strategy is new, it also sets cfg(panic="abort"), so that code + // which is trying to detect whether unwinding is enabled by checking for cfg(panic="abort") + // does not need to be updated. ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); if sess.panic_strategy() == PanicStrategy::ImmediateAbort { ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol()); diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs index e91d1db83d1d..d7a7a8bfd8c3 100644 --- a/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs @@ -1,3 +1,8 @@ +// This is a codegen test which checks that when code is compiled with panic=immediate-abort, +// we get a `tail call void @llvm.trap()` in user code instead of a call into the standard +// library's panic formatting code (such as panic_fmt) or one of the numerous panic outlining shims +// (such as slice_index_fail). + #![deny(warnings)] use run_make_support::{cargo, llvm_filecheck, path, rfs, target}; diff --git a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs index a3c5877a6a19..bb15bd41e79c 100644 --- a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs +++ b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs @@ -1,3 +1,9 @@ +// This test ensures we are able to compile and link a simple binary with panic=immediate-abort. +// The test panic-immediate-abort-codegen checks that panic strategy produces the desired codegen, +// but is based on compiling a library crate (which is the norm for codegen tests because it is +// cleaner and more portable). So this test ensures that we didn't mix up a cfg or a compiler +// implementation detail in a way that makes panic=immediate-abort encounter errors at link time. + //@ needs-target-std #![deny(warnings)] From 5f0a68eb220c4aa780e0206ee6c6273413d8d5fd Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 15 Aug 2025 01:20:37 +0200 Subject: [PATCH 121/537] regression test for https://github.com/rust-lang/rust/issues/117763 --- .../issues/cows-dont-have-branches-117763.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs diff --git a/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs new file mode 100644 index 000000000000..b97729fa1465 --- /dev/null +++ b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +//@ needs-deterministic-layouts + +// Currently Vec and &[T] have layouts that start with (pointer, len) +// which makes the conversion branchless. +// A nice-to-have property, not guaranteed. +#![crate_type = "cdylib"] + +// CHECK-LABEL: @branchless_cow_slices +#[no_mangle] +pub fn branchless_cow_slices<'a>(cow: &'a std::borrow::Cow<'a, [u8]>) -> &'a [u8] { + // CHECK-NOT: br + // CHECK-NOT: select + // CHECK-NOT: icmp + // CHECK: ret { ptr, {{i32|i64}} } + &*cow +} From 97b2292b065f825d482899149001a74b6a5450c4 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 17 Sep 2025 10:26:52 -0400 Subject: [PATCH 122/537] Allow shared access to `Exclusive` when `T: Sync` --- library/core/src/sync/exclusive.rs | 114 ++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 10 deletions(-) diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index cf086bf4f508..f181c5514f25 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -1,28 +1,32 @@ //! Defines [`Exclusive`]. +use core::cmp::Ordering; use core::fmt; use core::future::Future; -use core::marker::Tuple; +use core::hash::{Hash, Hasher}; +use core::marker::{StructuralPartialEq, Tuple}; use core::ops::{Coroutine, CoroutineState}; use core::pin::Pin; use core::task::{Context, Poll}; -/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_ -/// access to the underlying value. It provides no _immutable_, or _shared_ -/// access to the underlying value. +/// `Exclusive` provides _mutable_ access, also referred to as _exclusive_ +/// access to the underlying value. However, it only permits _immutable_, or _shared_ +/// access to the underlying value when that value is [`Sync`]. /// /// While this may seem not very useful, it allows `Exclusive` to _unconditionally_ -/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive` +/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `Exclusive` /// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound -/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API -/// whatsoever, making it useless, thus harmless, thus memory safe. +/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` for non-`Sync` T +/// has no API whatsoever, making it useless, thus harmless, thus memory safe. /// /// Certain constructs like [`Future`]s can only be used with _exclusive_ access, /// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the /// Rust compiler that something is `Sync` in practice. /// /// ## Examples -/// Using a non-`Sync` future prevents the wrapping struct from being `Sync` +/// +/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`: +/// /// ```compile_fail /// use core::cell::Cell; /// @@ -43,7 +47,8 @@ use core::task::{Context, Poll}; /// ``` /// /// `Exclusive` ensures the struct is `Sync` without stripping the future of its -/// functionality. +/// functionality: +/// /// ``` /// #![feature(exclusive_wrapper)] /// use core::cell::Cell; @@ -66,6 +71,7 @@ use core::task::{Context, Poll}; /// ``` /// /// ## Parallels with a mutex +/// /// In some sense, `Exclusive` can be thought of as a _compile-time_ version of /// a mutex, as the borrow-checker guarantees that only one `&mut` can exist /// for any value. This is a parallel with the fact that @@ -75,7 +81,7 @@ use core::task::{Context, Poll}; #[doc(alias = "SyncWrapper")] #[doc(alias = "SyncCell")] #[doc(alias = "Unique")] -// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would +// `Exclusive` can't have derived `PartialOrd`, `Clone`, etc. impls as they would // use `&` access to the inner value, violating the `Sync` impl's safety // requirements. #[derive(Default)] @@ -195,6 +201,17 @@ where } } +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Fn for Exclusive +where + F: Sync + Fn, + Args: Tuple, +{ + extern "rust-call" fn call(&self, args: Args) -> Self::Output { + self.as_ref().call(args) + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Future for Exclusive where @@ -221,3 +238,80 @@ where G::resume(self.get_pin_mut(), arg) } } + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl AsRef for Exclusive +where + T: Sync + ?Sized, +{ + #[inline] + fn as_ref(&self) -> &T { + &self.inner + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Clone for Exclusive +where + T: Sync + Clone, +{ + #[inline] + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Copy for Exclusive where T: Sync + Copy {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl PartialEq> for Exclusive +where + T: Sync + PartialEq + ?Sized, + U: Sync + ?Sized, +{ + #[inline] + fn eq(&self, other: &Exclusive) -> bool { + self.inner == other.inner + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl StructuralPartialEq for Exclusive where T: Sync + StructuralPartialEq + ?Sized {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Eq for Exclusive where T: Sync + Eq + ?Sized {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Hash for Exclusive +where + T: Sync + Hash + ?Sized, +{ + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&self.inner, state) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl PartialOrd> for Exclusive +where + T: Sync + PartialOrd + ?Sized, + U: Sync + ?Sized, +{ + #[inline] + fn partial_cmp(&self, other: &Exclusive) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Ord for Exclusive +where + T: Sync + Ord + ?Sized, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} From b3c24356884d9cb333ff71e49e41b648a7dec1e2 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sun, 21 Sep 2025 21:13:03 +0200 Subject: [PATCH 123/537] Make mips64el-unknown-linux-muslabi64 link dynamically I missed this target when I changed all the other tier 3 targets. Only realized that this one was still statically linked when I looked at the list of targets in the test later. Signed-off-by: Jens Reidel --- .../src/spec/targets/mips64el_unknown_linux_muslabi64.rs | 2 -- tests/run-make/musl-default-linking/rmake.rs | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index d42e097b0fd8..38c3c7dfaa1b 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -5,8 +5,6 @@ pub(crate) fn target() -> Target { base.cpu = "mips64r2".into(); base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".into(), diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs index 1b30c538b5e3..e9d09e359c68 100644 --- a/tests/run-make/musl-default-linking/rmake.rs +++ b/tests/run-make/musl-default-linking/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json}; // Per https://github.com/rust-lang/compiler-team/issues/422, // we should be trying to move these targets to dynamically link // musl libc by default. -//@ needs-llvm-components: aarch64 arm mips powerpc x86 +//@ needs-llvm-components: aarch64 arm powerpc x86 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "aarch64-unknown-linux-musl", "arm-unknown-linux-musleabi", @@ -14,7 +14,6 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "armv7-unknown-linux-musleabihf", "i586-unknown-linux-musl", "i686-unknown-linux-musl", - "mips64el-unknown-linux-muslabi64", "powerpc64le-unknown-linux-musl", "x86_64-unknown-linux-musl", ]; From 3565b0699d6830dc31732afa96272bcbd1f83606 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 19 Sep 2025 20:39:47 +0200 Subject: [PATCH 124/537] emit attribute for readonly non-pure inline assembly --- compiler/rustc_codegen_llvm/src/asm.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 5 ++ tests/codegen-llvm/asm/readonly-not-pure.rs | 48 +++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tests/codegen-llvm/asm/readonly-not-pure.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b79176e90981..838eb0db0403 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx)); } else if options.contains(InlineAsmOptions::NOMEM) { attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx)); - } else { - // LLVM doesn't have an attribute to represent ReadOnly + SideEffect + } else if options.contains(InlineAsmOptions::READONLY) { + attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx)); } attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9a86e4373d8f..fd972f371df4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -710,6 +710,7 @@ pub(crate) enum MemoryEffects { None, ReadOnly, InaccessibleMemOnly, + ReadOnlyNotPure, } /// LLVMOpcode diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 64151962321f..414274f24fb5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects { None, ReadOnly, InaccessibleMemOnly, + ReadOnlyNotPure, }; extern "C" LLVMAttributeRef @@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, case LLVMRustMemoryEffects::InaccessibleMemOnly: return wrap(Attribute::getWithMemoryEffects( *unwrap(C), MemoryEffects::inaccessibleMemOnly())); + case LLVMRustMemoryEffects::ReadOnlyNotPure: + return wrap(Attribute::getWithMemoryEffects( + *unwrap(C), + MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly())); default: report_fatal_error("bad MemoryEffects."); } diff --git a/tests/codegen-llvm/asm/readonly-not-pure.rs b/tests/codegen-llvm/asm/readonly-not-pure.rs new file mode 100644 index 000000000000..a3c0e276c7f5 --- /dev/null +++ b/tests/codegen-llvm/asm/readonly-not-pure.rs @@ -0,0 +1,48 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 --target x86_64-unknown-linux-gnu +//@ needs-llvm-components: x86 + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_core] + +// Test that when an inline assembly block specifies `readonly` but not `pure`, a detailed +// `MemoryEffects` is provided to LLVM: this assembly block is not allowed to perform writes, +// but it may have side-effects. + +extern crate minicore; +use minicore::*; + +pub static mut VAR: i32 = 0; + +// CHECK-LABEL: @no_options +// CHECK: call i32 asm +#[no_mangle] +pub unsafe fn no_options() -> i32 { + VAR = 1; + let _ignored: i32; + asm!("mov {0}, 1", out(reg) _ignored); + VAR +} + +// CHECK-LABEL: @readonly_pure +// CHECK-NOT: call i32 asm +#[no_mangle] +pub unsafe fn readonly_pure() -> i32 { + VAR = 1; + let _ignored: i32; + asm!("mov {0}, 1", out(reg) _ignored, options(pure, readonly)); + VAR +} + +// CHECK-LABEL: @readonly_not_pure +// CHECK: call i32 asm {{.*}} #[[ATTR:[0-9]+]] +#[no_mangle] +pub unsafe fn readonly_not_pure() -> i32 { + VAR = 1; + let _ignored: i32; + asm!("mov {0}, 1", out(reg) _ignored, options(readonly)); + VAR +} + +// CHECK: attributes #[[ATTR]] = { nounwind memory(read, inaccessiblemem: readwrite) } From 0138bbd4958f2247770105ff63e9129e779da569 Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Sun, 21 Sep 2025 08:54:25 -0700 Subject: [PATCH 125/537] Add x86_64-unknown-motor (Motor OS) tier 3 target Add the initial no-std Motor OS compiler target. Motor OS has been developed for several years in the open: https://github.com/moturus/motor-os. It has a more or less full implementation of Rust std library, as well as tokio/mio ports. Build instructions can be found here: https://github.com/moturus/motor-os/blob/main/docs/build.md. Signed-off-by: U. Lasiotus --- compiler/rustc_target/src/spec/base/mod.rs | 1 + compiler/rustc_target/src/spec/base/motor.rs | 34 ++++++++++++++ compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/x86_64_unknown_motor.rs | 38 ++++++++++++++++ src/bootstrap/src/core/sanity.rs | 5 +++ src/doc/rustc/src/platform-support.md | 1 + src/doc/rustc/src/platform-support/motor.md | 45 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 3 ++ tests/ui/check-cfg/cfg-crate-features.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 4 +- 10 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_target/src/spec/base/motor.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs create mode 100644 src/doc/rustc/src/platform-support/motor.md diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index be15da7329d7..6ab8597a4ecb 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -21,6 +21,7 @@ pub(crate) mod linux_uclibc; pub(crate) mod linux_wasm; pub(crate) mod lynxos178; pub(crate) mod managarm_mlibc; +pub(crate) mod motor; pub(crate) mod msvc; pub(crate) mod netbsd; pub(crate) mod nto_qnx; diff --git a/compiler/rustc_target/src/spec/base/motor.rs b/compiler/rustc_target/src/spec/base/motor.rs new file mode 100644 index 000000000000..18485b2cef2f --- /dev/null +++ b/compiler/rustc_target/src/spec/base/motor.rs @@ -0,0 +1,34 @@ +use crate::spec::{ + Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions, +}; + +pub(crate) fn opts() -> TargetOptions { + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &[ + "-e", + "motor_start", + "--no-undefined", + "--error-unresolved-symbols", + "--no-undefined-version", + "-u", + "__rust_abort", + ], + ); + TargetOptions { + os: "motor".into(), + executables: true, + // TLS is false below because if true, the compiler assumes + // we handle TLS at the ELF loading level, which we don't. + // We use "OS level" TLS (see thread/local.rs in stdlib). + has_thread_local: false, + frame_pointer: FramePointer::NonLeaf, + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No), + main_needs_argc_argv: true, + panic_strategy: PanicStrategy::Abort, + pre_link_args, + stack_probes: StackProbeType::Inline, + supports_stack_protector: true, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f705af52bd86..c40358af5938 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1642,6 +1642,7 @@ supported_targets! { ("aarch64-unknown-hermit", aarch64_unknown_hermit), ("riscv64gc-unknown-hermit", riscv64gc_unknown_hermit), ("x86_64-unknown-hermit", x86_64_unknown_hermit), + ("x86_64-unknown-motor", x86_64_unknown_motor), ("x86_64-unikraft-linux-musl", x86_64_unikraft_linux_musl), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs new file mode 100644 index 000000000000..0fd43357a766 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs @@ -0,0 +1,38 @@ +use crate::spec::{ + CodeModel, LinkSelfContainedDefault, LldFlavor, RelocModel, RelroLevel, Target, base, +}; + +pub(crate) fn target() -> Target { + let mut base = base::motor::opts(); + base.cpu = "x86-64".into(); + base.max_atomic_width = Some(64); + base.code_model = Some(CodeModel::Small); + + // We want fully static relocatable binaries. It was surprisingly + // difficult to make it happen reliably, especially various + // linker-related options below. Mostly trial and error. + base.position_independent_executables = true; + base.relro_level = RelroLevel::Full; + base.static_position_independent_executables = true; + base.relocation_model = RelocModel::Pic; + base.lld_flavor_json = LldFlavor::Ld; + base.link_self_contained = LinkSelfContainedDefault::True; + base.dynamic_linking = false; + base.crt_static_default = true; + base.crt_static_respected = true; + + Target { + llvm_target: "x86_64-unknown-none-elf".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Motor OS".into()), + tier: Some(3), + host_tools: None, + std: None, + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 68202500d979..91d80c96e426 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -38,6 +38,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "aarch64_be-unknown-hermit", "aarch64_be-unknown-none-softfloat", + "x86_64-unknown-motor", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM @@ -239,6 +240,10 @@ than building it. continue; } + if target.contains("motor") { + continue; + } + // skip check for cross-targets if skip_target_sanity && target != &build.host_target { continue; diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e5e46f726375..99c8e365f5cf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -431,6 +431,7 @@ target | std | host | notes `x86_64-unknown-l4re-uclibc` | ? | | [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc [`x86_64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | x86_64 Managarm +[`x86_64-unknown-motor`[(platform-support/motor.md) | ? | | x86_64 Motor OS [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD [`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ | | `x86_64-uwp-windows-gnu` | ✓ | | diff --git a/src/doc/rustc/src/platform-support/motor.md b/src/doc/rustc/src/platform-support/motor.md new file mode 100644 index 000000000000..e7aa7b23f3a5 --- /dev/null +++ b/src/doc/rustc/src/platform-support/motor.md @@ -0,0 +1,45 @@ +# `x86_64-unknown-motor` + +**Tier: 3** + +[Motor OS](https://github.com/moturus/motor-os) is a new operating system +for virtualized environments. + +## Target maintainers + +[@lasiotus](https://github.com/lasiotus) + +## Requirements + +This target is cross-compiled. There are no special requirements for the host. + +Motor OS uses the ELF file format. + +## Building the target + +The target can be built by enabling it for a `rustc` build, for example: + +```toml +[build] +build-stage = 2 +target = ["x86_64-unknown-motor"] +``` + +## Building Rust programs + +Rust standard library is fully supported/implemented, but is not yet part of +the official Rust repo, so an out-of-tree building process should be +followed, as described in the +[build doc](https://github.com/moturus/motor-os/blob/main/docs/build.md). + +## Testing + +Cross-compiled Rust binaries and test artifacts can be executed in Motor OS VMs, +as described in e.g. +[Hello Motor OS](https://github.com/moturus/motor-os/blob/main/docs/recipes/hello-motor-os.md) +example. + +## Cross-compilation toolchains and C code + +C code can be compiled as part of Rust cargo projects. However, there is +no libc support. diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index b5c116cdfef0..ebea9fe40f51 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -658,6 +658,9 @@ //@ revisions: x86_64_unknown_managarm_mlibc //@ [x86_64_unknown_managarm_mlibc] compile-flags: --target x86_64-unknown-managarm-mlibc //@ [x86_64_unknown_managarm_mlibc] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_motor +//@ [x86_64_unknown_motor] compile-flags: --target x86_64-unknown-motor +//@ [x86_64_unknown_motor] needs-llvm-components: x86 //@ revisions: x86_64_unknown_netbsd //@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd //@ [x86_64_unknown_netbsd] needs-llvm-components: x86 diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr index 6b2e628e12ea..39fee52a909b 100644 --- a/tests/ui/check-cfg/cfg-crate-features.stderr +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist` LL | #![cfg(not(target(os = "does_not_exist")))] | ^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, and `tvos` and 11 more + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, and `trusty` and 12 more = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 6490fc63fd76..df2357696a37 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -274,7 +274,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 28 warnings emitted From c54a953402aaa132c363b578f59cd30e39cb0abb Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sun, 21 Sep 2025 11:18:30 +0300 Subject: [PATCH 126/537] Early return in `visibility_print_with_space` --- src/librustdoc/html/format.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8c75f301841f..950d3a08827d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1422,10 +1422,13 @@ pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) f.write_str("#[doc(hidden)] ")?; } - match item.visibility(cx.tcx()) { - None => {} - Some(ty::Visibility::Public) => f.write_str("pub ")?, - Some(ty::Visibility::Restricted(vis_did)) => { + let Some(vis) = item.visibility(cx.tcx()) else { + return Ok(()); + }; + + match vis { + ty::Visibility::Public => f.write_str("pub ")?, + ty::Visibility::Restricted(vis_did) => { // FIXME(camelid): This may not work correctly if `item_did` is a module. // However, rustdoc currently never displays a module's // visibility, so it shouldn't matter. From cdf96614cf19643a0337e8b012d3e72f1bfa3cd2 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sun, 21 Sep 2025 10:55:50 +0300 Subject: [PATCH 127/537] Re-use some existing util fns --- src/librustdoc/html/format.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 950d3a08827d..fa55de4239a2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -965,10 +965,7 @@ fn fmt_type( write!(f, "]") } clean::RawPointer(m, t) => { - let m = match m { - hir::Mutability::Mut => "mut", - hir::Mutability::Not => "const", - }; + let m = m.ptr_str(); if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { let ty = t.print(cx); @@ -1406,12 +1403,13 @@ impl clean::FnDecl { } fn print_output(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| match &self.output { - clean::Tuple(tys) if tys.is_empty() => Ok(()), - ty if f.alternate() => { - write!(f, " -> {:#}", ty.print(cx)) + fmt::from_fn(move |f| { + if self.output.is_unit() { + return Ok(()); } - ty => write!(f, " -> {}", ty.print(cx)), + + f.write_str(if f.alternate() { " -> " } else { " -> " })?; + self.output.print(cx).fmt(f) }) } } From f1d6e000b500bd23a9f75716a161bc015ab49273 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 21 Sep 2025 17:26:39 -0400 Subject: [PATCH 128/537] Bless UI tests --- tests/ui/explicit-tail-calls/callee_is_weird.stderr | 2 +- tests/ui/impl-trait/where-allowed.stderr | 2 ++ tests/ui/traits/next-solver/well-formed-in-relate.stderr | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.stderr b/tests/ui/explicit-tail-calls/callee_is_weird.stderr index a4e5a38ce332..9a5da28b559e 100644 --- a/tests/ui/explicit-tail-calls/callee_is_weird.stderr +++ b/tests/ui/explicit-tail-calls/callee_is_weird.stderr @@ -12,7 +12,7 @@ error: tail calls can only be performed with function definitions or pointers LL | become (&mut &std::sync::Exclusive::new(f))() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: callee has type `Exclusive` + = note: callee has type `&Exclusive` error: tail calls can only be performed with function definitions or pointers --> $DIR/callee_is_weird.rs:22:12 diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 08caff326c47..4d8f23bf7ca6 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -387,6 +387,8 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where A: Tuple, F: Fn
, F: ?Sized; - impl Fn for Box where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + - impl Fn for Exclusive + where F: Sync, F: Fn, Args: Tuple; error[E0118]: no nominal type found for inherent implementation --> $DIR/where-allowed.rs:240:1 diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index 5294a072d312..d79e465b3e38 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -12,6 +12,8 @@ LL | x = unconstrained_map(); where A: Tuple, F: Fn, F: ?Sized; - impl Fn for Box where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + - impl Fn for Exclusive + where F: Sync, F: Fn, Args: Tuple; note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 | From 20671600a2873139a61c39128a359225c8580d3c Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sun, 21 Sep 2025 11:13:37 +0300 Subject: [PATCH 129/537] Introduce "wrapper" helpers to rustdoc --- src/librustdoc/clean/cfg.rs | 80 ++++----- src/librustdoc/display.rs | 86 ++++++++- src/librustdoc/html/format.rs | 323 ++++++++++++++-------------------- src/librustdoc/lib.rs | 1 + 4 files changed, 250 insertions(+), 240 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index e204e1788baa..8feca1367fc9 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -3,16 +3,16 @@ // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619), // switch to use those structures instead. -use std::fmt::{self, Write}; -use std::{mem, ops}; +use std::{fmt, mem, ops}; +use itertools::Either; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::FxHashSet; use rustc_session::parse::ParseSess; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; -use crate::display::Joined as _; +use crate::display::{Joined as _, MaybeDisplay, Wrapped}; use crate::html::escape::Escape; #[cfg(test)] @@ -376,27 +376,20 @@ impl Format { Format::LongPlain => false, } } + + fn escape(self, s: &str) -> impl fmt::Display { + if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) } + } } /// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used. struct Display<'a>(&'a Cfg, Format); -fn write_with_opt_paren( - fmt: &mut fmt::Formatter<'_>, - has_paren: bool, - obj: T, -) -> fmt::Result { - if has_paren { - fmt.write_char('(')?; - } - obj.fmt(fmt)?; - if has_paren { - fmt.write_char(')')?; - } - Ok(()) -} - impl Display<'_> { + fn code_wrappers(&self) -> Wrapped<&'static str> { + if self.1.is_html() { Wrapped::with("", "") } else { Wrapped::with("`", "`") } + } + fn display_sub_cfgs( &self, fmt: &mut fmt::Formatter<'_>, @@ -427,20 +420,17 @@ impl Display<'_> { sub_cfgs .iter() .map(|sub_cfg| { - fmt::from_fn(move |fmt| { - if let Cfg::Cfg(_, Some(feat)) = sub_cfg - && short_longhand - { - if self.1.is_html() { - write!(fmt, "{feat}")?; - } else { - write!(fmt, "`{feat}`")?; - } - } else { - write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; - } - Ok(()) - }) + if let Cfg::Cfg(_, Some(feat)) = sub_cfg + && short_longhand + { + Either::Left(self.code_wrappers().wrap(feat)) + } else { + Either::Right( + Wrapped::with_parens() + .when(!sub_cfg.is_all()) + .wrap(Display(sub_cfg, self.1)), + ) + } }) .joined(separator, f) }) @@ -461,9 +451,9 @@ impl fmt::Display for Display<'_> { sub_cfgs .iter() .map(|sub_cfg| { - fmt::from_fn(|fmt| { - write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1)) - }) + Wrapped::with_parens() + .when(!sub_cfg.is_all()) + .wrap(Display(sub_cfg, self.1)) }) .joined(separator, fmt) } @@ -568,21 +558,13 @@ impl fmt::Display for Display<'_> { }; if !human_readable.is_empty() { fmt.write_str(human_readable) - } else if let Some(v) = value { - if self.1.is_html() { - write!( - fmt, - r#"{}="{}""#, - Escape(name.as_str()), - Escape(v.as_str()) - ) - } else { - write!(fmt, r#"`{name}="{v}"`"#) - } - } else if self.1.is_html() { - write!(fmt, "{}", Escape(name.as_str())) } else { - write!(fmt, "`{name}`") + let value = value + .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str())))) + .maybe_display(); + self.code_wrappers() + .wrap(format_args!("{}{value}", self.1.escape(name.as_str()))) + .fmt(fmt) } } } diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs index db868c5c9a8f..d62ea4c36880 100644 --- a/src/librustdoc/display.rs +++ b/src/librustdoc/display.rs @@ -1,6 +1,6 @@ //! Various utilities for working with [`fmt::Display`] implementations. -use std::fmt::{self, Display, Formatter}; +use std::fmt::{self, Display, Formatter, FormattingOptions}; pub(crate) trait Joined: IntoIterator { /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`. @@ -45,3 +45,87 @@ impl MaybeDisplay for Option { }) } } + +#[derive(Clone, Copy)] +pub(crate) struct Wrapped { + prefix: T, + suffix: T, +} + +pub(crate) enum AngleBracket { + Open, + Close, +} + +impl Display for AngleBracket { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match (self, f.alternate()) { + (Self::Open, true) => "<", + (Self::Open, false) => "<", + (Self::Close, true) => ">", + (Self::Close, false) => ">", + }) + } +} + +impl Wrapped { + pub(crate) fn with_angle_brackets() -> Self { + Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close } + } +} + +impl Wrapped { + pub(crate) fn with_parens() -> Self { + Self { prefix: '(', suffix: ')' } + } + + pub(crate) fn with_square_brackets() -> Self { + Self { prefix: '[', suffix: ']' } + } +} + +impl Wrapped { + pub(crate) fn with(prefix: T, suffix: T) -> Self { + Self { prefix, suffix } + } + + pub(crate) fn when(self, if_: bool) -> Wrapped { + Wrapped { + prefix: if_.then_some(self.prefix).maybe_display(), + suffix: if_.then_some(self.suffix).maybe_display(), + } + } + + pub(crate) fn wrap_fn( + self, + content: impl Fn(&mut Formatter<'_>) -> fmt::Result, + ) -> impl Display { + fmt::from_fn(move |f| { + self.prefix.fmt(f)?; + content(f)?; + self.suffix.fmt(f) + }) + } + + pub(crate) fn wrap(self, content: C) -> impl Display { + self.wrap_fn(move |f| content.fmt(f)) + } +} + +#[derive(Clone, Copy)] +pub(crate) struct WithOpts { + opts: FormattingOptions, +} + +impl WithOpts { + pub(crate) fn from(f: &Formatter<'_>) -> Self { + Self { opts: f.options() } + } + + pub(crate) fn display(self, t: impl Display) -> impl Display { + fmt::from_fn(move |f| { + let mut f = f.with_options(self.opts); + t.fmt(&mut f) + }) + } +} diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fa55de4239a2..ecaff4cdf43a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -30,7 +30,7 @@ use super::url_parts_builder::UrlPartsBuilder; use crate::clean::types::ExternalLocation; use crate::clean::utils::find_nearest_parent_module; use crate::clean::{self, ExternalCrate, PrimitiveType}; -use crate::display::{Joined as _, MaybeDisplay as _}; +use crate::display::{Joined as _, MaybeDisplay as _, WithOpts, Wrapped}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyText}; @@ -105,20 +105,16 @@ impl clean::GenericParamDef { impl clean::Generics { pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| { - let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); - if real_params.peek().is_none() { - return Ok(()); - } - - let real_params = - fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)); - if f.alternate() { - write!(f, "<{real_params:#}>") - } else { - write!(f, "<{real_params}>") - } - }) + let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); + if real_params.peek().is_none() { + None + } else { + Some( + Wrapped::with_angle_brackets() + .wrap_fn(move |f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)), + ) + } + .maybe_display() } } @@ -151,11 +147,8 @@ fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) -> Ok(()) } clean::WherePredicate::EqPredicate { lhs, rhs } => { - if f.alternate() { - write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) - } else { - write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) - } + let opts = WithOpts::from(f); + write!(f, "{} == {}", opts.display(lhs.print(cx)), opts.display(rhs.print(cx))) } } }) @@ -279,13 +272,10 @@ impl clean::GenericBound { ty.print(cx).fmt(f) } clean::GenericBound::Use(args) => { - if f.alternate() { - f.write_str("use<")?; - } else { - f.write_str("use<")?; - } - args.iter().map(|arg| arg.name()).joined(", ", f)?; - if f.alternate() { f.write_str(">") } else { f.write_str(">") } + f.write_str("use")?; + Wrapped::with_angle_brackets() + .wrap_fn(|f| args.iter().map(|arg| arg.name()).joined(", ", f)) + .fmt(f) } }) } @@ -297,40 +287,29 @@ impl clean::GenericArgs { match self { clean::GenericArgs::AngleBracketed { args, constraints } => { if !args.is_empty() || !constraints.is_empty() { - if f.alternate() { - f.write_str("<")?; - } else { - f.write_str("<")?; - } - - [Either::Left(args), Either::Right(constraints)] - .into_iter() - .flat_map(Either::factor_into_iter) - .map(|either| { - either.map_either( - |arg| arg.print(cx), - |constraint| constraint.print(cx), - ) + Wrapped::with_angle_brackets() + .wrap_fn(|f| { + [Either::Left(args), Either::Right(constraints)] + .into_iter() + .flat_map(Either::factor_into_iter) + .map(|either| { + either.map_either( + |arg| arg.print(cx), + |constraint| constraint.print(cx), + ) + }) + .joined(", ", f) }) - .joined(", ", f)?; - - if f.alternate() { - f.write_str(">")?; - } else { - f.write_str(">")?; - } + .fmt(f)?; } } clean::GenericArgs::Parenthesized { inputs, output } => { - f.write_str("(")?; - inputs.iter().map(|ty| ty.print(cx)).joined(", ", f)?; - f.write_str(")")?; + Wrapped::with_parens() + .wrap_fn(|f| inputs.iter().map(|ty| ty.print(cx)).joined(", ", f)) + .fmt(f)?; if let Some(ref ty) = *output { - if f.alternate() { - write!(f, " -> {:#}", ty.print(cx))?; - } else { - write!(f, " -> {}", ty.print(cx))?; - } + f.write_str(if f.alternate() { " -> " } else { " -> " })?; + ty.print(cx).fmt(f)?; } } clean::GenericArgs::ReturnTypeNotation => { @@ -834,9 +813,10 @@ fn print_higher_ranked_params_with_space( fmt::from_fn(move |f| { if !params.is_empty() { f.write_str(keyword)?; - f.write_str(if f.alternate() { "<" } else { "<" })?; - params.iter().map(|lt| lt.print(cx)).joined(", ", f)?; - f.write_str(if f.alternate() { "> " } else { "> " })?; + Wrapped::with_angle_brackets() + .wrap_fn(|f| params.iter().map(|lt| lt.print(cx)).joined(", ", f)) + .fmt(f)?; + f.write_char(' ')?; } Ok(()) }) @@ -923,26 +903,23 @@ fn fmt_type( f, PrimitiveType::Tuple, format_args!( - "({})", - fmt::from_fn(|f| generic_names.iter().joined(", ", f)) + "{}", + Wrapped::with_parens() + .wrap_fn(|f| generic_names.iter().joined(", ", f)) ), cx, ) } else { - f.write_str("(")?; - many.iter().map(|item| item.print(cx)).joined(", ", f)?; - f.write_str(")") + Wrapped::with_parens() + .wrap_fn(|f| many.iter().map(|item| item.print(cx)).joined(", ", f)) + .fmt(f) } } }, clean::Slice(box clean::Generic(name)) => { primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx) } - clean::Slice(t) => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - write!(f, "]") - } + clean::Slice(t) => Wrapped::with_square_brackets().wrap(t.print(cx)).fmt(f), clean::Type::Pat(t, pat) => { fmt::Display::fmt(&t.print(cx), f)?; write!(f, " is {pat}") @@ -953,37 +930,27 @@ fn fmt_type( format_args!("[{name}; {n}]", n = Escape(n)), cx, ), - clean::Array(t, n) => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - if f.alternate() { - write!(f, "; {n}")?; - } else { - write!(f, "; ")?; - primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?; - } - write!(f, "]") - } + clean::Array(t, n) => Wrapped::with_square_brackets() + .wrap(fmt::from_fn(|f| { + t.print(cx).fmt(f)?; + f.write_str("; ")?; + if f.alternate() { + f.write_str(n) + } else { + primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx) + } + })) + .fmt(f), clean::RawPointer(m, t) => { let m = m.ptr_str(); if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { - let ty = t.print(cx); - if f.alternate() { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - format_args!("*{m} {ty:#}"), - cx, - ) - } else { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - format_args!("*{m} {ty}"), - cx, - ) - } + primitive_link( + f, + clean::PrimitiveType::RawPointer, + format_args!("*{m} {ty}", ty = WithOpts::from(f).display(t.print(cx))), + cx, + ) } else { primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?; t.print(cx).fmt(f) @@ -1017,14 +984,10 @@ fn fmt_type( clean::ImplTrait(ref bounds) if bounds.len() > 1 => true, _ => false, }; - if needs_parens { - f.write_str("(")?; - } - fmt_type(ty, f, use_absolute, cx)?; - if needs_parens { - f.write_str(")")?; - } - Ok(()) + Wrapped::with_parens() + .when(needs_parens) + .wrap_fn(|f| fmt_type(ty, f, use_absolute, cx)) + .fmt(f) } clean::ImplTrait(bounds) => { f.write_str("impl ")?; @@ -1054,23 +1017,21 @@ impl clean::QPathData { // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719), // we need to surround them with angle brackets in some cases (e.g. `::P`). - if f.alternate() { - if let Some(trait_) = trait_ - && should_fully_qualify - { - write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? - } else { - write!(f, "{:#}::", self_type.print(cx))? - } + if let Some(trait_) = trait_ + && should_fully_qualify + { + let opts = WithOpts::from(f); + Wrapped::with_angle_brackets() + .wrap(format_args!( + "{} as {}", + opts.display(self_type.print(cx)), + opts.display(trait_.print(cx)) + )) + .fmt(f)? } else { - if let Some(trait_) = trait_ - && should_fully_qualify - { - write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? - } else { - write!(f, "{}::", self_type.print(cx))? - } - }; + self_type.print(cx).fmt(f)?; + } + f.write_str("::")?; // It's pretty unsightly to look at `::C` in output, and // we've got hyperlinking on our side, so try to avoid longer // notation as much as possible by making `C` a hyperlink to trait @@ -1129,7 +1090,7 @@ impl clean::Impl { if let Some(ref ty) = self.trait_ { if self.is_negative_trait_impl() { - write!(f, "!")?; + f.write_char('!')?; } if self.kind.is_fake_variadic() && let Some(generics) = ty.generics() @@ -1137,18 +1098,17 @@ impl clean::Impl { { let last = ty.last(); if f.alternate() { - write!(f, "{last}<")?; - self.print_type(inner_type, f, use_absolute, cx)?; - write!(f, ">")?; + write!(f, "{last}")?; } else { - write!(f, "{}<", print_anchor(ty.def_id(), last, cx))?; - self.print_type(inner_type, f, use_absolute, cx)?; - write!(f, ">")?; - } + write!(f, "{}", print_anchor(ty.def_id(), last, cx))?; + }; + Wrapped::with_angle_brackets() + .wrap_fn(|f| self.print_type(inner_type, f, use_absolute, cx)) + .fmt(f)?; } else { ty.print(cx).fmt(f)?; } - write!(f, " for ")?; + f.write_str(" for ")?; } if let Some(ty) = self.kind.as_blanket_ty() { @@ -1215,18 +1175,10 @@ impl clean::Impl { && let Ok(ty) = generics.exactly_one() && self.kind.is_fake_variadic() { - let wrapper = print_anchor(path.def_id(), path.last(), cx); - if f.alternate() { - write!(f, "{wrapper:#}<")?; - } else { - write!(f, "{wrapper}<")?; - } - self.print_type(ty, f, use_absolute, cx)?; - if f.alternate() { - write!(f, ">")?; - } else { - write!(f, ">")?; - } + print_anchor(path.def_id(), path.last(), cx).fmt(f)?; + Wrapped::with_angle_brackets() + .wrap_fn(|f| self.print_type(ty, f, use_absolute, cx)) + .fmt(f)?; } else { fmt_type(type_, f, use_absolute, cx)?; } @@ -1308,23 +1260,13 @@ impl clean::FnDecl { pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; - if f.alternate() { - write!( - f, - "({params:#}{ellipsis}){arrow:#}", - params = print_params(&self.inputs, cx), - ellipsis = ellipsis, - arrow = self.print_output(cx) - ) - } else { - write!( - f, - "({params}{ellipsis}){arrow}", - params = print_params(&self.inputs, cx), - ellipsis = ellipsis, - arrow = self.print_output(cx) - ) - } + Wrapped::with_parens() + .wrap_fn(|f| { + print_params(&self.inputs, cx).fmt(f)?; + f.write_str(ellipsis) + }) + .fmt(f)?; + self.print_output(cx).fmt(f) }) } @@ -1343,8 +1285,7 @@ impl clean::FnDecl { fmt::from_fn(move |f| { // First, generate the text form of the declaration, with no line wrapping, and count the bytes. let mut counter = WriteCounter(0); - write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) })) - .unwrap(); + write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))?; // If the text form was over 80 characters wide, we will line-wrap our output. let line_wrapping_indent = if header_len + counter.0 > 80 { Some(indent) } else { None }; @@ -1362,42 +1303,44 @@ impl clean::FnDecl { f: &mut fmt::Formatter<'_>, cx: &Context<'_>, ) -> fmt::Result { - f.write_char('(')?; + Wrapped::with_parens() + .wrap_fn(|f| { + if !self.inputs.is_empty() { + let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4)); - if !self.inputs.is_empty() { - let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4)); + if let Some(indent) = line_wrapping_indent { + write!(f, "\n{indent}")?; + } - if let Some(indent) = line_wrapping_indent { - write!(f, "\n{indent}")?; - } + let sep = fmt::from_fn(|f| { + if let Some(indent) = line_wrapping_indent { + write!(f, ",\n{indent}") + } else { + f.write_str(", ") + } + }); - let sep = fmt::from_fn(|f| { - if let Some(indent) = line_wrapping_indent { - write!(f, ",\n{indent}") - } else { - f.write_str(", ") + self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?; + + if line_wrapping_indent.is_some() { + writeln!(f, ",")? + } + + if self.c_variadic { + match line_wrapping_indent { + None => write!(f, ", ...")?, + Some(indent) => writeln!(f, "{indent}...")?, + }; + } } - }); - self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?; + if let Some(n) = line_wrapping_indent { + write!(f, "{}", Indent(n))? + } - if line_wrapping_indent.is_some() { - writeln!(f, ",")? - } - - if self.c_variadic { - match line_wrapping_indent { - None => write!(f, ", ...")?, - Some(indent) => writeln!(f, "{indent}...")?, - }; - } - } - - if let Some(n) = line_wrapping_indent { - write!(f, "{}", Indent(n))? - } - - f.write_char(')')?; + Ok(()) + }) + .fmt(f)?; self.print_output(cx).fmt(f) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9871066b9eb5..0ff1c0906893 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -10,6 +10,7 @@ #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(file_buffered)] +#![feature(formatting_options)] #![feature(if_let_guard)] #![feature(iter_advance_by)] #![feature(iter_intersperse)] From 055e05a338af00751ffccc992feeda227b8436b1 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 17 Sep 2025 14:07:23 -0400 Subject: [PATCH 130/537] Mark float intrinsics with no preconditions as safe --- .../rustc_hir_analysis/src/check/intrinsic.rs | 64 ++++++++ .../libm/src/math/support/float_traits.rs | 2 +- library/core/src/intrinsics/mod.rs | 138 +++++++++--------- library/core/src/num/f128.rs | 21 +-- library/core/src/num/f16.rs | 21 +-- library/core/src/num/f32.rs | 21 +-- library/core/src/num/f64.rs | 21 +-- library/std/src/num/f128.rs | 16 +- library/std/src/num/f16.rs | 16 +- library/std/src/num/f32.rs | 16 +- library/std/src/num/f64.rs | 16 +- .../core_arch/src/aarch64/neon/generated.rs | 12 +- .../crates/core_arch/src/wasm32/mod.rs | 16 +- .../spec/neon/aarch64.spec.yml | 12 +- src/tools/miri/tests/pass/float.rs | 4 +- .../intrinsics/fmuladd_nondeterministic.rs | 4 +- .../codegen-llvm/intrinsic-no-unnamed-attr.rs | 4 +- tests/ui/intrinsics/intrinsic-fmuladd.rs | 4 +- tests/ui/intrinsics/reify-intrinsic.stderr | 2 +- 19 files changed, 222 insertions(+), 188 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 5fd04427496d..6faa67f6a904 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -81,22 +81,62 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::bswap | sym::caller_location | sym::carrying_mul_add + | sym::ceilf16 + | sym::ceilf32 + | sym::ceilf64 + | sym::ceilf128 | sym::cold_path | sym::const_eval_select | sym::contract_check_ensures | sym::contract_check_requires | sym::contract_checks + | sym::cosf16 + | sym::cosf32 + | sym::cosf64 + | sym::cosf128 | sym::ctlz | sym::ctpop | sym::cttz | sym::discriminant_value + | sym::exp2f16 + | sym::exp2f32 + | sym::exp2f64 + | sym::exp2f128 + | sym::expf16 + | sym::expf32 + | sym::expf64 + | sym::expf128 | sym::fadd_algebraic | sym::fdiv_algebraic + | sym::floorf16 + | sym::floorf32 + | sym::floorf64 + | sym::floorf128 + | sym::fmaf16 + | sym::fmaf32 + | sym::fmaf64 + | sym::fmaf128 | sym::fmul_algebraic + | sym::fmuladdf16 + | sym::fmuladdf32 + | sym::fmuladdf64 + | sym::fmuladdf128 | sym::forget | sym::frem_algebraic | sym::fsub_algebraic | sym::is_val_statically_known + | sym::log2f16 + | sym::log2f32 + | sym::log2f64 + | sym::log2f128 + | sym::log10f16 + | sym::log10f32 + | sym::log10f64 + | sym::log10f128 + | sym::logf16 + | sym::logf32 + | sym::logf64 + | sym::logf128 | sym::maximumf16 | sym::maximumf32 | sym::maximumf64 @@ -115,6 +155,14 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::minnumf128 | sym::mul_with_overflow | sym::needs_drop + | sym::powf16 + | sym::powf32 + | sym::powf64 + | sym::powf128 + | sym::powif16 + | sym::powif32 + | sym::powif64 + | sym::powif128 | sym::prefetch_read_data | sym::prefetch_read_instruction | sym::prefetch_write_data @@ -128,13 +176,29 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::round_ties_even_f32 | sym::round_ties_even_f64 | sym::round_ties_even_f128 + | sym::roundf16 + | sym::roundf32 + | sym::roundf64 + | sym::roundf128 | sym::rustc_peek | sym::saturating_add | sym::saturating_sub | sym::select_unpredictable + | sym::sinf16 + | sym::sinf32 + | sym::sinf64 + | sym::sinf128 | sym::size_of + | sym::sqrtf16 + | sym::sqrtf32 + | sym::sqrtf64 + | sym::sqrtf128 | sym::sub_with_overflow | sym::three_way_compare + | sym::truncf16 + | sym::truncf32 + | sym::truncf64 + | sym::truncf128 | sym::type_id | sym::type_id_eq | sym::type_name diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index fb790e696159..b5ee6413d553 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -289,7 +289,7 @@ macro_rules! float_impl { cfg_if! { // fma is not yet available in `core` if #[cfg(intrinsics_enabled)] { - unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) } + core::intrinsics::$fma_intrinsic(self, y, z) } else { super::super::$fma_fn(self, y, z) } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index bffffbc29c1e..a174ced5a2a6 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1022,28 +1022,28 @@ pub unsafe fn unaligned_volatile_store(dst: *mut T, val: T); /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sqrtf16(x: f16) -> f16; +pub fn sqrtf16(x: f16) -> f16; /// Returns the square root of an `f32` /// /// The stabilized version of this intrinsic is /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sqrtf32(x: f32) -> f32; +pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` /// /// The stabilized version of this intrinsic is /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sqrtf64(x: f64) -> f64; +pub fn sqrtf64(x: f64) -> f64; /// Returns the square root of an `f128` /// /// The stabilized version of this intrinsic is /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sqrtf128(x: f128) -> f128; +pub fn sqrtf128(x: f128) -> f128; /// Raises an `f16` to an integer power. /// @@ -1051,28 +1051,28 @@ pub unsafe fn sqrtf128(x: f128) -> f128; /// [`f16::powi`](../../std/primitive.f16.html#method.powi) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powif16(a: f16, x: i32) -> f16; +pub fn powif16(a: f16, x: i32) -> f16; /// Raises an `f32` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f32::powi`](../../std/primitive.f32.html#method.powi) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powif32(a: f32, x: i32) -> f32; +pub fn powif32(a: f32, x: i32) -> f32; /// Raises an `f64` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f64::powi`](../../std/primitive.f64.html#method.powi) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powif64(a: f64, x: i32) -> f64; +pub fn powif64(a: f64, x: i32) -> f64; /// Raises an `f128` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f128::powi`](../../std/primitive.f128.html#method.powi) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powif128(a: f128, x: i32) -> f128; +pub fn powif128(a: f128, x: i32) -> f128; /// Returns the sine of an `f16`. /// @@ -1080,28 +1080,28 @@ pub unsafe fn powif128(a: f128, x: i32) -> f128; /// [`f16::sin`](../../std/primitive.f16.html#method.sin) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sinf16(x: f16) -> f16; +pub fn sinf16(x: f16) -> f16; /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::sin`](../../std/primitive.f32.html#method.sin) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sinf32(x: f32) -> f32; +pub fn sinf32(x: f32) -> f32; /// Returns the sine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::sin`](../../std/primitive.f64.html#method.sin) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sinf64(x: f64) -> f64; +pub fn sinf64(x: f64) -> f64; /// Returns the sine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::sin`](../../std/primitive.f128.html#method.sin) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn sinf128(x: f128) -> f128; +pub fn sinf128(x: f128) -> f128; /// Returns the cosine of an `f16`. /// @@ -1109,28 +1109,28 @@ pub unsafe fn sinf128(x: f128) -> f128; /// [`f16::cos`](../../std/primitive.f16.html#method.cos) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn cosf16(x: f16) -> f16; +pub fn cosf16(x: f16) -> f16; /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::cos`](../../std/primitive.f32.html#method.cos) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn cosf32(x: f32) -> f32; +pub fn cosf32(x: f32) -> f32; /// Returns the cosine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::cos`](../../std/primitive.f64.html#method.cos) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn cosf64(x: f64) -> f64; +pub fn cosf64(x: f64) -> f64; /// Returns the cosine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::cos`](../../std/primitive.f128.html#method.cos) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn cosf128(x: f128) -> f128; +pub fn cosf128(x: f128) -> f128; /// Raises an `f16` to an `f16` power. /// @@ -1138,28 +1138,28 @@ pub unsafe fn cosf128(x: f128) -> f128; /// [`f16::powf`](../../std/primitive.f16.html#method.powf) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powf16(a: f16, x: f16) -> f16; +pub fn powf16(a: f16, x: f16) -> f16; /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is /// [`f32::powf`](../../std/primitive.f32.html#method.powf) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powf32(a: f32, x: f32) -> f32; +pub fn powf32(a: f32, x: f32) -> f32; /// Raises an `f64` to an `f64` power. /// /// The stabilized version of this intrinsic is /// [`f64::powf`](../../std/primitive.f64.html#method.powf) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powf64(a: f64, x: f64) -> f64; +pub fn powf64(a: f64, x: f64) -> f64; /// Raises an `f128` to an `f128` power. /// /// The stabilized version of this intrinsic is /// [`f128::powf`](../../std/primitive.f128.html#method.powf) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn powf128(a: f128, x: f128) -> f128; +pub fn powf128(a: f128, x: f128) -> f128; /// Returns the exponential of an `f16`. /// @@ -1167,28 +1167,28 @@ pub unsafe fn powf128(a: f128, x: f128) -> f128; /// [`f16::exp`](../../std/primitive.f16.html#method.exp) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn expf16(x: f16) -> f16; +pub fn expf16(x: f16) -> f16; /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp`](../../std/primitive.f32.html#method.exp) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn expf32(x: f32) -> f32; +pub fn expf32(x: f32) -> f32; /// Returns the exponential of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp`](../../std/primitive.f64.html#method.exp) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn expf64(x: f64) -> f64; +pub fn expf64(x: f64) -> f64; /// Returns the exponential of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp`](../../std/primitive.f128.html#method.exp) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn expf128(x: f128) -> f128; +pub fn expf128(x: f128) -> f128; /// Returns 2 raised to the power of an `f16`. /// @@ -1196,28 +1196,28 @@ pub unsafe fn expf128(x: f128) -> f128; /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn exp2f16(x: f16) -> f16; +pub fn exp2f16(x: f16) -> f16; /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn exp2f32(x: f32) -> f32; +pub fn exp2f32(x: f32) -> f32; /// Returns 2 raised to the power of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn exp2f64(x: f64) -> f64; +pub fn exp2f64(x: f64) -> f64; /// Returns 2 raised to the power of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn exp2f128(x: f128) -> f128; +pub fn exp2f128(x: f128) -> f128; /// Returns the natural logarithm of an `f16`. /// @@ -1225,28 +1225,28 @@ pub unsafe fn exp2f128(x: f128) -> f128; /// [`f16::ln`](../../std/primitive.f16.html#method.ln) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn logf16(x: f16) -> f16; +pub fn logf16(x: f16) -> f16; /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ln`](../../std/primitive.f32.html#method.ln) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn logf32(x: f32) -> f32; +pub fn logf32(x: f32) -> f32; /// Returns the natural logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ln`](../../std/primitive.f64.html#method.ln) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn logf64(x: f64) -> f64; +pub fn logf64(x: f64) -> f64; /// Returns the natural logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::ln`](../../std/primitive.f128.html#method.ln) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn logf128(x: f128) -> f128; +pub fn logf128(x: f128) -> f128; /// Returns the base 10 logarithm of an `f16`. /// @@ -1254,28 +1254,28 @@ pub unsafe fn logf128(x: f128) -> f128; /// [`f16::log10`](../../std/primitive.f16.html#method.log10) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log10f16(x: f16) -> f16; +pub fn log10f16(x: f16) -> f16; /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log10`](../../std/primitive.f32.html#method.log10) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log10f32(x: f32) -> f32; +pub fn log10f32(x: f32) -> f32; /// Returns the base 10 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log10`](../../std/primitive.f64.html#method.log10) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log10f64(x: f64) -> f64; +pub fn log10f64(x: f64) -> f64; /// Returns the base 10 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log10`](../../std/primitive.f128.html#method.log10) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log10f128(x: f128) -> f128; +pub fn log10f128(x: f128) -> f128; /// Returns the base 2 logarithm of an `f16`. /// @@ -1283,28 +1283,28 @@ pub unsafe fn log10f128(x: f128) -> f128; /// [`f16::log2`](../../std/primitive.f16.html#method.log2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log2f16(x: f16) -> f16; +pub fn log2f16(x: f16) -> f16; /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log2`](../../std/primitive.f32.html#method.log2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log2f32(x: f32) -> f32; +pub fn log2f32(x: f32) -> f32; /// Returns the base 2 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log2`](../../std/primitive.f64.html#method.log2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log2f64(x: f64) -> f64; +pub fn log2f64(x: f64) -> f64; /// Returns the base 2 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log2`](../../std/primitive.f128.html#method.log2) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn log2f128(x: f128) -> f128; +pub fn log2f128(x: f128) -> f128; /// Returns `a * b + c` for `f16` values. /// @@ -1312,28 +1312,28 @@ pub unsafe fn log2f128(x: f128) -> f128; /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmaf16(a: f16, b: f16, c: f16) -> f16; +pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmaf32(a: f32, b: f32, c: f32) -> f32; +pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmaf64(a: f64, b: f64, c: f64) -> f64; +pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values. /// /// The stabilized version of this intrinsic is /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmaf128(a: f128, b: f128, c: f128) -> f128; +pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// Returns `a * b + c` for `f16` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the @@ -1347,7 +1347,7 @@ pub unsafe fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; +pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1360,7 +1360,7 @@ pub unsafe fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; +pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1373,7 +1373,7 @@ pub unsafe fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; +pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1386,7 +1386,7 @@ pub unsafe fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; +pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// Returns the largest integer less than or equal to an `f16`. /// @@ -1395,7 +1395,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn floorf16(x: f16) -> f16; +pub const fn floorf16(x: f16) -> f16; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is @@ -1403,7 +1403,7 @@ pub const unsafe fn floorf16(x: f16) -> f16; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn floorf32(x: f32) -> f32; +pub const fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. /// /// The stabilized version of this intrinsic is @@ -1411,7 +1411,7 @@ pub const unsafe fn floorf32(x: f32) -> f32; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn floorf64(x: f64) -> f64; +pub const fn floorf64(x: f64) -> f64; /// Returns the largest integer less than or equal to an `f128`. /// /// The stabilized version of this intrinsic is @@ -1419,7 +1419,7 @@ pub const unsafe fn floorf64(x: f64) -> f64; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn floorf128(x: f128) -> f128; +pub const fn floorf128(x: f128) -> f128; /// Returns the smallest integer greater than or equal to an `f16`. /// @@ -1428,7 +1428,7 @@ pub const unsafe fn floorf128(x: f128) -> f128; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn ceilf16(x: f16) -> f16; +pub const fn ceilf16(x: f16) -> f16; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is @@ -1436,7 +1436,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn ceilf32(x: f32) -> f32; +pub const fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. /// /// The stabilized version of this intrinsic is @@ -1444,7 +1444,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn ceilf64(x: f64) -> f64; +pub const fn ceilf64(x: f64) -> f64; /// Returns the smallest integer greater than or equal to an `f128`. /// /// The stabilized version of this intrinsic is @@ -1452,7 +1452,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn ceilf128(x: f128) -> f128; +pub const fn ceilf128(x: f128) -> f128; /// Returns the integer part of an `f16`. /// @@ -1461,7 +1461,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn truncf16(x: f16) -> f16; +pub const fn truncf16(x: f16) -> f16; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is @@ -1469,7 +1469,7 @@ pub const unsafe fn truncf16(x: f16) -> f16; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn truncf32(x: f32) -> f32; +pub const fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. /// /// The stabilized version of this intrinsic is @@ -1477,7 +1477,7 @@ pub const unsafe fn truncf32(x: f32) -> f32; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn truncf64(x: f64) -> f64; +pub const fn truncf64(x: f64) -> f64; /// Returns the integer part of an `f128`. /// /// The stabilized version of this intrinsic is @@ -1485,7 +1485,7 @@ pub const unsafe fn truncf64(x: f64) -> f64; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn truncf128(x: f128) -> f128; +pub const fn truncf128(x: f128) -> f128; /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number with an even /// least significant digit. @@ -1534,7 +1534,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn roundf16(x: f16) -> f16; +pub const fn roundf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -1542,7 +1542,7 @@ pub const unsafe fn roundf16(x: f16) -> f16; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn roundf32(x: f32) -> f32; +pub const fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -1550,7 +1550,7 @@ pub const unsafe fn roundf32(x: f32) -> f32; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn roundf64(x: f64) -> f64; +pub const fn roundf64(x: f64) -> f64; /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is @@ -1558,10 +1558,10 @@ pub const unsafe fn roundf64(x: f64) -> f64; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[rustc_nounwind] -pub const unsafe fn roundf128(x: f128) -> f128; +pub const fn roundf128(x: f128) -> f128; /// Float addition that allows optimizations based on algebraic rules. -/// May assume inputs are finite. +/// Requires that inputs and output of the operation are finite, causing UB otherwise. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] @@ -1569,7 +1569,7 @@ pub const unsafe fn roundf128(x: f128) -> f128; pub unsafe fn fadd_fast(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. -/// May assume inputs are finite. +/// Requires that inputs and output of the operation are finite, causing UB otherwise. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] @@ -1577,7 +1577,7 @@ pub unsafe fn fadd_fast(a: T, b: T) -> T; pub unsafe fn fsub_fast(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. -/// May assume inputs are finite. +/// Requires that inputs and output of the operation are finite, causing UB otherwise. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] @@ -1585,7 +1585,7 @@ pub unsafe fn fsub_fast(a: T, b: T) -> T; pub unsafe fn fmul_fast(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. -/// May assume inputs are finite. +/// Requires that inputs and output of the operation are finite, causing UB otherwise. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] @@ -1593,7 +1593,7 @@ pub unsafe fn fmul_fast(a: T, b: T) -> T; pub unsafe fn fdiv_fast(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. -/// May assume inputs are finite. +/// Requires that inputs and output of the operation are finite, causing UB otherwise. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 66c892aadd08..6088fb6fa178 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1459,8 +1459,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf128(self) } + intrinsics::floorf128(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -1488,8 +1487,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf128(self) } + intrinsics::ceilf128(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -1523,8 +1521,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf128(self) } + intrinsics::roundf128(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -1587,8 +1584,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf128(self) } + intrinsics::truncf128(self) } /// Returns the fractional part of `self`. @@ -1664,8 +1660,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn mul_add(self, a: f128, b: f128) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf128(self, a, b) } + intrinsics::fmaf128(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -1780,8 +1775,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powi(self, n: i32) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif128(self, n) } + intrinsics::powif128(self, n) } /// Returns the square root of a number. @@ -1816,7 +1810,6 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sqrt(self) -> f128 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf128(self) } + intrinsics::sqrtf128(self) } } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 81220065e72a..3f66c5973d4a 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1434,8 +1434,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(self) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf16(self) } + intrinsics::floorf16(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -1463,8 +1462,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(self) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf16(self) } + intrinsics::ceilf16(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -1498,8 +1496,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(self) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf16(self) } + intrinsics::roundf16(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -1562,8 +1559,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(self) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf16(self) } + intrinsics::truncf16(self) } /// Returns the fractional part of `self`. @@ -1639,8 +1635,7 @@ impl f16 { #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn mul_add(self, a: f16, b: f16) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf16(self, a, b) } + intrinsics::fmaf16(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -1755,8 +1750,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powi(self, n: i32) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif16(self, n) } + intrinsics::powif16(self, n) } /// Returns the square root of a number. @@ -1791,8 +1785,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sqrt(self) -> f16 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf16(self) } + intrinsics::sqrtf16(self) } /// Returns the cube root of a number. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index cefcf1d1fe2f..ebce89e5b3da 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1603,8 +1603,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf32(x) } + intrinsics::floorf32(x) } /// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details. @@ -1632,8 +1631,7 @@ pub mod math { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] pub const fn ceil(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf32(x) } + intrinsics::ceilf32(x) } /// Experimental version of `round` in `core`. See [`f32::round`] for details. @@ -1666,8 +1664,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf32(x) } + intrinsics::roundf32(x) } /// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for @@ -1729,8 +1726,7 @@ pub mod math { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] pub const fn trunc(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf32(x) } + intrinsics::truncf32(x) } /// Experimental version of `fract` in `core`. See [`f32::fract`] for details. @@ -1804,8 +1800,7 @@ pub mod math { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf32(x, y, z) } + intrinsics::fmaf32(x, y, z) } /// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details. @@ -1896,8 +1891,7 @@ pub mod math { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] pub fn powi(x: f32, n: i32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif32(x, n) } + intrinsics::powif32(x, n) } /// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details. @@ -1927,8 +1921,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sqrt(x: f32) -> f32 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf32(x) } + intrinsics::sqrtf32(x) } /// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 9dd1141e7033..91e3949fc390 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1601,8 +1601,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn floor(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::floorf64(x) } + intrinsics::floorf64(x) } /// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details. @@ -1630,8 +1629,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn ceil(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::ceilf64(x) } + intrinsics::ceilf64(x) } /// Experimental version of `round` in `core`. See [`f64::round`] for details. @@ -1664,8 +1662,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn round(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::roundf64(x) } + intrinsics::roundf64(x) } /// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for @@ -1727,8 +1724,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn trunc(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::truncf64(x) } + intrinsics::truncf64(x) } /// Experimental version of `fract` in `core`. See [`f64::fract`] for details. @@ -1802,8 +1798,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::fmaf64(x, a, b) } + intrinsics::fmaf64(x, a, b) } /// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details. @@ -1894,8 +1889,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powi(x: f64, n: i32) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::powif64(x, n) } + intrinsics::powif64(x, n) } /// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details. @@ -1925,8 +1919,7 @@ pub mod math { #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sqrt(x: f64) -> f64 { - // SAFETY: intrinsic with no preconditions - unsafe { intrinsics::sqrtf64(x) } + intrinsics::sqrtf64(x) } /// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details. diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs index b83692390b6b..5d206c4b7da5 100644 --- a/library/std/src/num/f128.rs +++ b/library/std/src/num/f128.rs @@ -44,7 +44,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powf(self, n: f128) -> f128 { - unsafe { intrinsics::powf128(self, n) } + intrinsics::powf128(self, n) } /// Returns `e^(self)`, (the exponential function). @@ -76,7 +76,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp(self) -> f128 { - unsafe { intrinsics::expf128(self) } + intrinsics::expf128(self) } /// Returns `2^(self)`. @@ -106,7 +106,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp2(self) -> f128 { - unsafe { intrinsics::exp2f128(self) } + intrinsics::exp2f128(self) } /// Returns the natural logarithm of the number. @@ -151,7 +151,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln(self) -> f128 { - unsafe { intrinsics::logf128(self) } + intrinsics::logf128(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -241,7 +241,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log2(self) -> f128 { - unsafe { intrinsics::log2f128(self) } + intrinsics::log2f128(self) } /// Returns the base 10 logarithm of the number. @@ -284,7 +284,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log10(self) -> f128 { - unsafe { intrinsics::log10f128(self) } + intrinsics::log10f128(self) } /// Returns the cube root of a number. @@ -385,7 +385,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sin(self) -> f128 { - unsafe { intrinsics::sinf128(self) } + intrinsics::sinf128(self) } /// Computes the cosine of a number (in radians). @@ -414,7 +414,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cos(self) -> f128 { - unsafe { intrinsics::cosf128(self) } + intrinsics::cosf128(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 5599528717cb..2565ef0f9f2c 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -44,7 +44,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powf(self, n: f16) -> f16 { - unsafe { intrinsics::powf16(self, n) } + intrinsics::powf16(self, n) } /// Returns `e^(self)`, (the exponential function). @@ -76,7 +76,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp(self) -> f16 { - unsafe { intrinsics::expf16(self) } + intrinsics::expf16(self) } /// Returns `2^(self)`. @@ -106,7 +106,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp2(self) -> f16 { - unsafe { intrinsics::exp2f16(self) } + intrinsics::exp2f16(self) } /// Returns the natural logarithm of the number. @@ -151,7 +151,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln(self) -> f16 { - unsafe { intrinsics::logf16(self) } + intrinsics::logf16(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -241,7 +241,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log2(self) -> f16 { - unsafe { intrinsics::log2f16(self) } + intrinsics::log2f16(self) } /// Returns the base 10 logarithm of the number. @@ -284,7 +284,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log10(self) -> f16 { - unsafe { intrinsics::log10f16(self) } + intrinsics::log10f16(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -350,7 +350,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sin(self) -> f16 { - unsafe { intrinsics::sinf16(self) } + intrinsics::sinf16(self) } /// Computes the cosine of a number (in radians). @@ -379,7 +379,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cos(self) -> f16 { - unsafe { intrinsics::cosf16(self) } + intrinsics::cosf16(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 0247080a8d6b..ac1d889cc373 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -338,7 +338,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powf(self, n: f32) -> f32 { - unsafe { intrinsics::powf32(self, n) } + intrinsics::powf32(self, n) } /// Returns the square root of a number. @@ -395,7 +395,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f32 { - unsafe { intrinsics::expf32(self) } + intrinsics::expf32(self) } /// Returns `2^(self)`. @@ -420,7 +420,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f32 { - unsafe { intrinsics::exp2f32(self) } + intrinsics::exp2f32(self) } /// Returns the natural logarithm of the number. @@ -455,7 +455,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f32 { - unsafe { intrinsics::logf32(self) } + intrinsics::logf32(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -525,7 +525,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { - unsafe { intrinsics::log2f32(self) } + intrinsics::log2f32(self) } /// Returns the base 10 logarithm of the number. @@ -558,7 +558,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f32 { - unsafe { intrinsics::log10f32(self) } + intrinsics::log10f32(self) } /// The positive difference of two numbers. @@ -683,7 +683,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f32 { - unsafe { intrinsics::sinf32(self) } + intrinsics::sinf32(self) } /// Computes the cosine of a number (in radians). @@ -707,7 +707,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f32 { - unsafe { intrinsics::cosf32(self) } + intrinsics::cosf32(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 1cfd3909d967..55c8593a0c0b 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -338,7 +338,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powf(self, n: f64) -> f64 { - unsafe { intrinsics::powf64(self, n) } + intrinsics::powf64(self, n) } /// Returns the square root of a number. @@ -395,7 +395,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f64 { - unsafe { intrinsics::expf64(self) } + intrinsics::expf64(self) } /// Returns `2^(self)`. @@ -420,7 +420,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f64 { - unsafe { intrinsics::exp2f64(self) } + intrinsics::exp2f64(self) } /// Returns the natural logarithm of the number. @@ -455,7 +455,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f64 { - unsafe { intrinsics::logf64(self) } + intrinsics::logf64(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -525,7 +525,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - unsafe { intrinsics::log2f64(self) } + intrinsics::log2f64(self) } /// Returns the base 10 logarithm of the number. @@ -558,7 +558,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f64 { - unsafe { intrinsics::log10f64(self) } + intrinsics::log10f64(self) } /// The positive difference of two numbers. @@ -683,7 +683,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f64 { - unsafe { intrinsics::sinf64(self) } + intrinsics::sinf64(self) } /// Computes the cosine of a number (in radians). @@ -707,7 +707,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f64 { - unsafe { intrinsics::cosf64(self) } + intrinsics::cosf64(self) } /// Computes the tangent of a number (in radians). diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs index bc4c438038dc..40612660d4db 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs @@ -10183,7 +10183,7 @@ pub fn vfmad_lane_f64(a: f64, b: f64, c: float64x1_t) -> f64 { #[target_feature(enable = "neon,fp16")] #[unstable(feature = "stdarch_neon_f16", issue = "136306")] pub fn vfmah_f16(a: f16, b: f16, c: f16) -> f16 { - unsafe { fmaf16(b, c, a) } + fmaf16(b, c, a) } #[doc = "Floating-point fused multiply-add to accumulator"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmah_lane_f16)"] @@ -23045,7 +23045,7 @@ pub fn vrndaq_f64(a: float64x2_t) -> float64x2_t { #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg_attr(test, assert_instr(frinta))] pub fn vrndah_f16(a: f16) -> f16 { - unsafe { roundf16(a) } + roundf16(a) } #[doc = "Floating-point round to integral, to nearest with ties to away"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndh_f16)"] @@ -23054,7 +23054,7 @@ pub fn vrndah_f16(a: f16) -> f16 { #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg_attr(test, assert_instr(frintz))] pub fn vrndh_f16(a: f16) -> f16 { - unsafe { truncf16(a) } + truncf16(a) } #[doc = "Floating-point round to integral, using current rounding mode"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndi_f16)"] @@ -23229,7 +23229,7 @@ pub fn vrndmq_f64(a: float64x2_t) -> float64x2_t { #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg_attr(test, assert_instr(frintm))] pub fn vrndmh_f16(a: f16) -> f16 { - unsafe { floorf16(a) } + floorf16(a) } #[doc = "Floating-point round to integral, to nearest with ties to even"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndn_f64)"] @@ -23356,7 +23356,7 @@ pub fn vrndpq_f64(a: float64x2_t) -> float64x2_t { #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg_attr(test, assert_instr(frintp))] pub fn vrndph_f16(a: f16) -> f16 { - unsafe { ceilf16(a) } + ceilf16(a) } #[doc = "Floating-point round to integral exact, using current rounding mode"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndx_f16)"] @@ -24846,7 +24846,7 @@ pub fn vsqrtq_f64(a: float64x2_t) -> float64x2_t { #[unstable(feature = "stdarch_neon_f16", issue = "136306")] #[cfg_attr(test, assert_instr(fsqrt))] pub fn vsqrth_f16(a: f16) -> f16 { - unsafe { sqrtf16(a) } + sqrtf16(a) } #[doc = "Shift Right and Insert (immediate)"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsri_n_s8)"] diff --git a/library/stdarch/crates/core_arch/src/wasm32/mod.rs b/library/stdarch/crates/core_arch/src/wasm32/mod.rs index 60049c73295c..01bf0a71658b 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/mod.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/mod.rs @@ -43,7 +43,7 @@ pub fn unreachable() -> ! { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f32_ceil(a: f32) -> f32 { - unsafe { crate::intrinsics::ceilf32(a) } + crate::intrinsics::ceilf32(a) } /// Generates the [`f32.floor`] instruction, returning the largest integer less than or equal to `a`. @@ -57,7 +57,7 @@ pub fn f32_ceil(a: f32) -> f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f32_floor(a: f32) -> f32 { - unsafe { crate::intrinsics::floorf32(a) } + crate::intrinsics::floorf32(a) } /// Generates the [`f32.trunc`] instruction, roundinging to the nearest integer towards zero. @@ -71,7 +71,7 @@ pub fn f32_floor(a: f32) -> f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f32_trunc(a: f32) -> f32 { - unsafe { crate::intrinsics::truncf32(a) } + crate::intrinsics::truncf32(a) } /// Generates the [`f32.nearest`] instruction, roundinging to the nearest integer. Rounds half-way @@ -100,7 +100,7 @@ pub fn f32_nearest(a: f32) -> f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f32_sqrt(a: f32) -> f32 { - unsafe { crate::intrinsics::sqrtf32(a) } + crate::intrinsics::sqrtf32(a) } /// Generates the [`f64.ceil`] instruction, returning the smallest integer greater than or equal to `a`. @@ -114,7 +114,7 @@ pub fn f32_sqrt(a: f32) -> f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f64_ceil(a: f64) -> f64 { - unsafe { crate::intrinsics::ceilf64(a) } + crate::intrinsics::ceilf64(a) } /// Generates the [`f64.floor`] instruction, returning the largest integer less than or equal to `a`. @@ -128,7 +128,7 @@ pub fn f64_ceil(a: f64) -> f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f64_floor(a: f64) -> f64 { - unsafe { crate::intrinsics::floorf64(a) } + crate::intrinsics::floorf64(a) } /// Generates the [`f64.trunc`] instruction, roundinging to the nearest integer towards zero. @@ -142,7 +142,7 @@ pub fn f64_floor(a: f64) -> f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f64_trunc(a: f64) -> f64 { - unsafe { crate::intrinsics::truncf64(a) } + crate::intrinsics::truncf64(a) } /// Generates the [`f64.nearest`] instruction, roundinging to the nearest integer. Rounds half-way @@ -171,7 +171,7 @@ pub fn f64_nearest(a: f64) -> f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "wasm_numeric_instr", issue = "133908")] pub fn f64_sqrt(a: f64) -> f64 { - unsafe { crate::intrinsics::sqrtf64(a) } + crate::intrinsics::sqrtf64(a) } unsafe extern "C-unwind" { diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml index a31613e6b1ae..ece435870ae2 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml @@ -3054,7 +3054,7 @@ intrinsics: types: - [f16, 'h_'] compose: - - FnCall: [roundf16, [a], [], true] + - FnCall: [roundf16, [a], []] - name: "vrndn{neon_type.no}" doc: "Floating-point round to integral, to nearest with ties to even" @@ -3151,7 +3151,7 @@ intrinsics: types: - [f16, 'h_'] compose: - - FnCall: [floorf16, [a], [], true] + - FnCall: [floorf16, [a], []] @@ -3198,7 +3198,7 @@ intrinsics: types: - [f16, 'h_'] compose: - - FnCall: [ceilf16, [a], [], true] + - FnCall: [ceilf16, [a], []] - name: "vrnd{neon_type.no}" doc: "Floating-point round to integral, toward zero" @@ -3243,7 +3243,7 @@ intrinsics: types: - [f16, 'h_'] compose: - - FnCall: [truncf16, [a], [], true] + - FnCall: [truncf16, [a], []] - name: "vrndi{neon_type.no}" @@ -8398,7 +8398,7 @@ intrinsics: types: - [f16, 'h_'] compose: - - FnCall: [sqrtf16, [a], [], true] + - FnCall: [sqrtf16, [a], []] - name: "vrsqrts{type[0]}" doc: "Floating-point reciprocal square root step" @@ -10346,7 +10346,7 @@ intrinsics: types: - ["f16", "h_f16"] compose: - - FnCall: [fmaf16, [b, c, a], [], true] + - FnCall: [fmaf16, [b, c, a], []] - name: "vfmah_lane{type[2]}" diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 9f1b3f612b2d..323019df4250 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1401,12 +1401,12 @@ fn test_fmuladd() { #[inline(never)] pub fn test_operations_f32(a: f32, b: f32, c: f32) { - assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c); + assert_approx_eq!(fmuladdf32(a, b, c), a * b + c); } #[inline(never)] pub fn test_operations_f64(a: f64, b: f64, c: f64) { - assert_approx_eq!(unsafe { fmuladdf64(a, b, c) }, a * b + c); + assert_approx_eq!(fmuladdf64(a, b, c), a * b + c); } test_operations_f32(0.1, 0.2, 0.3); diff --git a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs index b688405c4b18..4d3e91c4cba7 100644 --- a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs +++ b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs @@ -28,7 +28,7 @@ fn main() { let c = std::hint::black_box(-a * b); // It is unspecified whether the following operation is fused or not. The // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. - let x = unsafe { fmuladdf64(a, b, c) }; + let x = fmuladdf64(a, b, c); x == 0.0 }), "`fmuladdf64` failed to be evaluated as both fused and unfused" @@ -41,7 +41,7 @@ fn main() { let c = std::hint::black_box(-a * b); // It is unspecified whether the following operation is fused or not. The // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. - let x = unsafe { fmuladdf32(a, b, c) }; + let x = fmuladdf32(a, b, c); x == 0.0 }), "`fmuladdf32` failed to be evaluated as both fused and unfused" diff --git a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs index 4bec579831dc..255f20e6ff64 100644 --- a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs +++ b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs @@ -7,7 +7,5 @@ use std::intrinsics::sqrtf32; // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} fn main() { - unsafe { - sqrtf32(0.0f32); - } + sqrtf32(0.0f32); } diff --git a/tests/ui/intrinsics/intrinsic-fmuladd.rs b/tests/ui/intrinsics/intrinsic-fmuladd.rs index d03297884f79..ab4285590cb9 100644 --- a/tests/ui/intrinsics/intrinsic-fmuladd.rs +++ b/tests/ui/intrinsics/intrinsic-fmuladd.rs @@ -11,7 +11,7 @@ macro_rules! assert_approx_eq { } fn main() { - unsafe { + { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; @@ -25,7 +25,7 @@ fn main() { assert_eq!(fmuladdf32(8.9, inf, 3.2), inf); assert_eq!(fmuladdf32(-3.2, 2.4, neg_inf), neg_inf); } - unsafe { + { let nan: f64 = f64::NAN; let inf: f64 = f64::INFINITY; let neg_inf: f64 = f64::NEG_INFINITY; diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index aea6f838e0d4..1307a85c8b6c 100644 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr @@ -22,7 +22,7 @@ LL | std::intrinsics::floorf32, | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | = note: expected fn pointer `unsafe fn(_) -> _` - found fn item `unsafe fn(_) -> _ {floorf32}` + found fn item `fn(_) -> _ {floorf32}` error: aborting due to 3 previous errors From ab7cfc7c307d50659a0165dad910565809f5d40f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 22 Sep 2025 02:14:50 +0300 Subject: [PATCH 131/537] Clarify `rust-analyzer.inlayHints.maxLength` is not a hard guarantee --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 ++ .../rust-analyzer/docs/book/src/configuration_generated.md | 2 ++ src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 6b489d511438..a88d228fcb60 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -267,6 +267,8 @@ config_data! { inlayHints_lifetimeElisionHints_useParameterNames: bool = false, /// Maximum length for inlay hints. Set to null to have an unlimited length. + /// + /// **Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit. inlayHints_maxLength: Option = Some(25), /// Show function parameter name inlay hints at the call site. diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 50dacd88f407..e78f1b4ba358 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1046,6 +1046,8 @@ Default: `25` Maximum length for inlay hints. Set to null to have an unlimited length. +**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit. + ## rust-analyzer.inlayHints.parameterHints.enable {#inlayHints.parameterHints.enable} diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 1d27a1205355..745e0da4efef 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2355,7 +2355,7 @@ "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.maxLength": { - "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.", + "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.\n\n**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.", "default": 25, "type": [ "null", From 8f1a1f8533cb270625a057a2bb7f50ef3f8ec1b5 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 05:45:23 +0200 Subject: [PATCH 132/537] Update tests/rustdoc/private-mod-override-re-export.rs Co-authored-by: lolbinarycat --- tests/rustdoc/private-mod-override-re-export.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rustdoc/private-mod-override-re-export.rs b/tests/rustdoc/private-mod-override-re-export.rs index 47b07958709b..8deafe242225 100644 --- a/tests/rustdoc/private-mod-override-re-export.rs +++ b/tests/rustdoc/private-mod-override-re-export.rs @@ -11,4 +11,4 @@ mod m1 { pub use m1::*; use crate::m1::m2; -//@ !has foo/index.html '//a[@href="m2/index.html"]' 'm2' +//@ count foo/index.html '//a[@class="mod"]' 0 From 52e6998a1837884daad9c9a0f8bf78631557fd2a Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 11:47:12 +0800 Subject: [PATCH 133/537] Move test file --- .../private-mod-override-reexport.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc/{private-mod-override-re-export.rs => reexport/private-mod-override-reexport.rs} (100%) diff --git a/tests/rustdoc/private-mod-override-re-export.rs b/tests/rustdoc/reexport/private-mod-override-reexport.rs similarity index 100% rename from tests/rustdoc/private-mod-override-re-export.rs rename to tests/rustdoc/reexport/private-mod-override-reexport.rs From 9acc63a48c8206cfe2c2d272600d538983308657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 17 Sep 2025 22:29:49 -0700 Subject: [PATCH 134/537] port `#[debugger_visualizer]` to the new attribute system --- .../src/attributes/debugger.rs | 60 ++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 + .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 4 +- .../rustc_hir/src/attrs/data_structures.rs | 19 ++- .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/middle/debugger_visualizer.rs | 8 +- compiler/rustc_passes/messages.ftl | 9 -- compiler/rustc_passes/src/check_attr.rs | 16 +-- .../rustc_passes/src/debugger_visualizer.rs | 113 +++++++++--------- compiler/rustc_passes/src/errors.rs | 17 --- tests/ui/attributes/malformed-attrs.rs | 3 +- tests/ui/attributes/malformed-attrs.stderr | 53 ++++---- .../invalid-debugger-visualizer-option.rs | 2 +- .../invalid-debugger-visualizer-option.stderr | 22 ++-- .../invalid-debugger-visualizer-target.rs | 3 +- .../invalid-debugger-visualizer-target.stderr | 4 +- 18 files changed, 185 insertions(+), 154 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/debugger.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs new file mode 100644 index 000000000000..56ff10be4264 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -0,0 +1,60 @@ +use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType}; + +use super::prelude::*; + +pub(crate) struct DebuggerViualizerParser; + +impl CombineAttributeParser for DebuggerViualizerParser { + const PATH: &[Symbol] = &[sym::debugger_visualizer]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]); + const TEMPLATE: AttributeTemplate = template!( + List: &[r#"natvis_file = "...", gdb_script_file = "...""#], + "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute" + ); + + type Item = DebugVisualizer; + const CONVERT: ConvertFn = |v, _| AttributeKind::DebuggerVisualizer(v); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c { + let Some(l) = args.list() else { + cx.expected_list(args.span().unwrap_or(cx.attr_span)); + return None; + }; + let Some(single) = l.single() else { + cx.expected_single_argument(l.span); + return None; + }; + let Some(mi) = single.meta_item() else { + cx.expected_name_value(single.span(), None); + return None; + }; + let path = mi.path().word_sym(); + let visualizer_type = match path { + Some(sym::natvis_file) => DebuggerVisualizerType::Natvis, + Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter, + _ => { + cx.expected_specific_argument( + mi.path().span(), + &[sym::natvis_file, sym::gdb_script_file], + ); + return None; + } + }; + + let Some(path) = mi.args().name_value() else { + cx.expected_name_value(single.span(), path); + return None; + }; + + let Some(path) = path.value_as_str() else { + cx.expected_string_literal(path.value_span, Some(path.value_as_lit())); + return None; + }; + + Some(DebugVisualizer { span: mi.span(), visualizer_type, path }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 4ed13d239b9d..8dbf4c0ef32e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod crate_level; +pub(crate) mod debugger; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4c32bb87a242..1f1f9d6d50e5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,6 +28,7 @@ use crate::attributes::crate_level::{ CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser, }; +use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -163,6 +164,7 @@ attribute_parsers!( // tidy-alphabetical-start Combine, Combine, + Combine, Combine, Combine, Combine, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 7a6dc008c7b9..3081badb821f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -2,9 +2,9 @@ use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; +use rustc_hir::attrs::DebuggerVisualizerType; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; -use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType; use rustc_session::config::{CrateType, DebugInfo}; use crate::builder::Builder; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 68a2f43ec67b..422b06350e1f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::attrs::OptimizeAttr; +use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; use rustc_middle::middle::lang_items; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8ab43ff2582c..5a9e644f9702 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -363,6 +363,20 @@ pub struct LinkEntry { pub import_name_type: Option<(PeImportNameType, Span)>, } +#[derive(HashStable_Generic, PrintAttribute)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] +pub enum DebuggerVisualizerType { + Natvis, + GdbPrettyPrinter, +} + +#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +pub struct DebugVisualizer { + pub span: Span, + pub visualizer_type: DebuggerVisualizerType, + pub path: Symbol, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -485,7 +499,10 @@ pub enum AttributeKind { /// Represents `#[custom_mir]`. CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span), - ///Represents `#[rustc_deny_explicit_impl]`. + /// Represents `#[debugger_visualizer]`. + DebuggerVisualizer(ThinVec), + + /// Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 8e4434050747..7112daa327e2 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -37,6 +37,7 @@ impl AttributeKind { Coverage(..) => No, CrateName { .. } => No, CustomMir(_, _, _) => Yes, + DebuggerVisualizer(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index 5a811321f58b..a7f0095dcdfb 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -1,15 +1,9 @@ use std::path::PathBuf; use std::sync::Arc; +use rustc_hir::attrs::DebuggerVisualizerType; use rustc_macros::{Decodable, Encodable, HashStable}; -#[derive(HashStable)] -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] -pub enum DebuggerVisualizerType { - Natvis, - GdbPrettyPrinter, -} - /// A single debugger visualizer file. #[derive(HashStable)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6cd68380e46f..870e0a90b542 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -93,15 +93,6 @@ passes_dead_codes = } } never {$participle} -passes_debug_visualizer_invalid = - invalid argument - .note_1 = expected: `natvis_file = "..."` - .note_2 = OR - .note_3 = expected: `gdb_script_file = "..."` - -passes_debug_visualizer_placement = - attribute should be applied to a module - passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 94c9e71ce770..9f40e713e508 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -281,6 +281,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcClass { .. } | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) + | AttributeKind::DebuggerVisualizer(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -301,7 +302,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), [sym::rustc_no_implicit_autorefs, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } @@ -1782,20 +1782,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. - fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) { - // Here we only check that the #[debugger_visualizer] attribute is attached - // to nothing other than a module. All other checks are done in the - // `debugger_visualizer` query where they need to be done for decoding - // anyway. - match target { - Target::Mod => {} - _ => { - self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() }); - } - } - } - /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) fn check_rustc_allow_const_fn_unstable( diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 7a7a8175e556..7211f3cf85b3 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,67 +1,60 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. -use rustc_ast::Attribute; +use rustc_ast::ast::NodeId; +use rustc_ast::{HasNodeId, ItemKind, ast}; +use rustc_attr_parsing::AttributeParser; use rustc_expand::base::resolve_path; -use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, DebugVisualizer}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::sym; +use rustc_span::{DUMMY_SP, Span, sym}; -use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable}; +use crate::errors::DebugVisualizerUnreadable; impl DebuggerVisualizerCollector<'_> { - fn check_for_debugger_visualizer(&mut self, attr: &Attribute) { - if attr.has_name(sym::debugger_visualizer) { - let Some(hints) = attr.meta_item_list() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; + fn check_for_debugger_visualizer( + &mut self, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, + ) { + if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) = + AttributeParser::parse_limited( + &self.sess, + attrs, + sym::debugger_visualizer, + span, + node_id, + None, + ) + { + for DebugVisualizer { span, visualizer_type, path } in visualizers { + let file = match resolve_path(&self.sess, path.as_str(), span) { + Ok(file) => file, + Err(err) => { + err.emit(); + return; + } + }; - let [hint] = hints.as_slice() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; - - let Some(meta_item) = hint.meta_item() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; - - let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str()) - { - (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value), - (Some(sym::gdb_script_file), Some(value)) => { - (DebuggerVisualizerType::GdbPrettyPrinter, value) - } - (_, _) => { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span }); - return; - } - }; - - let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) { - Ok(file) => file, - Err(err) => { - err.emit(); - return; - } - }; - - match self.sess.source_map().load_binary_file(&file) { - Ok((source, _)) => { - self.visualizers.push(DebuggerVisualizerFile::new( - source, - visualizer_type, - file, - )); - } - Err(error) => { - self.sess.dcx().emit_err(DebugVisualizerUnreadable { - span: meta_item.span, - file: &file, - error, - }); + match self.sess.source_map().load_binary_file(&file) { + Ok((source, _)) => { + self.visualizers.push(DebuggerVisualizerFile::new( + source, + visualizer_type, + file, + )); + } + Err(error) => { + self.sess.dcx().emit_err(DebugVisualizerUnreadable { + span, + file: &file, + error, + }); + } } } } @@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> { } impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { - fn visit_attribute(&mut self, attr: &'ast Attribute) { - self.check_for_debugger_visualizer(attr); - rustc_ast::visit::walk_attribute(self, attr); + fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result { + if let ItemKind::Mod(..) = item.kind { + self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id()); + } + rustc_ast::visit::walk_item(self, item); + } + fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result { + self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id); + rustc_ast::visit::walk_crate(self, krate); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cd8935f6b2f0..cfd6b9e6dffa 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -475,23 +475,6 @@ pub(crate) struct MacroOnlyAttribute { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_debug_visualizer_placement)] -pub(crate) struct DebugVisualizerPlacement { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_debug_visualizer_invalid)] -#[note(passes_note_1)] -#[note(passes_note_2)] -#[note(passes_note_3)] -pub(crate) struct DebugVisualizerInvalid { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_debug_visualizer_unreadable)] pub(crate) struct DebugVisualizerUnreadable<'a> { diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index e30479b03b11..820484aa015d 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -185,8 +185,7 @@ extern "C" { #[forbid] //~^ ERROR malformed #[debugger_visualizer] -//~^ ERROR invalid argument -//~| ERROR malformed `debugger_visualizer` attribute input +//~^ ERROR malformed `debugger_visualizer` attribute input #[automatically_derived = 18] //~^ ERROR malformed mod yooo { diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 246029ecf80f..70ab3fb13c49 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:210:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate @@ -156,22 +156,14 @@ LL | #[forbid(lint1, lint2, ...)] LL | #[forbid(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ -error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:187:1 - | -LL | #[debugger_visualizer] - | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` - | - = note: for more information, visit - error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:202:1 + --> $DIR/malformed-attrs.rs:201:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:206:1 + --> $DIR/malformed-attrs.rs:205:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` @@ -197,7 +189,7 @@ LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:214:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -226,16 +218,6 @@ LL | #[doc] = note: for more information, see issue #57571 = note: for more information, visit -error: invalid argument - --> $DIR/malformed-attrs.rs:187:1 - | -LL | #[debugger_visualizer] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: expected: `natvis_file = "..."` - = note: OR - = note: expected: `gdb_script_file = "..."` - error[E0539]: malformed `export_name` attribute input --> $DIR/malformed-attrs.rs:29:1 | @@ -685,8 +667,19 @@ LL | #[linkage = "external"] | ++++++++++++ = and 5 other candidates +error[E0539]: malformed `debugger_visualizer` attribute input + --> $DIR/malformed-attrs.rs:187:1 + | +LL | #[debugger_visualizer] + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` + | + = note: for more information, visit + error[E0565]: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:190:1 + --> $DIR/malformed-attrs.rs:189:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -695,7 +688,7 @@ LL | #[automatically_derived = 18] | help: must be of the form: `#[automatically_derived]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:196:1 + --> $DIR/malformed-attrs.rs:195:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -704,19 +697,19 @@ LL | #[non_exhaustive = 1] | help: must be of the form: `#[non_exhaustive]` error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:207:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]` - --> $DIR/malformed-attrs.rs:213:1 + --> $DIR/malformed-attrs.rs:212:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ error[E0565]: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:215:1 + --> $DIR/malformed-attrs.rs:214:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^---^ @@ -800,7 +793,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:222:1 + --> $DIR/malformed-attrs.rs:221:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -819,7 +812,7 @@ LL | #[coroutine = 63] || {} = note: expected unit type `()` found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}` -error: aborting due to 77 previous errors; 3 warnings emitted +error: aborting due to 76 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. @@ -871,7 +864,7 @@ LL | #[ignore()] Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:222:1 + --> $DIR/malformed-attrs.rs:221:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.rs b/tests/ui/invalid/invalid-debugger-visualizer-option.rs index 0f1cf15a6879..166962866dce 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-option.rs +++ b/tests/ui/invalid/invalid-debugger-visualizer-option.rs @@ -1,6 +1,6 @@ //@ normalize-stderr: "foo.random:.*\(" -> "foo.random: $$FILE_NOT_FOUND_MSG (" //@ normalize-stderr: "os error \d+" -> "os error $$FILE_NOT_FOUND_CODE" -#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR invalid argument +#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR malformed `debugger_visualizer` attribute input #![debugger_visualizer(natvis_file = "../foo.random")] //~ ERROR fn main() {} diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr index 6fbb4d641e6f..e877e39d8f11 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr +++ b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr @@ -1,18 +1,20 @@ -error: invalid argument - --> $DIR/invalid-debugger-visualizer-option.rs:4:24 - | -LL | #![debugger_visualizer(random_file = "../foo.random")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: expected: `natvis_file = "..."` - = note: OR - = note: expected: `gdb_script_file = "..."` - error: couldn't read $DIR/../foo.random: $FILE_NOT_FOUND_MSG (os error $FILE_NOT_FOUND_CODE) --> $DIR/invalid-debugger-visualizer-option.rs:5:24 | LL | #![debugger_visualizer(natvis_file = "../foo.random")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0539]: malformed `debugger_visualizer` attribute input + --> $DIR/invalid-debugger-visualizer-option.rs:4:1 + | +LL | #![debugger_visualizer(random_file = "../foo.random")] + | ^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^ + | | | + | | valid arguments are `natvis_file` or `gdb_script_file` + | help: must be of the form: `#![debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` + | + = note: for more information, visit + error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/invalid/invalid-debugger-visualizer-target.rs index 1efb9555c242..48b041532140 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.rs +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.rs @@ -1,2 +1,3 @@ -#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module +#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] +//~^ ERROR `#[debugger_visualizer]` attribute cannot be used on functions fn main() {} diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr index 1df345325337..629af94c5ef2 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr @@ -1,8 +1,10 @@ -error: attribute should be applied to a module +error: `#[debugger_visualizer]` attribute cannot be used on functions --> $DIR/invalid-debugger-visualizer-target.rs:1:1 | LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[debugger_visualizer]` can be applied to modules and crates error: aborting due to 1 previous error From dc805bf49844d7bde1013f817c4368c1c3c485aa Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 22 Sep 2025 14:18:48 +0800 Subject: [PATCH 135/537] Fix apply in internal if for pull_assignment_up Example --- ```rust fn foo() { let mut a = 1; if true { a = 2; } else if true { $0a = 3; } else { a = 4; } } ``` **Before this PR**: ```rust fn foo() { let mut a = 1; if true { a = 2; } else a = if true { 3 } else { 4 }; } ``` **After this PR**: ```rust fn foo() { let mut a = 1; a = if true { 2 } else if true { 3 } else { 4 }; } ``` --- .../src/handlers/pull_assignment_up.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs index 21debf6745a6..00902fafe827 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs @@ -53,6 +53,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) -> }; let tgt: ast::Expr = if let Some(if_expr) = ctx.find_node_at_offset::() { + let if_expr = std::iter::successors(Some(if_expr), |it| { + it.syntax().parent().and_then(ast::IfExpr::cast) + }) + .last()?; collector.collect_if(&if_expr)?; if_expr.into() } else if let Some(match_expr) = ctx.find_node_at_offset::() { @@ -237,6 +241,37 @@ fn foo() { ); } + #[test] + fn test_pull_assignment_up_inner_if() { + check_assist( + pull_assignment_up, + r#" +fn foo() { + let mut a = 1; + + if true { + a = 2; + } else if true { + $0a = 3; + } else { + a = 4; + } +}"#, + r#" +fn foo() { + let mut a = 1; + + a = if true { + 2 + } else if true { + 3 + } else { + 4 + }; +}"#, + ); + } + #[test] fn test_pull_assignment_up_match() { check_assist( From c5e668274b56a0c83745336352fd9df9fe68e50a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 22 Sep 2025 14:45:31 +0800 Subject: [PATCH 136/537] Fix applicable on underscore for bind_unused_param Fixes: - applicable on underscore prefix parameter - using binding mode as an expression Examples --- ```rust fn foo($0_x: i32, y: i32) {} ``` **Before this PR**: ```rust fn foo(_x: i32, y: i32) { let _ = _x; } ``` **After this PR**: Assist not applicable --- ```rust fn foo(ref $0y: i32) {} ``` **Before this PR**: ```rust fn foo(ref y: i32) { let _ = ref y; } ``` **After this PR**: ```rust fn foo(ref y: i32) { let _ = y; } ``` --- .../src/handlers/bind_unused_param.rs | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs index 00c7d25b257b..1b24f7fe7ffb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs @@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists}; use ide_db::{LineIndexDatabase, assists::AssistId, defs::Definition}; use syntax::{ AstNode, - ast::{self, edit_in_place::Indent}, + ast::{self, HasName, edit_in_place::Indent}, }; // Assist: bind_unused_param @@ -22,6 +22,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let param: ast::Param = ctx.find_node_at_offset()?; let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None }; + let name = ident_pat.name().filter(|n| !n.text().starts_with('_'))?; let param_def = { let local = ctx.sema.to_def(&ident_pat)?; @@ -39,14 +40,14 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O acc.add( AssistId::quick_fix("bind_unused_param"), - format!("Bind as `let _ = {ident_pat};`"), + format!("Bind as `let _ = {name};`"), param.syntax().text_range(), |builder| { let line_index = ctx.db().line_index(ctx.vfs_file_id()); let indent = func.indent_level(); let text_indent = indent + 1; - let mut text = format!("\n{text_indent}let _ = {ident_pat};"); + let mut text = format!("\n{text_indent}let _ = {name};"); let left_line = line_index.line_col(l_curly_range.end()).line; let right_line = line_index.line_col(r_curly_range.start()).line; @@ -83,6 +84,22 @@ fn foo(y: i32) { ); } + #[test] + fn bind_unused_ref_ident_pat() { + cov_mark::check!(single_line); + check_assist( + bind_unused_param, + r#" +fn foo(ref $0y: i32) {} +"#, + r#" +fn foo(ref y: i32) { + let _ = y; +} +"#, + ); + } + #[test] fn bind_unused_empty_block_with_newline() { check_assist( @@ -149,6 +166,16 @@ impl Trait for () { bind_unused_param, r#" fn foo(x: i32, $0y: i32) { y; } +"#, + ); + } + + #[test] + fn keep_underscore_used() { + check_assist_not_applicable( + bind_unused_param, + r#" +fn foo($0_x: i32, y: i32) {} "#, ); } From 4193716963035cccc26dfde9dbf6a78a133dfb60 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 22 Sep 2025 10:26:03 +0300 Subject: [PATCH 137/537] Another regression test for next solver fixed bug --- .../hir-ty/src/tests/regression/new_solver.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index ead79a8f5b90..c7711f31bf26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -418,3 +418,35 @@ fn foo() { "#]], ); } + +#[test] +fn regression_19637() { + check_no_mismatches( + r#" +//- minicore: coerce_unsized +pub trait Any {} + +impl Any for T {} + +pub trait Trait: Any { + type F; +} + +pub struct TT {} + +impl Trait for TT { + type F = f32; +} + +pub fn coercion(x: &mut dyn Any) -> &mut dyn Any { + x +} + +fn main() { + let mut t = TT {}; + let tt = &mut t as &mut dyn Trait; + let st = coercion(tt); +} + "#, + ); +} From 7d0012914ea223ba1f6b7dae1ecd31be95e0051a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 09:28:38 +0200 Subject: [PATCH 138/537] assert_unsafe_precondition: fix some incorrect check_language_ub --- library/core/src/ascii/ascii_char.rs | 2 +- library/core/src/num/int_macros.rs | 6 +++--- library/core/src/num/uint_macros.rs | 4 ++-- library/core/src/slice/index.rs | 2 +- library/core/src/ub_checks.rs | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 178af2c0e3b4..d77fafed2039 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -515,7 +515,7 @@ impl AsciiChar { #[track_caller] pub const unsafe fn digit_unchecked(d: u8) -> Self { assert_unsafe_precondition!( - check_language_ub, + check_library_ub, "`ascii::Char::digit_unchecked` input cannot exceed 9.", (d: u8 = d) => d < 10 ); diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 64a3dd3e8bc5..0d80c40fb236 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1460,8 +1460,8 @@ macro_rules! int_impl { #[inline] pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( - check_language_ub, - concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"), + check_library_ub, + concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out bits that would change the value of the first bit"), ( zeros: u32 = self.leading_zeros(), ones: u32 = self.leading_ones(), @@ -1638,7 +1638,7 @@ macro_rules! int_impl { #[inline] pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( - check_language_ub, + check_library_ub, concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"), ( zeros: u32 = self.trailing_zeros(), diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index bf72ec831970..d68c7be9865b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1865,7 +1865,7 @@ macro_rules! uint_impl { #[inline] pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( - check_language_ub, + check_library_ub, concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"), ( zeros: u32 = self.leading_zeros(), @@ -2037,7 +2037,7 @@ macro_rules! uint_impl { #[inline] pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( - check_language_ub, + check_library_ub, concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"), ( zeros: u32 = self.trailing_zeros(), diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index a8147d745f3a..d4c466201edf 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -233,7 +233,7 @@ unsafe impl const SliceIndex<[T]> for usize { #[track_caller] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { assert_unsafe_precondition!( - check_language_ub, + check_language_ub, // okay because of the `assume` below "slice::get_unchecked requires that the index is within the slice", (this: usize = self, len: usize = slice.len()) => this < len ); diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index b809294cfcee..514ff93c9820 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -21,8 +21,9 @@ use crate::intrinsics::{self, const_eval_select}; /// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice /// diagnostic, but our ability to detect UB is unchanged. /// But if `check_language_ub` is used when the check is actually for library UB, the check is -/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the -/// library UB, the backtrace Miri reports may be far removed from original cause. +/// omitted in const-eval/Miri and thus UB might occur undetected. Even if we eventually execute +/// language UB which relies on the library UB, the backtrace Miri reports may be far removed from +/// original cause. /// /// These checks are behind a condition which is evaluated at codegen time, not expansion time like /// [`debug_assert`]. This means that a standard library built with optimizations and debug From e9b2c4f395673399b0445733c7e8d3955e42ff0c Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Thu, 15 May 2025 15:46:53 +0300 Subject: [PATCH 139/537] avoid violating `slice::from_raw_parts` safety contract in `Vec::extract_if` The implementation of the `Vec::extract_if` iterator violates the safety contract adverized by `slice::from_raw_parts` by always constructing a mutable slice for the entire length of the vector even though that span of memory can contain holes from items already drained. The safety contract of `slice::from_raw_parts` requires that all elements must be properly initialized. As an example we can look at the following code: ```rust let mut v = vec![Box::new(0u64), Box::new(1u64)]; for item in v.extract_if(.., |x| **x == 0) { drop(item); } ``` In the second iteration a `&mut [Box]` slice of length 2 will be constructed. The first slot of the slice contains the bitpattern of an already deallocated box, which is invalid. This fixes the issue by only creating references to valid items and using pointer manipulation for the rest. I have also taken the liberty to remove the big `unsafe` blocks in place of targetted ones with a SAFETY comment. The approach closely mirrors the implementation of `Vec::retain_mut`. Signed-off-by: Petros Angelatos --- library/alloc/src/vec/extract_if.rs | 64 ++++++++++++++++++----------- src/tools/miri/tests/pass/vec.rs | 10 +++++ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index a456d3d9e602..cb9e14f554d4 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -64,27 +64,37 @@ where type Item = T; fn next(&mut self) -> Option { - unsafe { - while self.idx < self.end { - let i = self.idx; - let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); - let drained = (self.pred)(&mut v[i]); - // Update the index *after* the predicate is called. If the index - // is updated prior and the predicate panics, the element at this - // index would be leaked. - self.idx += 1; - if drained { - self.del += 1; - return Some(ptr::read(&v[i])); - } else if self.del > 0 { - let del = self.del; - let src: *const T = &v[i]; - let dst: *mut T = &mut v[i - del]; - ptr::copy_nonoverlapping(src, dst, 1); + while self.idx < self.end { + let i = self.idx; + // SAFETY: + // We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from + // the validity of `Self`. Therefore `i` points to an element within `vec`. + // + // Additionally, the i-th element is valid because each element is visited at most once + // and it is the first time we access vec[i]. + // + // Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that + // function is that i < vec.len(), but we've set vec's length to zero. + let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) }; + let drained = (self.pred)(cur); + // Update the index *after* the predicate is called. If the index + // is updated prior and the predicate panics, the element at this + // index would be leaked. + self.idx += 1; + if drained { + self.del += 1; + // SAFETY: We never touch this element again after returning it. + return Some(unsafe { ptr::read(cur) }); + } else if self.del > 0 { + // SAFETY: `self.del` > 0, so the hole slot must not overlap with current element. + // We use copy for move, and never touch this element again. + unsafe { + let hole_slot = self.vec.as_mut_ptr().add(i - self.del); + ptr::copy_nonoverlapping(cur, hole_slot, 1); } } - None } + None } fn size_hint(&self) -> (usize, Option) { @@ -95,14 +105,18 @@ where #[stable(feature = "extract_if", since = "1.87.0")] impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { - unsafe { - if self.idx < self.old_len && self.del > 0 { - let ptr = self.vec.as_mut_ptr(); - let src = ptr.add(self.idx); - let dst = src.sub(self.del); - let tail_len = self.old_len - self.idx; - src.copy_to(dst, tail_len); + if self.del > 0 { + // SAFETY: Trailing unchecked items must be valid since we never touch them. + unsafe { + ptr::copy( + self.vec.as_ptr().add(self.idx), + self.vec.as_mut_ptr().add(self.idx - self.del), + self.old_len - self.idx, + ); } + } + // SAFETY: After filling holes, all items are in contiguous memory. + unsafe { self.vec.set_len(self.old_len - self.del); } } diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 3e526813bb45..8b1b1e143b16 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -169,6 +169,15 @@ fn miri_issue_2759() { input.replace_range(0..0, "0"); } +/// This was skirting the edge of UB, let's make sure it remains on the sound side. +/// Context: . +fn extract_if() { + let mut v = vec![Box::new(0u64), Box::new(1u64)]; + for item in v.extract_if(.., |x| **x == 0) { + drop(item); + } +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -199,4 +208,5 @@ fn main() { swap_remove(); reverse(); miri_issue_2759(); + extract_if(); } From 8d7e637dc947e11fab4294ec032cfc1e252e421d Mon Sep 17 00:00:00 2001 From: sysrex <769991+sysrex@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:15:50 +0100 Subject: [PATCH 140/537] chore: remove dead links --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b52c3dfff61..2b5699dcd098 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,5 +47,4 @@ refer to [this section][contributing-bug-reports] and [open an issue][issue temp [contributing-bug-reports]: https://rustc-dev-guide.rust-lang.org/contributing.html#bug-reports [issue template]: https://github.com/rust-lang/rust/issues/new/choose [internals]: https://internals.rust-lang.org -[rust-discord]: http://discord.gg/rust-lang [rust-zulip]: https://rust-lang.zulipchat.com From e37f0fed052701f38c9b61541f565b834106ad32 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 17:32:50 +0800 Subject: [PATCH 141/537] Add regression test --- .../rustdoc-merge-no-input-finalize/rmake.rs | 22 +++++++++++++++++++ .../rustdoc-merge-no-input-finalize/sierra.rs | 1 + 2 files changed, 23 insertions(+) create mode 100644 tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs create mode 100644 tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs new file mode 100644 index 000000000000..6df9e95829d8 --- /dev/null +++ b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs @@ -0,0 +1,22 @@ +// Running --merge=finalize without an input crate root should not trigger ICE. +// Issue: https://github.com/rust-lang/rust/issues/146646 + +//@ needs-target-std + +use run_make_support::rustdoc; + +fn main() { + rustdoc() + .input("sierra.rs") + .arg("-Zunstable-options") + .arg("--parts-out-dir=parts") + .arg("--merge=none") + .run(); + + rustdoc() + .arg("-Zunstable-options") + .arg("--include-parts-dir=parts") + .arg("--merge=finalize") + .out_dir("out") + .run(); +} diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs b/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs new file mode 100644 index 000000000000..f8fc48341ed6 --- /dev/null +++ b/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs @@ -0,0 +1 @@ +pub struct Sierra; From 1c316023d65be6ae88ff938d272669bc286fd5b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Sep 2025 12:24:22 +0200 Subject: [PATCH 142/537] =?UTF-8?q?TB:=20rename=20Active=20=E2=86=92=20Uni?= =?UTF-8?q?que=20to=20match=20paper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tree_borrows/diagnostics.rs | 4 +- .../src/borrow_tracker/tree_borrows/perms.rs | 102 +++++++++--------- .../src/borrow_tracker/tree_borrows/tree.rs | 18 ++-- .../borrow_tracker/tree_borrows/tree/tests.rs | 4 +- .../fail/async-shared-mutable.tree.stderr | 2 +- .../box_noalias_violation.tree.stderr | 4 +- .../both_borrows/illegal_write6.tree.stderr | 4 +- .../arg_inplace_locals_alias.tree.stderr | 4 +- .../arg_inplace_locals_alias_ret.tree.stderr | 4 +- .../arg_inplace_mutate.tree.stderr | 4 +- .../arg_inplace_observe_during.tree.stderr | 4 +- .../return_pointer_aliasing_read.tree.stderr | 4 +- .../return_pointer_aliasing_write.tree.stderr | 4 +- ...inter_aliasing_write_tail_call.tree.stderr | 4 +- .../tree_borrows/alternate-read-write.stderr | 2 +- .../tree_borrows/fnentry_invalidation.stderr | 2 +- .../parent_read_freezes_raw_mut.stderr | 2 +- .../fail/tree_borrows/pass_invalid_mut.stderr | 2 +- .../tree_borrows/reservedim_spurious_write.rs | 3 +- .../tree_borrows/return_invalid_mut.stderr | 2 +- .../subtree_traversal_skipping_diagnostics.rs | 2 +- .../fail/tree_borrows/unique.default.stderr | 32 ------ .../pass/tree_borrows/cell-inside-box.rs | 2 +- .../pass/tree_borrows/reborrow-is-read.rs | 4 +- .../miri/tests/pass/tree_borrows/reserved.rs | 4 +- 25 files changed, 95 insertions(+), 128 deletions(-) delete mode 100644 src/tools/miri/tests/fail/tree_borrows/unique.default.stderr diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index 7b4c533cfaed..a7977cd3366f 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -244,8 +244,8 @@ pub(super) enum TransitionError { ChildAccessForbidden(Permission), /// A protector was triggered due to an invalid transition that loses /// too much permissions. - /// For example, if a protected tag goes from `Active` to `Disabled` due - /// to a foreign write this will produce a `ProtectedDisabled(Active)`. + /// For example, if a protected tag goes from `Unique` to `Disabled` due + /// to a foreign write this will produce a `ProtectedDisabled(Unique)`. /// This kind of error can only occur on foreign accesses. ProtectedDisabled(Permission), /// Cannot deallocate because some tag in the allocation is strongly protected. diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 390435e58d17..e21775c9f239 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -14,7 +14,7 @@ enum PermissionPriv { Cell, /// represents: a local mutable reference that has not yet been written to; /// allows: child reads, foreign reads; - /// affected by: child writes (becomes Active), + /// affected by: child writes (becomes Unique), /// rejects: foreign writes (Disabled). /// /// `ReservedFrz` is mostly for types that are `Freeze` (no interior mutability). @@ -31,17 +31,17 @@ enum PermissionPriv { /// This is so that the behavior of `Reserved` adheres to the rules of `noalias`: /// - foreign-read then child-write is UB due to `conflicted`, /// - child-write then foreign-read is UB since child-write will activate and then - /// foreign-read disables a protected `Active`, which is UB. + /// foreign-read disables a protected `Unique`, which is UB. ReservedFrz { conflicted: bool }, /// Alternative version of `ReservedFrz` made for types with interior mutability. /// allows: child reads, foreign reads, foreign writes (extra); - /// affected by: child writes (becomes Active); + /// affected by: child writes (becomes Unique); /// rejects: nothing. ReservedIM, /// represents: a unique pointer; /// allows: child reads, child writes; /// rejects: foreign reads (Frozen), foreign writes (Disabled). - Active, + Unique, /// represents: a shared pointer; /// allows: all read accesses; /// rejects child writes (UB), foreign writes (Disabled). @@ -56,7 +56,7 @@ use super::foreign_access_skipping::IdempotentForeignAccess; impl PartialOrd for PermissionPriv { /// PermissionPriv is ordered by the reflexive transitive closure of - /// `Reserved(conflicted=false) < Reserved(conflicted=true) < Active < Frozen < Disabled`. + /// `Reserved(conflicted=false) < Reserved(conflicted=true) < Unique < Frozen < Disabled`. /// `Reserved` that have incompatible `ty_is_freeze` are incomparable to each other. /// This ordering matches the reachability by transitions, as asserted by the exhaustive test /// `permissionpriv_partialord_is_reachability`. @@ -76,8 +76,8 @@ impl PartialOrd for PermissionPriv { (_, Disabled) => Less, (Frozen, _) => Greater, (_, Frozen) => Less, - (Active, _) => Greater, - (_, Active) => Less, + (Unique, _) => Greater, + (_, Unique) => Less, (ReservedIM, ReservedIM) => Equal, (ReservedFrz { conflicted: c1 }, ReservedFrz { conflicted: c2 }) => { // `bool` is ordered such that `false <= true`, so this works as intended. @@ -115,8 +115,8 @@ impl PermissionPriv { // Famously, ReservedIM survives foreign writes. It is never protected. ReservedIM if prot => unreachable!("Protected ReservedIM should not exist!"), ReservedIM => IdempotentForeignAccess::Write, - // Active changes on any foreign access (becomes Frozen/Disabled). - Active => IdempotentForeignAccess::None, + // Unique changes on any foreign access (becomes Frozen/Disabled). + Unique => IdempotentForeignAccess::None, // Frozen survives foreign reads, but not writes. Frozen => IdempotentForeignAccess::Read, // Disabled survives foreign reads and writes. It survives them @@ -139,12 +139,12 @@ mod transition { Disabled => return None, // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read // accesses, since the data is not being mutated. Hence the `{ .. }`. - readable @ (Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable, + readable @ (Cell | ReservedFrz { .. } | ReservedIM | Unique | Frozen) => readable, }) } /// A non-child node was read-accessed: keep `Reserved` but mark it as `conflicted` if it - /// is protected; invalidate `Active`. + /// is protected; invalidate `Unique`. fn foreign_read(state: PermissionPriv, protected: bool) -> Option { Some(match state { // Cell ignores foreign reads. @@ -167,10 +167,10 @@ mod transition { assert!(!protected); res } - Active => + Unique => if protected { // We wrote, someone else reads -- that's bad. - // (Since Active is always initialized, this move-to-protected will mean insta-UB.) + // (Since Unique is always initialized, this move-to-protected will mean insta-UB.) Disabled } else { // We don't want to disable here to allow read-read reordering: it is crucial @@ -180,7 +180,7 @@ mod transition { }) } - /// A child node was write-accessed: `Reserved` must become `Active` to obtain + /// A child node was write-accessed: `Reserved` must become `Unique` to obtain /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB. fn child_write(state: PermissionPriv, protected: bool) -> Option { Some(match state { @@ -192,7 +192,7 @@ mod transition { ReservedFrz { conflicted: true } if protected => return None, // A write always activates the 2-phase borrow, even with interior // mutability - ReservedFrz { .. } | ReservedIM | Active => Active, + ReservedFrz { .. } | ReservedIM | Unique => Unique, Frozen | Disabled => return None, }) } @@ -266,8 +266,8 @@ impl Permission { /// Default initial permission of the root of a new tree at inbounds positions. /// Must *only* be used for the root, this is not in general an "initial" permission! - pub fn new_active() -> Self { - Self { inner: Active } + pub fn new_unique() -> Self { + Self { inner: Unique } } /// Default initial permission of a reborrowed mutable reference that is either @@ -309,7 +309,7 @@ impl Permission { // Do not do perform access if it is a `Cell`, as this // can cause data races when using thread-safe data types. Cell => None, - Active => Some(AccessKind::Write), + Unique => Some(AccessKind::Write), _ => Some(AccessKind::Read), } } @@ -344,7 +344,7 @@ impl Permission { (_, Cell) => false, // ReservedIM can be replaced by anything besides Cell. // ReservedIM allows all transitions, but unlike Cell, a local write - // to ReservedIM transitions to Active, while it is a no-op for Cell. + // to ReservedIM transitions to Unique, while it is a no-op for Cell. (ReservedIM, _) => true, (_, ReservedIM) => false, // Reserved (as parent, where conflictedness does not matter) @@ -352,12 +352,12 @@ impl Permission { // since ReservedIM and Cell alone would survive foreign writes (ReservedFrz { .. }, _) => true, (_, ReservedFrz { .. }) => false, - // Active can not be replaced by something surviving + // Unique can not be replaced by something surviving // foreign reads and then remaining writable (i.e., Reserved*). // Replacing a state by itself is always okay, even if the child state is protected. - // Active can be replaced by Frozen, since it is not protected. - (Active, Active | Frozen | Disabled) => true, - (_, Active) => false, + // Unique can be replaced by Frozen, since it is not protected. + (Unique, Unique | Frozen | Disabled) => true, + (_, Unique) => false, // Frozen can only be replaced by Disabled (and itself). (Frozen, Frozen | Disabled) => true, (_, Frozen) => false, @@ -410,7 +410,7 @@ pub mod diagnostics { ReservedFrz { conflicted: false } => "Reserved", ReservedFrz { conflicted: true } => "Reserved (conflicted)", ReservedIM => "Reserved (interior mutable)", - Active => "Active", + Unique => "Unique", Frozen => "Frozen", Disabled => "Disabled", } @@ -441,7 +441,7 @@ pub mod diagnostics { ReservedFrz { conflicted: false } => "Res ", ReservedFrz { conflicted: true } => "ResC", ReservedIM => "ReIM", - Active => "Act ", + Unique => "Act ", Frozen => "Frz ", Disabled => "Dis ", } @@ -455,7 +455,7 @@ pub mod diagnostics { assert!(self.is_possible()); assert!(!self.is_noop()); match (self.from, self.to) { - (_, Active) => "the first write to a 2-phase borrowed mutable reference", + (_, Unique) => "the first write to a 2-phase borrowed mutable reference", (_, Frozen) => "a loss of write permissions", (ReservedFrz { conflicted: false }, ReservedFrz { conflicted: true }) => "a temporary loss of write permissions until function exit", @@ -472,8 +472,8 @@ pub mod diagnostics { /// /// Irrelevant events: /// - modifications of write permissions when the error is related to read permissions - /// (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Active`, - /// `Reserved(conflicted=false) -> Reserved(conflicted=true)`, and `Active -> Frozen`) + /// (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Unique`, + /// `Reserved(conflicted=false) -> Reserved(conflicted=true)`, and `Unique -> Frozen`) /// - all transitions for attempts to deallocate strongly protected tags /// /// # Panics @@ -481,10 +481,10 @@ pub mod diagnostics { /// This function assumes that its arguments apply to the same location /// and that they were obtained during a normal execution. It will panic otherwise. /// - all transitions involved in `self` and `err` should be increasing - /// (Reserved < Active < Frozen < Disabled); + /// (Reserved < Unique < Frozen < Disabled); /// - between `self` and `err` the permission should also be increasing, /// so all permissions inside `err` should be greater than `self.1`; - /// - `Active`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error + /// - `Unique`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error /// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)` /// of either of them; /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected @@ -500,11 +500,11 @@ pub mod diagnostics { TransitionError::ChildAccessForbidden(insufficient) => { // Show where the permission was gained then lost, // but ignore unrelated permissions. - // This eliminates transitions like `Active -> Frozen` + // This eliminates transitions like `Unique -> Frozen` // when the error is a failed `Read`. match (self.to, insufficient.inner) { (Frozen, Frozen) => true, - (Active, Frozen) => true, + (Unique, Frozen) => true, (Disabled, Disabled) => true, ( ReservedFrz { conflicted: true, .. }, @@ -512,14 +512,14 @@ pub mod diagnostics { ) => true, // A pointer being `Disabled` is a strictly stronger source of // errors than it being `Frozen`. If we try to access a `Disabled`, - // then where it became `Frozen` (or `Active` or `Reserved`) is the least + // then where it became `Frozen` (or `Unique` or `Reserved`) is the least // of our concerns for now. - (ReservedFrz { conflicted: true } | Active | Frozen, Disabled) => false, + (ReservedFrz { conflicted: true } | Unique | Frozen, Disabled) => false, (ReservedFrz { conflicted: true }, Frozen) => false, - // `Active`, `Reserved`, and `Cell` have all permissions, so a - // `ChildAccessForbidden(Reserved | Active)` can never exist. - (_, Active) | (_, ReservedFrz { conflicted: false }) | (_, Cell) => + // `Unique`, `Reserved`, and `Cell` have all permissions, so a + // `ChildAccessForbidden(Reserved | Unique)` can never exist. + (_, Unique) | (_, ReservedFrz { conflicted: false }) | (_, Cell) => unreachable!("this permission cannot cause an error"), // No transition has `Reserved { conflicted: false }` or `ReservedIM` // as its `.to` unless it's a noop. `Cell` cannot be in its `.to` @@ -527,11 +527,11 @@ pub mod diagnostics { (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), // All transitions produced in normal executions (using `apply_access`) - // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`. + // change permissions in the order `Reserved -> Unique -> Frozen -> Disabled`. // We assume that the error was triggered on the same location that // the transition `self` applies to, so permissions found must be increasing // in the order `self.from < self.to <= insufficient.inner` - (Active | Frozen | Disabled, ReservedFrz { .. } | ReservedIM) + (Unique | Frozen | Disabled, ReservedFrz { .. } | ReservedIM) | (Disabled, Frozen) | (ReservedFrz { .. }, ReservedIM) => unreachable!("permissions between self and err must be increasing"), @@ -540,29 +540,29 @@ pub mod diagnostics { TransitionError::ProtectedDisabled(before_disabled) => { // Show how we got to the starting point of the forbidden transition, // but ignore what came before. - // This eliminates transitions like `Reserved -> Active` + // This eliminates transitions like `Reserved -> Unique` // when the error is a `Frozen -> Disabled`. match (self.to, before_disabled.inner) { // We absolutely want to know where it was activated/frozen/marked // conflicted. - (Active, Active) => true, + (Unique, Unique) => true, (Frozen, Frozen) => true, ( ReservedFrz { conflicted: true, .. }, ReservedFrz { conflicted: true, .. }, ) => true, // If the error is a transition `Frozen -> Disabled`, then we don't really - // care whether before that was `Reserved -> Active -> Frozen` or + // care whether before that was `Reserved -> Unique -> Frozen` or // `Frozen` directly. // The error will only show either // - created as Reserved { conflicted: false }, // then Reserved { .. } -> Disabled is forbidden // - created as Reserved { conflicted: false }, - // then Active -> Disabled is forbidden + // then Unique -> Disabled is forbidden // A potential `Reserved { conflicted: false } // -> Reserved { conflicted: true }` is inexistant or irrelevant, - // and so is the `Reserved { conflicted: false } -> Active` - (Active, Frozen) => false, + // and so is the `Reserved { conflicted: false } -> Unique` + (Unique, Frozen) => false, (ReservedFrz { conflicted: true }, _) => false, (_, Disabled) => @@ -575,12 +575,12 @@ pub mod diagnostics { (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), - // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`, + // Permissions only evolve in the order `Reserved -> Unique -> Frozen -> Disabled`, // so permissions found must be increasing in the order // `self.from < self.to <= forbidden.from < forbidden.to`. - (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) - | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Active) - | (Active, Cell | ReservedFrz { .. } | ReservedIM) => + (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Unique | Frozen) + | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Unique) + | (Unique, Cell | ReservedFrz { .. } | ReservedIM) => unreachable!("permissions between self and err must be increasing"), } } @@ -617,7 +617,7 @@ mod propagation_optimization_checks { impl Exhaustive for PermissionPriv { fn exhaustive() -> Box> { Box::new( - vec![Active, Frozen, Disabled, ReservedIM, Cell] + vec![Unique, Frozen, Disabled, ReservedIM, Cell] .into_iter() .chain(::exhaustive().map(|conflicted| ReservedFrz { conflicted })), ) @@ -730,7 +730,7 @@ mod propagation_optimization_checks { #[test] // Check that all transitions are consistent with the order on PermissionPriv, - // i.e. Reserved -> Active -> Frozen -> Disabled + // i.e. Reserved -> Unique -> Frozen -> Disabled fn permissionpriv_partialord_is_reachability() { let reach = { let mut reach = rustc_data_structures::fx::FxHashSet::default(); diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 22bd63bd6b6f..9e7d272ee4b0 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -57,7 +57,7 @@ pub(super) struct LocationState { impl LocationState { /// Constructs a new initial state. It has neither been accessed, nor been subjected /// to any foreign access yet. - /// The permission is not allowed to be `Active`. + /// The permission is not allowed to be `Unique`. /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs` pub fn new_non_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self { assert!(permission.is_initial() || permission.is_disabled()); @@ -80,7 +80,7 @@ impl LocationState { /// Check if the state can exist as the initial permission of a pointer. /// /// Do not confuse with `is_accessed`, the two are almost orthogonal - /// as apart from `Active` which is not initial and must be accessed, + /// as apart from `Unique` which is not initial and must be accessed, /// any other permission can have an arbitrary combination of being /// initial/accessed. /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally @@ -170,7 +170,7 @@ impl LocationState { } if self.permission.is_frozen() && access_kind == AccessKind::Read { // A foreign read to a `Frozen` tag will have almost no observable effect. - // It's a theorem that `Frozen` nodes have no active children, so all children + // It's a theorem that `Frozen` nodes have no `Unique` children, so all children // already survive foreign reads. Foreign reads in general have almost no // effect, the only further thing they could do is make protected `Reserved` // nodes become conflicted, i.e. make them reject child writes for the further @@ -265,7 +265,7 @@ pub(super) struct Node { pub children: SmallVec<[UniIndex; 4]>, /// Either `Reserved`, `Frozen`, or `Disabled`, it is the permission this tag will /// lazily be initialized to on the first access. - /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active` by + /// It is only ever `Disabled` for a tree root, since the root is initialized to `Unique` by /// its own separate mechanism. default_initial_perm: Permission, /// The default initial (strongest) idempotent foreign access. @@ -598,14 +598,14 @@ impl Tree { }; let rperms = { let mut perms = UniValMap::default(); - // We manually set it to `Active` on all in-bounds positions. - // We also ensure that it is accessed, so that no `Active` but + // We manually set it to `Unique` on all in-bounds positions. + // We also ensure that it is accessed, so that no `Unique` but // not yet accessed nodes exist. Essentially, we pretend there - // was a write that initialized these to `Active`. + // was a write that initialized these to `Unique`. perms.insert( root_idx, LocationState::new_accessed( - Permission::new_active(), + Permission::new_unique(), IdempotentForeignAccess::None, ), ); @@ -790,7 +790,7 @@ impl<'tcx> Tree { /// - the access will be applied only to accessed locations of the allocation, /// - it will not be visible to children, /// - it will be recorded as a `FnExit` diagnostic access - /// - and it will be a read except if the location is `Active`, i.e. has been written to, + /// - and it will be a read except if the location is `Unique`, i.e. has been written to, /// in which case it will be a write. /// /// `LocationState::perform_access` will take care of raising transition diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index d9b3696e4f80..83232615616e 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -420,7 +420,7 @@ mod spurious_read { /// `(LocStateProt, LocStateProt)` where the two states are not guaranteed /// to be updated at the same time. /// Some `LocStateProtPair` may be unreachable through normal means - /// such as `x: Active, y: Active` in the case of mutually foreign pointers. + /// such as `x: Unique, y: Unique` in the case of mutually foreign pointers. struct LocStateProtPair { xy_rel: RelPosXY, x: LocStateProt, @@ -709,7 +709,7 @@ mod spurious_read { let mut err = 0; for pat in Pattern::exhaustive() { let Ok(initial_source) = pat.initial_state() else { - // Failed to retag `x` in the source (e.g. `y` was protected Active) + // Failed to retag `x` in the source (e.g. `y` was protected Unique) continue; }; // `x` must stay protected, but the function protecting `y` might return here diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index 449a29088a01..dc8b4f6665a0 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -16,7 +16,7 @@ LL | | Poll::<()>::Pending LL | | }) LL | | .await | |______________^ -help: the accessed tag later transitioned to Active due to a child write access at offsets [OFFSET] +help: the accessed tag later transitioned to Unique due to a child write access at offsets [OFFSET] --> tests/fail/async-shared-mutable.rs:LL:CC | LL | *x = 1; diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index 3c8ec7f7d3e4..6a1f7761a410 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -7,7 +7,7 @@ LL | *y = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag is foreign to the protected tag (i.e., it is not a child) - = help: this foreign read access would cause the protected tag (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe fn test(mut x: Box, y: *const i32) -> i32 { | ^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | *x = 5; diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index 6780e52c3baf..1547a6ca73a0 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { *y = 2 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag is foreign to the protected tag (i.e., it is not a child) - = help: this foreign write access would cause the protected tag (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/both_borrows/illegal_write6.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | *a = 1; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr index 2266a9c39f91..2d9ce2aa1fb6 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -7,7 +7,7 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign read access would cause the protected tag (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | y.0 = 0; | ^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | LL | y.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr index b7f514de0af9..42e391b5daf0 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr @@ -7,7 +7,7 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this reborrow (acting as a foreign read access) would cause the protected tag (currently Active) to become Disabled + = help: this reborrow (acting as a foreign read access) would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | x | ^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | LL | x diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 1995528e9f9d..74706d6b9f6b 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(S(0)) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign write access would cause the protected tag (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index e506a61c6bb3..c8c0e5c37efe 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign read access would cause the protected tag (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | x.0 = 0; | ^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | x.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index b1aa2ba28860..b43e19c3905c 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign read access would cause the protected tag (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 0cf449ea3ec2..deefb24b7850 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign write access would cause the protected tag (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index a006c6feae43..76ccf39744d9 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) - = help: this foreign write access would cause the protected tag (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag was created here, in the initial state Reserved | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr index 9e955a6d5b19..aff482abfa0c 100644 --- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr @@ -12,7 +12,7 @@ help: the accessed tag was created here, in the initial state Reserved | LL | let y = unsafe { &mut *(x as *mut u8) }; | ^^^^^^^^^^^^^^^^^^^^ -help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] +help: the accessed tag later transitioned to Unique due to a child write access at offsets [0x0..0x1] --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | *y += 1; // Success diff --git a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr index 7886029dccfc..bfd6854514e5 100644 --- a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr @@ -12,7 +12,7 @@ help: the accessed tag was created here, in the initial state Reserved | LL | let z = &mut x as *mut i32; | ^^^^^^ -help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the accessed tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | *z = 1; diff --git a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr index 2edbbd80569b..7a713abcbc45 100644 --- a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr @@ -12,7 +12,7 @@ help: the accessed tag was created here, in the initial state Reserved | LL | let mref = &mut root; | ^^^^^^^^^ -help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] +help: the accessed tag later transitioned to Unique due to a child write access at offsets [0x0..0x1] --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | *ptr = 0; // Write diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index c00c67173b7d..9a70d248aa0c 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -18,7 +18,7 @@ help: the conflicting tag was created here, in the initial state Reserved | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the conflicting tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | *xref = 18; // activate xref diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 024a14600b1b..3e5d83911ee6 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -60,8 +60,7 @@ fn main() { fn inner(x: &mut u8, b: IdxBarrier) { *x = 42; // activate immediately synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); - // A spurious write should be valid here because `x` is - // `Active` and protected. + // A spurious write should be valid here because `x` is `Unique` and protected. if cfg!(with) { synchronized!(b, "spurious write x (executed)"); *x = 64; diff --git a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr index ba8ab472872f..4b6308847bb8 100644 --- a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr @@ -18,7 +18,7 @@ help: the conflicting tag was created here, in the initial state Reserved | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ -help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x4..0x8] +help: the conflicting tag later transitioned to Unique due to a child write access at offsets [0x4..0x8] --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | *ret = *ret; // activate diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs index 6514334b09df..94a3bb805442 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs @@ -5,7 +5,7 @@ // When this method is called, the tree will be a single line and look like this, // with other_ptr being the root at the top -// other_ptr = root : Active +// other_ptr = root : Unique // intermediary : Frozen // an intermediary node // m : Reserved fn write_to_mut(m: &mut u8, other_ptr: *const u8) { diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr deleted file mode 100644 index c7d72f70f40c..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | *uniq.as_ptr() = 3; - | ^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag has state Frozen which forbids this child write access -help: the accessed tag was created here, in the initial state Reserved - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | let refmut = &mut data; - | ^^^^^^^^^ -help: the accessed tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | *uniq.as_ptr() = 1; // activation - | ^^^^^^^^^^^^^^^^^^ - = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -help: the accessed tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1] - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | let _definitely_parent = data; // definitely Frozen by now - | ^^^^ - = help: this transition corresponds to a loss of write permissions - = note: BACKTRACE (of the first span): - = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs index adf2f4e845b5..4a868455c849 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs @@ -20,7 +20,7 @@ pub fn main() { name!(ptr2); // We perform a write through `x`. - // Because `ptr1` is ReservedIM, a child write will make it transition to Active. + // Because `ptr1` is ReservedIM, a child write will make it transition to Unique. // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it. let x = (*ptr1).get(); *x = 1; diff --git a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs index 4fbccef2367d..edd649b91edd 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs @@ -6,7 +6,7 @@ mod utils; // To check that a reborrow is counted as a Read access, we use a reborrow -// with no additional Read to Freeze an Active pointer. +// with no additional Read to Freeze an Unique pointer. fn main() { unsafe { @@ -15,7 +15,7 @@ fn main() { let alloc_id = alloc_id!(parent); let x = &mut *parent; name!(x); - *x = 0; // x is now Active + *x = 0; // x is now Unique print_state!(alloc_id); let y = &mut *parent; name!(y); diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs index c57cd7fcf0ab..83e1d9c70ed5 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs @@ -68,7 +68,7 @@ unsafe fn cell_unprotected_read() { } // Foreign Write on an interior mutable pointer is a noop. -// Also y must become Active. +// Also y must become Unique. unsafe fn cell_unprotected_write() { print("[interior mut] Foreign Write: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); @@ -97,7 +97,7 @@ unsafe fn int_protected_read() { } // Foreign Read on a Reserved is a noop. -// Also y must become Active. +// Also y must become Unique. unsafe fn int_unprotected_read() { print("[] Foreign Read: Res -> Res"); let base = &mut 0u8; From bbe05dcbdf4e08ab24e179cbbaaf50c96fa0634e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 09:54:24 +0200 Subject: [PATCH 143/537] Tree::new_child: remove SIFA precondition and sync terminology --- .../tree_borrows/diagnostics.rs | 2 +- .../src/borrow_tracker/tree_borrows/mod.rs | 28 ++------ .../src/borrow_tracker/tree_borrows/tree.rs | 68 +++++++------------ .../borrow_tracker/tree_borrows/tree/tests.rs | 6 +- 4 files changed, 34 insertions(+), 70 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index a7977cd3366f..00f921b0f8af 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -504,7 +504,7 @@ impl DisplayFmt { if let Some(perm) = perm { format!( "{ac}{st}", - ac = if perm.is_accessed() { self.accessed.yes } else { self.accessed.no }, + ac = if perm.accessed() { self.accessed.yes } else { self.accessed.no }, st = perm.permission().short_name(), ) } else { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index bed65440dc9a..6e5b5c807aa2 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -294,24 +294,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); } - let span = this.machine.current_span(); - - // When adding a new node, the SIFA of its parents needs to be updated, potentially across - // the entire memory range. For the parts that are being accessed below, the access itself - // trivially takes care of that. However, we have to do some more work to also deal with the - // parts that are not being accessed. Specifically what we do is that we call - // `update_last_accessed_after_retag` on the SIFA of the permission set for the part of - // memory outside `perm_map` -- so that part is definitely taken care of. The remaining - // concern is the part of memory that is in the range of `perms_map`, but not accessed - // below. There we have two cases: - // * If the type is `!Freeze`, then the non-accessed part uses `nonfreeze_perm`, so the - // `nonfreeze_perm` initialized parts are also fine. We enforce the `freeze_perm` parts to - // be accessed via the assert below, and thus everything is taken care of. - // * If the type is `Freeze`, then `freeze_perm` is used everywhere (both inside and outside - // the initial range), and we update everything to have the `freeze_perm`'s SIFA, so there - // are no issues. (And this assert below is not actually needed in this case). - assert!(new_perm.freeze_access); - let protected = new_perm.protector.is_some(); let precise_interior_mut = this .machine @@ -337,7 +319,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { LocationState::new_non_accessed(perm, sifa) } }; - let perms_map = if !precise_interior_mut { + let inside_perms = if !precise_interior_mut { // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`. let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); let state = loc_state(ty_is_freeze); @@ -364,8 +346,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let alloc_extra = this.get_alloc_extra(alloc_id)?; let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); - for (perm_range, perm) in perms_map.iter_all() { - if perm.is_accessed() { + for (perm_range, perm) in inside_perms.iter_all() { + if perm.accessed() { // Some reborrows incur a read access to the parent. // Adjust range to be relative to allocation start (rather than to `place`). let range_in_alloc = AllocRange { @@ -401,10 +383,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { base_offset, orig_tag, new_tag, - perms_map, + inside_perms, new_perm.outside_perm, protected, - span, + this.machine.current_span(), )?; drop(tree_borrows); diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 9e7d272ee4b0..be2a07eee150 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -11,7 +11,7 @@ //! - idempotency properties asserted in `perms.rs` (for optimizations) use std::ops::Range; -use std::{fmt, mem}; +use std::{cmp, fmt, mem}; use rustc_abi::Size; use rustc_data_structures::fx::FxHashSet; @@ -73,23 +73,10 @@ impl LocationState { /// Check if the location has been accessed, i.e. if it has /// ever been accessed through a child pointer. - pub fn is_accessed(&self) -> bool { + pub fn accessed(&self) -> bool { self.accessed } - /// Check if the state can exist as the initial permission of a pointer. - /// - /// Do not confuse with `is_accessed`, the two are almost orthogonal - /// as apart from `Unique` which is not initial and must be accessed, - /// any other permission can have an arbitrary combination of being - /// initial/accessed. - /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally - /// passes and can be uncommented, remove this `#[allow(dead_code)]`. - #[cfg_attr(not(test), allow(dead_code))] - pub fn is_initial(&self) -> bool { - self.permission.is_initial() - } - pub fn permission(&self) -> Permission { self.permission } @@ -618,30 +605,26 @@ impl Tree { impl<'tcx> Tree { /// Insert a new tag in the tree. /// - /// `initial_perms` defines the initial permissions for the part of memory - /// that is already considered "initialized" immediately. The ranges in this - /// map are relative to `base_offset`. - /// `default_perm` defines the initial permission for the rest of the allocation. - /// - /// For all non-accessed locations in the RangeMap (those that haven't had an - /// implicit read), their SIFA must be weaker than or as weak as the SIFA of - /// `default_perm`. + /// `inside_perm` defines the initial permissions for a block of memory starting at + /// `base_offset`. These may nor may not be already marked as "accessed". + /// `outside_perm` defines the initial permission for the rest of the allocation. + /// These are definitely not "accessed". pub(super) fn new_child( &mut self, base_offset: Size, parent_tag: BorTag, new_tag: BorTag, - initial_perms: DedupRangeMap, - default_perm: Permission, + inside_perms: DedupRangeMap, + outside_perm: Permission, protected: bool, span: Span, ) -> InterpResult<'tcx> { let idx = self.tag_mapping.insert(new_tag); let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); - assert!(default_perm.is_initial()); + assert!(outside_perm.is_initial()); let default_strongest_idempotent = - default_perm.strongest_idempotent_foreign_access(protected); + outside_perm.strongest_idempotent_foreign_access(protected); // Create the node self.nodes.insert( idx, @@ -649,36 +632,35 @@ impl<'tcx> Tree { tag: new_tag, parent: Some(parent_idx), children: SmallVec::default(), - default_initial_perm: default_perm, + default_initial_perm: outside_perm, default_initial_idempotent_foreign_access: default_strongest_idempotent, - debug_info: NodeDebugInfo::new(new_tag, default_perm, span), + debug_info: NodeDebugInfo::new(new_tag, outside_perm, span), }, ); // Register new_tag as a child of parent_tag self.nodes.get_mut(parent_idx).unwrap().children.push(idx); + // We need to know the biggest SIFA for `update_last_accessed_after_retag` below. + let mut max_sifa = default_strongest_idempotent; for (Range { start, end }, &perm) in - initial_perms.iter(Size::from_bytes(0), initial_perms.size()) + inside_perms.iter(Size::from_bytes(0), inside_perms.size()) { - assert!(perm.is_initial()); + assert!(perm.permission.is_initial()); + max_sifa = cmp::max(max_sifa, perm.idempotent_foreign_access); for (_perms_range, perms) in self .rperms .iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start)) { - assert!( - default_strongest_idempotent - >= perm.permission.strongest_idempotent_foreign_access(protected) - ); perms.insert(idx, perm); } } - // Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`). - // We now weaken the recorded SIFA for our parents, until the invariant is restored. - // We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA - // for the new permission statically, and use that. - // See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm`. - self.update_last_accessed_after_retag(parent_idx, default_strongest_idempotent); + // Inserting the new perms might have broken the SIFA invariant (see + // `foreign_access_skipping.rs`). We now weaken the recorded SIFA for our parents, until the + // invariant is restored. We could weaken them all to `LocalAccess`, but it is more + // efficient to compute the SIFA for the new permission statically, and use that. For this + // we need the *maximum* SIFA (`Write` needs more fixup than `None`). + self.update_last_accessed_after_retag(parent_idx, max_sifa); interp_ok(()) } @@ -755,9 +737,9 @@ impl<'tcx> Tree { == Some(&ProtectorKind::StrongProtector) // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). // Related to https://github.com/rust-lang/rust/issues/55005. - && !perm.permission().is_cell() + && !perm.permission.is_cell() // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579. - && perm.is_accessed() + && perm.accessed { Err(TransitionError::ProtectedDealloc) } else { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index 83232615616e..189e48eca724 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -106,7 +106,7 @@ fn tree_compacting_is_sound() { as_foreign_or_child(rel), kind, parent.permission(), - as_lazy_or_accessed(child.is_accessed()), + as_lazy_or_accessed(child.accessed()), child.permission(), as_protected(child_protected), np.permission(), @@ -122,7 +122,7 @@ fn tree_compacting_is_sound() { as_foreign_or_child(rel), kind, parent.permission(), - as_lazy_or_accessed(child.is_accessed()), + as_lazy_or_accessed(child.accessed()), child.permission(), as_protected(child_protected), nc.permission() @@ -375,7 +375,7 @@ mod spurious_read { impl LocStateProt { fn is_initial(&self) -> bool { - self.state.is_initial() + self.state.permission().is_initial() } fn perform_access(&self, kind: AccessKind, rel: AccessRelatedness) -> Result { From ba2537b6ffdbd9979874ca029e5bd86c6b925b37 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 18:09:10 +0800 Subject: [PATCH 144/537] add exit code check --- .../rustdoc-merge-no-input-finalize/rmake.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs index 6df9e95829d8..4ead8c2e56c5 100644 --- a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs +++ b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs @@ -3,20 +3,26 @@ //@ needs-target-std -use run_make_support::rustdoc; +use run_make_support::{path, rustdoc}; fn main() { + let out_dir = path("out"); + let merged_dir = path("merged"); + let parts_out_dir = path("parts"); rustdoc() .input("sierra.rs") + .out_dir(&out_dir) .arg("-Zunstable-options") - .arg("--parts-out-dir=parts") + .arg(format!("--parts-out-dir={}", parts_out_dir.display())) .arg("--merge=none") .run(); - rustdoc() + let output = rustdoc() .arg("-Zunstable-options") - .arg("--include-parts-dir=parts") + .out_dir(&out_dir) + .arg(format!("--include-parts-dir={}", parts_out_dir.display())) .arg("--merge=finalize") - .out_dir("out") .run(); + + output.assert_exit_code(0); } From 06819d95c0697c6a2f8f1498a22260f47c210bd7 Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Tue, 2 Sep 2025 16:13:51 +0100 Subject: [PATCH 145/537] Extends branch protection tests to include GCS --- tests/assembly-llvm/aarch64-pointer-auth.rs | 6 +++++- tests/codegen-llvm/branch-protection.rs | 6 +++++- .../pointer-auth-link-with-c-lto-clang/rmake.rs | 8 +++++--- tests/run-make/pointer-auth-link-with-c/rmake.rs | 10 ++++++---- .../branch-protection-missing-pac-ret.BADFLAGS.stderr | 2 +- ...branch-protection-missing-pac-ret.BADFLAGSPC.stderr | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/assembly-llvm/aarch64-pointer-auth.rs b/tests/assembly-llvm/aarch64-pointer-auth.rs index 56a26df469f3..e1ca6d775813 100644 --- a/tests/assembly-llvm/aarch64-pointer-auth.rs +++ b/tests/assembly-llvm/aarch64-pointer-auth.rs @@ -1,10 +1,13 @@ // Test that PAC instructions are emitted when branch-protection is specified. //@ add-core-stubs -//@ revisions: PACRET PAUTHLR_NOP PAUTHLR +//@ revisions: GCS PACRET PAUTHLR_NOP PAUTHLR //@ assembly-output: emit-asm //@ needs-llvm-components: aarch64 //@ compile-flags: --target aarch64-unknown-linux-gnu +//@ [GCS] min-llvm-version: 21 +//@ [GCS] ignore-apple (XCode version needs updating) +//@ [GCS] compile-flags: -Z branch-protection=gcs //@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf //@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf //@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf @@ -17,6 +20,7 @@ extern crate minicore; use minicore::*; +// GCS: .aeabi_attribute 2, 1 // Tag_Feature_GCS // PACRET: hint #25 // PACRET: hint #29 // PAUTHLR_NOP: hint #25 diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs index d67e494cc0d6..f92259c941ce 100644 --- a/tests/codegen-llvm/branch-protection.rs +++ b/tests/codegen-llvm/branch-protection.rs @@ -1,9 +1,10 @@ // Test that the correct module flags are emitted with different branch protection flags. //@ add-core-stubs -//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE +//@ revisions: BTI GCS PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE //@ needs-llvm-components: aarch64 //@ [BTI] compile-flags: -Z branch-protection=bti +//@ [GCS] compile-flags: -Z branch-protection=gcs //@ [PACRET] compile-flags: -Z branch-protection=pac-ret //@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf //@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key @@ -32,6 +33,9 @@ pub fn test() {} // BTI: !"sign-return-address-all", i32 0 // BTI: !"sign-return-address-with-bkey", i32 0 +// GCS: attributes [[ATTR]] = {{.*}} "guarded-control-stack" +// GCS: !"guarded-control-stack", i32 1 + // PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf" // PACRET-SAME: "sign-return-address-key"="a_key" // PACRET: !"branch-target-enforcement", i32 0 diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs index 0a2186b09538..2ac5fdee063c 100644 --- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -1,12 +1,14 @@ // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication // code (PAC), a useful hashing measure for verifying that pointers have not been modified. // This test checks that compilation and execution is successful when this feature is activated, -// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO. +// with some of its possible extra arguments (bti, gcs, pac-ret, leaf) when doing LTO. // See https://github.com/rust-lang/rust/pull/88354 //@ needs-force-clang-based-tests //@ only-aarch64 // Reason: branch protection is not supported on other architectures +//@ ignore-apple +// Reason: XCode needs updating to support gcs //@ ignore-cross-compile // Reason: the compiled binary is executed @@ -19,7 +21,7 @@ fn main() { clang() .arg("-v") .lto("thin") - .arg("-mbranch-protection=bti+pac-ret+b-key+leaf") + .arg("-mbranch-protection=bti+gcs+pac-ret+b-key+leaf") .arg("-c") .out_exe("test.o") .input("test.c") @@ -30,7 +32,7 @@ fn main() { .opt_level("2") .linker(&env_var("CLANG")) .link_arg("-fuse-ld=lld") - .arg("-Zbranch-protection=bti,pac-ret,leaf") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") .input("test.rs") .output("test.bin") .run(); diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs index a4d7454e5755..1ddcb79d64ff 100644 --- a/tests/run-make/pointer-auth-link-with-c/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs @@ -1,11 +1,13 @@ // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication // code (PAC), a useful hashing measure for verifying that pointers have not been modified. // This test checks that compilation and execution is successful when this feature is activated, -// with some of its possible extra arguments (bti, pac-ret, pc, leaf, b-key). +// with some of its possible extra arguments (bti, gcs, pac-ret, pc, leaf, b-key). // See https://github.com/rust-lang/rust/pull/88354 //@ only-aarch64 // Reason: branch protection is not supported on other architectures +//@ ignore-apple +// Reason: XCode needs updating to support gcs //@ ignore-cross-compile // Reason: the compiled binary is executed @@ -13,17 +15,17 @@ use run_make_support::{build_native_static_lib, cc, is_windows_msvc, llvm_ar, ru fn main() { build_native_static_lib("test"); - rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run(); + rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); run("test"); cc().arg("-v") .arg("-c") .out_exe("test") .input("test.c") - .arg("-mbranch-protection=bti+pac-ret+leaf") + .arg("-mbranch-protection=bti+gcs+pac-ret+leaf") .run(); let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run(); + rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); run("test"); // FIXME: +pc was only recently added to LLVM diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr index dae08119dbc6..277111a41f29 100644 --- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr +++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr @@ -1,2 +1,2 @@ -error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected +error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr index 13f79e94674b..e1ade01d2fe7 100644 --- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr +++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr @@ -1,2 +1,2 @@ -error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected +error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected From 870a98c7b3bec5e0ec3432a4900d2bb6f0e1cc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 22 Sep 2025 14:14:48 +0200 Subject: [PATCH 146/537] Fix modification check of `rustdoc-json-types` --- src/tools/tidy/src/rustdoc_json.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index 7a53c08737f6..ade774616c71 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -17,11 +17,13 @@ pub fn check(src_path: &Path, ci_info: &crate::CiInfo, diag_ctx: DiagCtx) { }; // First we check that `src/rustdoc-json-types` was modified. - if !crate::files_modified(ci_info, |p| p == RUSTDOC_JSON_TYPES) { + if !crate::files_modified(ci_info, |p| p.starts_with(RUSTDOC_JSON_TYPES)) { // `rustdoc-json-types` was not modified so nothing more to check here. - check.verbose_msg("`rustdoc-json-types` was not modified."); return; } + + check.message("`rustdoc-json-types` modified, checking format version"); + // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated. match crate::git_diff(base_commit, src_path.join("rustdoc-json-types")) { Some(output) => { From 6adbb3a18972c1e4c24ac8a2766a0a5fc699f900 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Sep 2025 18:06:07 +0530 Subject: [PATCH 147/537] remove explicit target assignment in config during rustc initialization --- src/bootstrap/src/core/builder/tests.rs | 19 +++++++------------ src/bootstrap/src/core/config/config.rs | 4 +--- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 0bb22eccd193..f838149977d0 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -22,13 +22,7 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { } fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config { - TestCtx::new() - .config(cmd[0]) - .args(&cmd[1..]) - .hosts(host) - .targets(target) - .args(&["--build", TEST_TRIPLE_1]) - .create_config() + TestCtx::new().config(cmd[0]).args(&cmd[1..]).hosts(host).targets(target).create_config() } fn first(v: Vec<(A, B)>) -> Vec { @@ -236,6 +230,7 @@ mod dist { use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build}; use crate::Flags; + use crate::core::builder::tests::host_target; use crate::core::builder::*; fn configure(host: &[&str], target: &[&str]) -> Config { @@ -244,11 +239,11 @@ mod dist { #[test] fn llvm_out_behaviour() { - let mut config = configure(&[TEST_TRIPLE_1], &[TEST_TRIPLE_2]); + let mut config = configure(&[], &[TEST_TRIPLE_2]); config.llvm_from_ci = true; let build = Build::new(config.clone()); - let target = TargetSelection::from_user(TEST_TRIPLE_1); + let target = TargetSelection::from_user(&host_target()); assert!(build.llvm_out(target).ends_with("ci-llvm")); let target = TargetSelection::from_user(TEST_TRIPLE_2); assert!(build.llvm_out(target).ends_with("llvm")); @@ -313,14 +308,14 @@ mod sysroot_target_dirs { /// cg_gcc tests instead. #[test] fn test_test_compiler() { - let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); + let config = configure_with_args(&["test", "compiler"], &[], &[TEST_TRIPLE_1]); let cache = run_build(&config.paths.clone(), config); let compiler = cache.contains::(); let cranelift = cache.contains::(); let gcc = cache.contains::(); - assert_eq!((compiler, cranelift, gcc), (true, false, false)); + assert_eq!((compiler, cranelift, gcc), (false, false, false)); } #[test] @@ -346,7 +341,7 @@ fn test_test_coverage() { // Print each test case so that if one fails, the most recently printed // case is the one that failed. println!("Testing case: {cmd:?}"); - let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); + let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]); let mut cache = run_build(&config.paths.clone(), config); let modes = diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1f3b90d324fb..957de5367ef6 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -688,9 +688,7 @@ impl Config { let initial_rustc = build_rustc.unwrap_or_else(|| { download_beta_toolchain(&dwn_ctx, &out); - let target = if cfg!(test) { get_host_target() } else { host_target }; - - out.join(target).join("stage0").join("bin").join(exe("rustc", host_target)) + out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) }); let initial_sysroot = t!(PathBuf::from_str( From 42ebba214b3c570761dc99f5fc1517ad092778ac Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 20:36:18 +0800 Subject: [PATCH 148/537] address review comments --- tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs index 4ead8c2e56c5..0b1e1948d5fc 100644 --- a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs +++ b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs @@ -16,6 +16,7 @@ fn main() { .arg(format!("--parts-out-dir={}", parts_out_dir.display())) .arg("--merge=none") .run(); + assert!(parts_out_dir.join("crate-info").exists()); let output = rustdoc() .arg("-Zunstable-options") @@ -23,6 +24,5 @@ fn main() { .arg(format!("--include-parts-dir={}", parts_out_dir.display())) .arg("--merge=finalize") .run(); - - output.assert_exit_code(0); + output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug."); } From a25896bc2785b234c8b093a25b7f7df34798aea8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 14:34:34 +0200 Subject: [PATCH 149/537] share check_all_outcomes impl, and increase max iteration counts --- .../miri/tests/pass/0weak_memory/weak.rs | 33 ++--------------- src/tools/miri/tests/pass/float_nan.rs | 37 +++---------------- src/tools/miri/tests/utils/mod.rs | 35 ++++++++++++++++++ 3 files changed, 45 insertions(+), 60 deletions(-) diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index c752fc114ba5..611733d0dac5 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -13,6 +13,10 @@ use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicUsize, fence}; use std::thread::spawn; +#[path = "../../utils/mod.rs"] +mod utils; +use utils::check_all_outcomes; + #[allow(dead_code)] #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -33,35 +37,6 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize { val } -/// Check that the function produces the intended set of outcomes. -#[track_caller] -fn check_all_outcomes( - expected: impl IntoIterator, - generate: impl Fn() -> T, -) { - use std::collections::HashSet; - - let expected: HashSet = HashSet::from_iter(expected); - let mut seen = HashSet::new(); - // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 16; - for i in 0..tries { - let val = generate(); - assert!(expected.contains(&val), "got an unexpected value: {val:?}"); - seen.insert(val); - if i > tries / 2 && expected.len() == seen.len() { - // We saw everything and we did quite a few tries, let's avoid wasting time. - return; - } - } - // Let's see if we saw them all. - for val in expected { - if !seen.contains(&val) { - panic!("did not get value that should be possible: {val:?}"); - } - } -} - fn relaxed() { check_all_outcomes([0, 1, 2], || { let x = static_atomic(0); diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 902816307403..c07ffdf9740c 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -5,6 +5,10 @@ use std::fmt; use std::hint::black_box; +#[path = "../utils/mod.rs"] +mod utils; +use utils::check_all_outcomes; + fn ldexp(a: f64, b: i32) -> f64 { extern "C" { fn ldexp(x: f64, n: i32) -> f64; @@ -26,35 +30,6 @@ enum NaNKind { } use NaNKind::*; -/// Check that the function produces the intended set of outcomes. -#[track_caller] -fn check_all_outcomes( - expected: impl IntoIterator, - generate: impl Fn() -> T, -) { - use std::collections::HashSet; - - let expected: HashSet = HashSet::from_iter(expected); - let mut seen = HashSet::new(); - // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 12; - for i in 0..tries { - let val = generate(); - assert!(expected.contains(&val), "got an unexpected value: {val}"); - seen.insert(val); - if i > tries / 2 && expected.len() == seen.len() { - // We saw everything and we did quite a few tries, let's avoid wasting time. - return; - } - } - // Let's see if we saw them all. - for val in expected { - if !seen.contains(&val) { - panic!("did not get value that should be possible: {val}"); - } - } -} - // -- f32 support #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq, Hash)] @@ -81,7 +56,7 @@ const F32_EXP: u32 = 8; // 8 bits of exponent const F32_MANTISSA: u32 = F32_SIGN_BIT - F32_EXP; const F32_NAN_PAYLOAD: u32 = F32_MANTISSA - 1; -impl fmt::Display for F32 { +impl fmt::Debug for F32 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Alaways show raw bits. write!(f, "0x{:08x} ", self.0)?; @@ -154,7 +129,7 @@ const F64_EXP: u32 = 11; // 11 bits of exponent const F64_MANTISSA: u32 = F64_SIGN_BIT - F64_EXP; const F64_NAN_PAYLOAD: u32 = F64_MANTISSA - 1; -impl fmt::Display for F64 { +impl fmt::Debug for F64 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Alaways show raw bits. write!(f, "0x{:08x} ", self.0)?; diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs index 138ada4e20d7..459fea404ea3 100644 --- a/src/tools/miri/tests/utils/mod.rs +++ b/src/tools/miri/tests/utils/mod.rs @@ -16,3 +16,38 @@ pub fn run_provenance_gc() { // SAFETY: No preconditions. The GC is fine to run at any time. unsafe { miri_run_provenance_gc() } } + +/// Check that the function produces the intended set of outcomes. +#[track_caller] +pub fn check_all_outcomes( + expected: impl IntoIterator, + generate: impl Fn() -> T, +) { + use std::collections::HashSet; + + let expected: HashSet = HashSet::from_iter(expected); + let mut seen = HashSet::new(); + // Let's give it N times as many tries as we are expecting values. + let min_tries = std::cmp::max(20, expected.len() * 4); + let max_tries = expected.len() * 50; + for i in 0..max_tries { + let val = generate(); + assert!(expected.contains(&val), "got an unexpected value: {val:?}"); + seen.insert(val); + if i >= min_tries && expected.len() == seen.len() { + // We saw everything and we did enough tries, let's avoid wasting time. + return; + } + } + // Let's see if we saw them all. + if expected.len() == seen.len() { + return; + } + // Find the missing one. + for val in expected { + if !seen.contains(&val) { + panic!("did not get value that should be possible: {val:?}"); + } + } + unreachable!() +} From 37de09fed92a2814d93faff6e789c34d2a18718e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 14:49:13 +0200 Subject: [PATCH 150/537] share the check_nondet helper as well --- src/tools/miri/tests/pass/float.rs | 194 ++++++++---------- .../intrinsics/fmuladd_nondeterministic.rs | 103 ++++------ src/tools/miri/tests/utils/mod.rs | 15 ++ 3 files changed, 138 insertions(+), 174 deletions(-) diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 3ce5ea8356bd..8570addeedd2 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -8,12 +8,16 @@ #![allow(internal_features)] #![allow(unnecessary_transmutes)] +#[path = "../utils/mod.rs"] +mod utils; use std::any::type_name; use std::cmp::min; use std::fmt::{Debug, Display, LowerHex}; use std::hint::black_box; use std::{f32, f64}; +use utils::check_nondet; + /// Compare the two floats, allowing for $ulp many ULPs of error. /// /// ULP means "Units in the Last Place" or "Units of Least Precision". @@ -1429,29 +1433,14 @@ fn test_fmuladd() { /// `min` and `max` on equal arguments are non-deterministic. fn test_min_max_nondet() { - /// Ensure that if we call the closure often enough, we see both `true` and `false.` - #[track_caller] - fn ensure_both(f: impl Fn() -> bool) { - let rounds = 32; - let first = f(); - for _ in 1..rounds { - if f() != first { - // We saw two different values! - return; - } - } - // We saw the same thing N times. - panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); - } - - ensure_both(|| f16::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f16::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f32::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f32::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f64::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f64::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f128::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f128::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f16::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f16::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::max(0.0, -0.0).is_sign_positive()); } fn test_non_determinism() { @@ -1461,35 +1450,20 @@ fn test_non_determinism() { }; use std::{f32, f64}; - /// Ensure that the operation is non-deterministic - #[track_caller] - fn ensure_nondet(f: impl Fn() -> T) { - let rounds = 16; - let first = f(); - for _ in 1..rounds { - if f() != first { - // We saw two different values! - return; - } - } - // We saw the same thing N times. - panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); - } - macro_rules! test_operations_f { ($a:expr, $b:expr) => { - ensure_nondet(|| fadd_algebraic($a, $b)); - ensure_nondet(|| fsub_algebraic($a, $b)); - ensure_nondet(|| fmul_algebraic($a, $b)); - ensure_nondet(|| fdiv_algebraic($a, $b)); - ensure_nondet(|| frem_algebraic($a, $b)); + check_nondet(|| fadd_algebraic($a, $b)); + check_nondet(|| fsub_algebraic($a, $b)); + check_nondet(|| fmul_algebraic($a, $b)); + check_nondet(|| fdiv_algebraic($a, $b)); + check_nondet(|| frem_algebraic($a, $b)); unsafe { - ensure_nondet(|| fadd_fast($a, $b)); - ensure_nondet(|| fsub_fast($a, $b)); - ensure_nondet(|| fmul_fast($a, $b)); - ensure_nondet(|| fdiv_fast($a, $b)); - ensure_nondet(|| frem_fast($a, $b)); + check_nondet(|| fadd_fast($a, $b)); + check_nondet(|| fsub_fast($a, $b)); + check_nondet(|| fmul_fast($a, $b)); + check_nondet(|| fdiv_fast($a, $b)); + check_nondet(|| frem_fast($a, $b)); } }; } @@ -1499,70 +1473,70 @@ fn test_non_determinism() { } pub fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); - ensure_nondet(|| a.powf(b)); - ensure_nondet(|| a.powi(2)); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 10f32.exp2()); - ensure_nondet(|| f32::consts::E.ln()); - ensure_nondet(|| 10f32.log10()); - ensure_nondet(|| 8f32.log2()); - ensure_nondet(|| 1f32.ln_1p()); - ensure_nondet(|| 27.0f32.cbrt()); - ensure_nondet(|| 3.0f32.hypot(4.0f32)); - ensure_nondet(|| 1f32.sin()); - ensure_nondet(|| 1f32.cos()); + check_nondet(|| a.powf(b)); + check_nondet(|| a.powi(2)); + check_nondet(|| a.log(b)); + check_nondet(|| a.exp()); + check_nondet(|| 10f32.exp2()); + check_nondet(|| f32::consts::E.ln()); + check_nondet(|| 10f32.log10()); + check_nondet(|| 8f32.log2()); + check_nondet(|| 1f32.ln_1p()); + check_nondet(|| 27.0f32.cbrt()); + check_nondet(|| 3.0f32.hypot(4.0f32)); + check_nondet(|| 1f32.sin()); + check_nondet(|| 1f32.cos()); // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, // which means the little rounding errors Miri introduces are discarded by the cast down to // `f32`. Just skip the test for them. if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { - ensure_nondet(|| 1.0f32.tan()); - ensure_nondet(|| 1.0f32.asin()); - ensure_nondet(|| 5.0f32.acos()); - ensure_nondet(|| 1.0f32.atan()); - ensure_nondet(|| 1.0f32.atan2(2.0f32)); - ensure_nondet(|| 1.0f32.sinh()); - ensure_nondet(|| 1.0f32.cosh()); - ensure_nondet(|| 1.0f32.tanh()); + check_nondet(|| 1.0f32.tan()); + check_nondet(|| 1.0f32.asin()); + check_nondet(|| 5.0f32.acos()); + check_nondet(|| 1.0f32.atan()); + check_nondet(|| 1.0f32.atan2(2.0f32)); + check_nondet(|| 1.0f32.sinh()); + check_nondet(|| 1.0f32.cosh()); + check_nondet(|| 1.0f32.tanh()); } - ensure_nondet(|| 1.0f32.asinh()); - ensure_nondet(|| 2.0f32.acosh()); - ensure_nondet(|| 0.5f32.atanh()); - ensure_nondet(|| 5.0f32.gamma()); - ensure_nondet(|| 5.0f32.ln_gamma()); - ensure_nondet(|| 5.0f32.erf()); - ensure_nondet(|| 5.0f32.erfc()); + check_nondet(|| 1.0f32.asinh()); + check_nondet(|| 2.0f32.acosh()); + check_nondet(|| 0.5f32.atanh()); + check_nondet(|| 5.0f32.gamma()); + check_nondet(|| 5.0f32.ln_gamma()); + check_nondet(|| 5.0f32.erf()); + check_nondet(|| 5.0f32.erfc()); } pub fn test_operations_f64(a: f64, b: f64) { test_operations_f!(a, b); - ensure_nondet(|| a.powf(b)); - ensure_nondet(|| a.powi(2)); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 50f64.exp2()); - ensure_nondet(|| 3f64.ln()); - ensure_nondet(|| f64::consts::E.log10()); - ensure_nondet(|| f64::consts::E.log2()); - ensure_nondet(|| 1f64.ln_1p()); - ensure_nondet(|| 27.0f64.cbrt()); - ensure_nondet(|| 3.0f64.hypot(4.0f64)); - ensure_nondet(|| 1f64.sin()); - ensure_nondet(|| 1f64.cos()); - ensure_nondet(|| 1.0f64.tan()); - ensure_nondet(|| 1.0f64.asin()); - ensure_nondet(|| 5.0f64.acos()); - ensure_nondet(|| 1.0f64.atan()); - ensure_nondet(|| 1.0f64.atan2(2.0f64)); - ensure_nondet(|| 1.0f64.sinh()); - ensure_nondet(|| 1.0f64.cosh()); - ensure_nondet(|| 1.0f64.tanh()); - ensure_nondet(|| 1.0f64.asinh()); - ensure_nondet(|| 3.0f64.acosh()); - ensure_nondet(|| 0.5f64.atanh()); - ensure_nondet(|| 5.0f64.gamma()); - ensure_nondet(|| 5.0f64.ln_gamma()); - ensure_nondet(|| 5.0f64.erf()); - ensure_nondet(|| 5.0f64.erfc()); + check_nondet(|| a.powf(b)); + check_nondet(|| a.powi(2)); + check_nondet(|| a.log(b)); + check_nondet(|| a.exp()); + check_nondet(|| 50f64.exp2()); + check_nondet(|| 3f64.ln()); + check_nondet(|| f64::consts::E.log10()); + check_nondet(|| f64::consts::E.log2()); + check_nondet(|| 1f64.ln_1p()); + check_nondet(|| 27.0f64.cbrt()); + check_nondet(|| 3.0f64.hypot(4.0f64)); + check_nondet(|| 1f64.sin()); + check_nondet(|| 1f64.cos()); + check_nondet(|| 1.0f64.tan()); + check_nondet(|| 1.0f64.asin()); + check_nondet(|| 5.0f64.acos()); + check_nondet(|| 1.0f64.atan()); + check_nondet(|| 1.0f64.atan2(2.0f64)); + check_nondet(|| 1.0f64.sinh()); + check_nondet(|| 1.0f64.cosh()); + check_nondet(|| 1.0f64.tanh()); + check_nondet(|| 1.0f64.asinh()); + check_nondet(|| 3.0f64.acosh()); + check_nondet(|| 0.5f64.atanh()); + check_nondet(|| 5.0f64.gamma()); + check_nondet(|| 5.0f64.ln_gamma()); + check_nondet(|| 5.0f64.erf()); + check_nondet(|| 5.0f64.erfc()); } pub fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); @@ -1574,15 +1548,15 @@ fn test_non_determinism() { test_operations_f128(25., 18.); // SNaN^0 = (1 | NaN) - ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); - ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); + check_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); + check_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); // 1^SNaN = (1 | NaN) - ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); - ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); + check_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); + check_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); // same as powf (keep it consistent): // x^SNaN = (1 | NaN) - ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); - ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); + check_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); + check_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); } diff --git a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs index b688405c4b18..401b2911f809 100644 --- a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs +++ b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs @@ -3,73 +3,48 @@ use std::intrinsics::simd::simd_relaxed_fma; use std::intrinsics::{fmuladdf32, fmuladdf64}; use std::simd::prelude::*; -fn ensure_both_happen(f: impl Fn() -> bool) -> bool { - let mut saw_true = false; - let mut saw_false = false; - for _ in 0..50 { - let b = f(); - if b { - saw_true = true; - } else { - saw_false = true; - } - if saw_true && saw_false { - return true; - } - } - false -} +#[path = "../../utils/mod.rs"] +mod utils; +use utils::check_nondet; fn main() { - assert!( - ensure_both_happen(|| { - let a = std::hint::black_box(0.1_f64); - let b = std::hint::black_box(0.2); - let c = std::hint::black_box(-a * b); - // It is unspecified whether the following operation is fused or not. The - // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. - let x = unsafe { fmuladdf64(a, b, c) }; - x == 0.0 - }), - "`fmuladdf64` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = std::hint::black_box(0.1_f64); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. + let x = unsafe { fmuladdf64(a, b, c) }; + x == 0.0 + }); - assert!( - ensure_both_happen(|| { - let a = std::hint::black_box(0.1_f32); - let b = std::hint::black_box(0.2); - let c = std::hint::black_box(-a * b); - // It is unspecified whether the following operation is fused or not. The - // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. - let x = unsafe { fmuladdf32(a, b, c) }; - x == 0.0 - }), - "`fmuladdf32` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = std::hint::black_box(0.1_f32); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. + let x = unsafe { fmuladdf32(a, b, c) }; + x == 0.0 + }); - assert!( - ensure_both_happen(|| { - let a = f32x4::splat(std::hint::black_box(0.1)); - let b = f32x4::splat(std::hint::black_box(0.2)); - let c = std::hint::black_box(-a * b); - let x = unsafe { simd_relaxed_fma(a, b, c) }; - // Whether we fuse or not is a per-element decision, so sometimes these should be - // the same and sometimes not. - x[0] == x[1] - }), - "`simd_relaxed_fma` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = f32x4::splat(std::hint::black_box(0.1)); + let b = f32x4::splat(std::hint::black_box(0.2)); + let c = std::hint::black_box(-a * b); + let x = unsafe { simd_relaxed_fma(a, b, c) }; + // Whether we fuse or not is a per-element decision, so sometimes these should be + // the same and sometimes not. + x[0] == x[1] + }); - assert!( - ensure_both_happen(|| { - let a = f64x4::splat(std::hint::black_box(0.1)); - let b = f64x4::splat(std::hint::black_box(0.2)); - let c = std::hint::black_box(-a * b); - let x = unsafe { simd_relaxed_fma(a, b, c) }; - // Whether we fuse or not is a per-element decision, so sometimes these should be - // the same and sometimes not. - x[0] == x[1] - }), - "`simd_relaxed_fma` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = f64x4::splat(std::hint::black_box(0.1)); + let b = f64x4::splat(std::hint::black_box(0.2)); + let c = std::hint::black_box(-a * b); + let x = unsafe { simd_relaxed_fma(a, b, c) }; + // Whether we fuse or not is a per-element decision, so sometimes these should be + // the same and sometimes not. + x[0] == x[1] + }); } diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs index 459fea404ea3..37f999621634 100644 --- a/src/tools/miri/tests/utils/mod.rs +++ b/src/tools/miri/tests/utils/mod.rs @@ -51,3 +51,18 @@ pub fn check_all_outcomes( } unreachable!() } + +/// Check that the operation is non-deterministic +#[track_caller] +pub fn check_nondet(f: impl Fn() -> T) { + let rounds = 50; + let first = f(); + for _ in 1..rounds { + if f() != first { + // We saw two different values! + return; + } + } + // We saw the same thing N times. + panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); +} From 823337a4ade5e559d485904b685e8f2cef4a3a2c Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 22 Sep 2025 22:15:25 +0900 Subject: [PATCH 151/537] Remove unused #![feature(get_mut_unchecked)] in Rc and Arc examples --- library/alloc/src/rc.rs | 9 --------- library/alloc/src/sync.rs | 9 --------- 2 files changed, 18 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fcb466778a3f..aed3357afbf4 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -480,8 +480,6 @@ impl Rc { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::rc::Rc; /// /// let mut five = Rc::::new_uninit(); @@ -572,7 +570,6 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] /// /// use std::rc::Rc; /// @@ -1014,8 +1011,6 @@ impl Rc<[T]> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::rc::Rc; /// /// let mut values = Rc::<[u32]>::new_uninit_slice(3); @@ -1181,8 +1176,6 @@ impl Rc, A> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::rc::Rc; /// /// let mut five = Rc::::new_uninit(); @@ -1218,8 +1211,6 @@ impl Rc<[mem::MaybeUninit], A> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::rc::Rc; /// /// let mut values = Rc::<[u32]>::new_uninit_slice(3); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 32396cccb8fc..a466b74944c5 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -480,8 +480,6 @@ impl Arc { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::sync::Arc; /// /// let mut five = Arc::::new_uninit(); @@ -586,7 +584,6 @@ impl Arc { /// /// ``` /// #![feature(allocator_api)] - /// #![feature(get_mut_unchecked)] /// /// use std::sync::Arc; /// @@ -1156,8 +1153,6 @@ impl Arc<[T]> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::sync::Arc; /// /// let mut values = Arc::<[u32]>::new_uninit_slice(3); @@ -1326,8 +1321,6 @@ impl Arc, A> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::sync::Arc; /// /// let mut five = Arc::::new_uninit(); @@ -1364,8 +1357,6 @@ impl Arc<[mem::MaybeUninit], A> { /// # Examples /// /// ``` - /// #![feature(get_mut_unchecked)] - /// /// use std::sync::Arc; /// /// let mut values = Arc::<[u32]>::new_uninit_slice(3); From 8a0e3808c04c16732c4651884c2a28063f4eec43 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Sep 2025 18:46:18 +0530 Subject: [PATCH 152/537] add check for toml file --- src/bootstrap/src/core/config/tests.rs | 13 +++---------- src/bootstrap/src/core/config/toml/mod.rs | 6 ++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index f277e3704f27..3390e9586a4c 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -307,10 +307,11 @@ fn clippy_rule_separate_prefix() { #[test] fn verbose_tests_default_value() { - let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()])); + let config = TestCtx::new().config("build").args(&["compiler".into()]).create_config(); assert_eq!(config.verbose_tests, false); - let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()])); + let config = + TestCtx::new().config("build").args(&["compiler".into(), "-v".into()]).create_config(); assert_eq!(config.verbose_tests, true); } @@ -643,18 +644,10 @@ fn test_include_precedence_over_profile() { "#; File::create(extension).unwrap().write_all(extension_content).unwrap(); - let root_config = testdir.join("config.toml"); - let root_config_content = br#" - profile = "dist" - include = ["./extension.toml"] - "#; - File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); - let config = test_ctx .config("check") .with_default_toml_config( r#" - profile = "dist" include = ["./extension.toml"] "#, ) diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs index f6dc5b67e101..5f86d2e72818 100644 --- a/src/bootstrap/src/core/config/toml/mod.rs +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -152,6 +152,12 @@ impl Config { } pub(crate) fn get_toml(file: &Path) -> Result { + #[cfg(test)] + { + let tmp = std::env::temp_dir(); + assert!(file.starts_with(&tmp), "Expected path in temp dir {:?}, got {:?}", tmp, file); + } + Self::get_toml_inner(file) } From 83b784fda12a3422bfa7ce14c1bbd9864df70e5e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Sep 2025 18:54:23 +0530 Subject: [PATCH 153/537] add comment explaining the test_build_dir --- src/bootstrap/src/core/config/config.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 957de5367ef6..280ae088f3f3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2479,6 +2479,13 @@ fn find_correct_section_for_field(field_name: &str) -> Vec { .collect() } +/// Resolve the build directory used for tests. +/// +/// - When tests are run through bootstrap (`x.py test`), the build system +/// sets `CARGO_TARGET_DIR`, so we can trust and use it here. +/// - When tests are run directly with cargo test, `CARGO_TARGET_DIR` will +/// not be set. In that case we fall back to resolving relative to +/// `CARGO_MANIFEST_DIR`, by walking two parents up and appending `build`. fn test_build_dir() -> PathBuf { env::var_os("CARGO_TARGET_DIR") .map(|value| Path::new(&value).parent().unwrap().to_path_buf()) From a45d58bcb55f3639f07721ca3032d5bec1b0443f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 22 Sep 2025 16:53:20 +0300 Subject: [PATCH 154/537] Fix lifetime elision handling for `Fn`-style trait bounds Two fixes were needed: 1. Previously, we enabled elision for the generic args of `Fn` itself, instead of for generic args of paths within it. 2. In lowering in the new solver the `Output` parameter did not have elision set correctly, I don't know why. In the old lowering it was done correctly. --- .../crates/hir-ty/src/lower/path.rs | 12 ++-- .../hir-ty/src/lower_nextsolver/path.rs | 56 ++++++++++++------- .../src/handlers/missing_lifetime.rs | 12 ++++ 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index b0132e4dcbc4..bc03298e3bbb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -603,7 +603,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { explicit_self_ty: Option, lowering_assoc_type_generics: bool, ) -> Substitution { - let mut lifetime_elision = self.ctx.lifetime_elision.clone(); + let old_lifetime_elision = self.ctx.lifetime_elision.clone(); if let Some(args) = self.current_or_prev_segment.args_and_bindings && args.parenthesized != GenericArgsParentheses::No @@ -633,19 +633,21 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. - lifetime_elision = + self.ctx.lifetime_elision = LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; } - self.substs_from_args_and_bindings( + let result = self.substs_from_args_and_bindings( self.current_or_prev_segment.args_and_bindings, def, infer_args, explicit_self_ty, PathGenericsSource::Segment(self.current_segment_u32()), lowering_assoc_type_generics, - lifetime_elision, - ) + self.ctx.lifetime_elision.clone(), + ); + self.ctx.lifetime_elision = old_lifetime_elision; + result } pub(super) fn substs_from_args_and_bindings( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index 7d6734303c48..46dc66a8c8ba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -616,7 +616,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { explicit_self_ty: Option>, lowering_assoc_type_generics: bool, ) -> crate::next_solver::GenericArgs<'db> { - let mut lifetime_elision = self.ctx.lifetime_elision.clone(); + let old_lifetime_elision = self.ctx.lifetime_elision.clone(); if let Some(args) = self.current_or_prev_segment.args_and_bindings && args.parenthesized != GenericArgsParentheses::No @@ -646,19 +646,21 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { } // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. - lifetime_elision = + self.ctx.lifetime_elision = LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; } - self.substs_from_args_and_bindings( + let result = self.substs_from_args_and_bindings( self.current_or_prev_segment.args_and_bindings, def, infer_args, explicit_self_ty, PathGenericsSource::Segment(self.current_segment_u32()), lowering_assoc_type_generics, - lifetime_elision, - ) + self.ctx.lifetime_elision.clone(), + ); + self.ctx.lifetime_elision = old_lifetime_elision; + result } pub(super) fn substs_from_args_and_bindings( @@ -915,22 +917,36 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = binding.type_ref { - match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) { - (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (), - (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => { - let ty = self.ctx.lower_ty(type_ref); - let pred = Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Projection(ProjectionPredicate { - projection_term, - term: ty.into(), - }), - )), - )); - predicates.push(pred); + let lifetime_elision = + if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar { + // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def). + LifetimeElisionKind::for_fn_ret(self.ctx.interner) + } else { + self.ctx.lifetime_elision.clone() + }; + self.with_lifetime_elision(lifetime_elision, |this| { + match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) { + (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (), + ( + _, + ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque, + ) => { + let ty = this.ctx.lower_ty(type_ref); + let pred = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Projection( + ProjectionPredicate { + projection_term, + term: ty.into(), + }, + ), + )), + )); + predicates.push(pred); + } } - } + }) } for bound in binding.bounds.iter() { predicates.extend(self.ctx.lower_type_bound( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs index 76b30745a04d..b07f9e68f634 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs @@ -88,4 +88,16 @@ fn bar() {} "#, ); } + + #[test] + fn fn_traits() { + check_diagnostics( + r#" +//- minicore: fn +struct WithLifetime<'a>(&'a ()); + +fn foo WithLifetime>() {} + "#, + ); + } } From 5dde557fc49ff0268f9890786ef050802b309a75 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Sat, 6 Sep 2025 12:57:18 -0400 Subject: [PATCH 155/537] constify {float}::total_cmp() --- library/core/src/num/f128.rs | 3 +- library/core/src/num/f16.rs | 3 +- library/core/src/num/f32.rs | 3 +- library/core/src/num/f64.rs | 3 +- library/coretests/tests/floats/mod.rs | 165 +++++++++++++------------- 5 files changed, 90 insertions(+), 87 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 66c892aadd08..c5323c9d0421 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1196,7 +1196,8 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i128; let mut right = other.to_bits() as i128; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 81220065e72a..77b73b634892 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1175,7 +1175,8 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i16; let mut right = other.to_bits() as i16; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index cefcf1d1fe2f..da0ba7fe1db5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1353,9 +1353,10 @@ impl f32 { /// } /// ``` #[stable(feature = "total_cmp", since = "1.62.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[must_use] #[inline] - pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i32; let mut right = other.to_bits() as i32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 9dd1141e7033..c93056e31063 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1351,9 +1351,10 @@ impl f64 { /// } /// ``` #[stable(feature = "total_cmp", since = "1.62.0")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] #[must_use] #[inline] - pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i64; let mut right = other.to_bits() as i64; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 31515561c637..d2b572230944 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1246,104 +1246,103 @@ float_test! { float_test! { name: total_cmp, attrs: { - const: #[cfg(false)], f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, test { use core::cmp::Ordering; - fn quiet_bit_mask() -> ::Int { + const fn quiet_bit_mask() -> ::Int { 1 << (Float::MANTISSA_DIGITS - 2) } - fn q_nan() -> Float { + const fn q_nan() -> Float { Float::from_bits(Float::NAN.to_bits() | quiet_bit_mask()) } - assert_eq!(Ordering::Equal, Float::total_cmp(&-q_nan(), &-q_nan())); - assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::INFINITY, &-Float::INFINITY)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MAX, &-Float::MAX)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-2.5, &-2.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-1.0, &-1.0)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-1.5, &-1.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-0.5, &-0.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::TINY, &-Float::TINY)); - assert_eq!(Ordering::Equal, Float::total_cmp(&-0.0, &-0.0)); - assert_eq!(Ordering::Equal, Float::total_cmp(&0.0, &0.0)); - assert_eq!(Ordering::Equal, Float::total_cmp(&Float::TINY, &Float::TINY)); - assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MIN_POSITIVE, &Float::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, Float::total_cmp(&0.5, &0.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&1.0, &1.0)); - assert_eq!(Ordering::Equal, Float::total_cmp(&1.5, &1.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&2.5, &2.5)); - assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MAX, &Float::MAX)); - assert_eq!(Ordering::Equal, Float::total_cmp(&Float::INFINITY, &Float::INFINITY)); - assert_eq!(Ordering::Equal, Float::total_cmp(&q_nan(), &q_nan())); + assert!(matches!(Float::total_cmp(&-q_nan(), &-q_nan()), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-Float::INFINITY, &-Float::INFINITY), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-Float::MAX, &-Float::MAX), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-2.5, &-2.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-1.0, &-1.0), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-1.5, &-1.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-0.5, &-0.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MIN_POSITIVE), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MAX_SUBNORMAL), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-Float::TINY, &-Float::TINY), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&-0.0, &-0.0), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&0.0, &0.0), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&Float::TINY, &Float::TINY), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MAX_SUBNORMAL), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &Float::MIN_POSITIVE), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&0.5, &0.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&1.0, &1.0), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&1.5, &1.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&2.5, &2.5), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&Float::MAX, &Float::MAX), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&Float::INFINITY, &Float::INFINITY), Ordering::Equal)); + assert!(matches!(Float::total_cmp(&q_nan(), &q_nan()), Ordering::Equal)); - assert_eq!(Ordering::Less, Float::total_cmp(&-Float::INFINITY, &-Float::MAX)); - assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MAX, &-2.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-2.5, &-1.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-1.5, &-1.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-1.0, &-0.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-0.5, &-Float::MIN_POSITIVE)); - assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::TINY)); - assert_eq!(Ordering::Less, Float::total_cmp(&-Float::TINY, &-0.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-0.0, &0.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&0.0, &Float::TINY)); - assert_eq!(Ordering::Less, Float::total_cmp(&Float::TINY, &Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Less, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MIN_POSITIVE)); - assert_eq!(Ordering::Less, Float::total_cmp(&Float::MIN_POSITIVE, &0.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&0.5, &1.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&1.0, &1.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&1.5, &2.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&2.5, &Float::MAX)); - assert_eq!(Ordering::Less, Float::total_cmp(&Float::MAX, &Float::INFINITY)); + assert!(matches!(Float::total_cmp(&-Float::INFINITY, &-Float::MAX), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-Float::MAX, &-2.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-2.5, &-1.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-1.5, &-1.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-1.0, &-0.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-0.5, &-Float::MIN_POSITIVE), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MAX_SUBNORMAL), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::TINY), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-Float::TINY, &-0.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-0.0, &0.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&0.0, &Float::TINY), Ordering::Less)); + assert!(matches!(Float::total_cmp(&Float::TINY, &Float::MAX_SUBNORMAL), Ordering::Less)); + assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MIN_POSITIVE), Ordering::Less)); + assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &0.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&0.5, &1.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&1.0, &1.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&1.5, &2.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&2.5, &Float::MAX), Ordering::Less)); + assert!(matches!(Float::total_cmp(&Float::MAX, &Float::INFINITY), Ordering::Less)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MAX, &-Float::INFINITY)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-2.5, &-Float::MAX)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-1.5, &-2.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-1.0, &-1.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-0.5, &-1.0)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MIN_POSITIVE, &-0.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::TINY, &-Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Greater, Float::total_cmp(&-0.0, &-Float::TINY)); - assert_eq!(Ordering::Greater, Float::total_cmp(&0.0, &-0.0)); - assert_eq!(Ordering::Greater, Float::total_cmp(&Float::TINY, &0.0)); - assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::TINY)); - assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MIN_POSITIVE, &Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Greater, Float::total_cmp(&0.5, &Float::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, Float::total_cmp(&1.0, &0.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&1.5, &1.0)); - assert_eq!(Ordering::Greater, Float::total_cmp(&2.5, &1.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MAX, &2.5)); - assert_eq!(Ordering::Greater, Float::total_cmp(&Float::INFINITY, &Float::MAX)); + assert!(matches!(Float::total_cmp(&-Float::MAX, &-Float::INFINITY), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-2.5, &-Float::MAX), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-1.5, &-2.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-1.0, &-1.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-0.5, &-1.0), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-0.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MIN_POSITIVE), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-Float::TINY, &-Float::MAX_SUBNORMAL), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&-0.0, &-Float::TINY), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&0.0, &-0.0), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&Float::TINY, &0.0), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::TINY), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &Float::MAX_SUBNORMAL), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&0.5, &Float::MIN_POSITIVE), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&1.0, &0.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&1.5, &1.0), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&2.5, &1.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&Float::MAX, &2.5), Ordering::Greater)); + assert!(matches!(Float::total_cmp(&Float::INFINITY, &Float::MAX), Ordering::Greater)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::INFINITY)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MAX)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-2.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-1.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-1.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-0.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MIN_POSITIVE)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::TINY)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-0.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &0.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::TINY)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MAX_SUBNORMAL)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MIN_POSITIVE)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &0.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &1.0)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &1.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &2.5)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MAX)); - assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::INFINITY)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::INFINITY), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MAX), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-2.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-1.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-1.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-0.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MIN_POSITIVE), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MAX_SUBNORMAL), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::TINY), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &-0.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &0.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &Float::TINY), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MAX_SUBNORMAL), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MIN_POSITIVE), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &0.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &1.0), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &1.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &2.5), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MAX), Ordering::Less)); + assert!(matches!(Float::total_cmp(&-q_nan(), &Float::INFINITY), Ordering::Less)); } } From 75e3eb82682752563a2687ffb3f135e68ea2b802 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 22 Sep 2025 00:42:44 +0900 Subject: [PATCH 156/537] internal: Migrate more predicate things to next-solver --- .../crates/hir-ty/src/infer/unify.rs | 106 +++++++----------- .../rust-analyzer/crates/hir-ty/src/lib.rs | 45 +++++--- .../crates/hir-ty/src/lower_nextsolver.rs | 12 ++ .../crates/hir-ty/src/method_resolution.rs | 98 ++++++---------- .../rust-analyzer/crates/hir-ty/src/traits.rs | 6 +- 5 files changed, 118 insertions(+), 149 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 1687857ae1ac..cee95d3880df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -11,39 +11,35 @@ use hir_def::{AdtId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::Ty as _; use rustc_type_ir::{ - FloatVid, IntVid, TyVid, TypeVisitableExt, - inherent::{IntoKind, Span, Term as _}, + FloatVid, IntVid, TyVid, TypeVisitableExt, UpcastFrom, + inherent::{IntoKind, Span, Term as _, Ty as _}, relate::{Relate, solver_relating::RelateExt}, - solve::{Certainty, GoalSource, NoSolution}, + solve::{Certainty, GoalSource}, }; use smallvec::SmallVec; use triomphe::Arc; use super::{InferResult, InferenceContext, TypeError}; -use crate::next_solver::ErrorGuaranteed; use crate::{ AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData, - Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, - ProjectionTy, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, - VariableKind, WhereClause, + InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Scalar, Substitution, + TraitEnvironment, Ty, TyExt, TyKind, VariableKind, consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, - next_solver::infer::InferOk, next_solver::{ - self, ClauseKind, DbInterner, ParamEnv, Predicate, PredicateKind, SolverDefIds, Term, + self, ClauseKind, DbInterner, ErrorGuaranteed, ParamEnv, Predicate, PredicateKind, + SolverDefIds, Term, TraitRef, fulfill::FulfillmentCtxt, infer::{ - DbInternerInferExt, InferCtxt, + DbInternerInferExt, InferCtxt, InferOk, snapshot::CombinedSnapshot, traits::{Obligation, ObligationCause}, }, inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, - to_chalk_trait_id, traits::{ FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, }, @@ -877,26 +873,15 @@ impl<'db> InferenceTable<'db> { /// whether a trait *might* be implemented before deciding to 'lock in' the /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner)); + pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { + let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let canonicalized = self.canonicalize(goal); next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } - #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result { - let goal = InEnvironment::new(&self.trait_env.env, goal); - let goal = goal.to_nextsolver(self.interner); - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); - result.map(|m| m.1) - } - pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = next_solver::Goal { - param_env: self.trait_env.env.to_nextsolver(self.interner), - predicate, - }; + let goal = next_solver::Goal { param_env: self.param_env, predicate }; self.register_obligation_in_env(goal) } @@ -984,7 +969,7 @@ impl<'db> InferenceTable<'db> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(FnTrait, Vec>, crate::next_solver::Ty<'db>)> { + ) -> Option<(FnTrait, Vec>, next_solver::Ty<'db>)> { for (fn_trait_name, output_assoc_name, subtraits) in [ (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]), (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]), @@ -997,42 +982,34 @@ impl<'db> InferenceTable<'db> { trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = TyBuilder::tuple(num_args) - .fill(|it| { - let arg = match it { - ParamKind::Type => self.new_type_var(), - ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), - ParamKind::Const(_) => unreachable!("Tuple with const parameter"), - }; - arg_tys.push(arg.to_nextsolver(self.interner)); - arg.cast(Interner) + let arg_ty = next_solver::Ty::new_tup_from_iter( + self.interner, + std::iter::repeat_with(|| { + let ty = self.next_ty_var(); + arg_tys.push(ty); + ty }) - .build(); + .take(num_args), + ); + let args = [ty.to_nextsolver(self.interner), arg_ty]; + let trait_ref = crate::next_solver::TraitRef::new(self.interner, fn_trait.into(), args); - let b = TyBuilder::trait_ref(self.db, fn_trait); - if b.remaining() != 2 { - return None; - } - let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); + let projection = crate::next_solver::Ty::new_alias( + self.interner, + rustc_type_ir::AliasTyKind::Projection, + crate::next_solver::AliasTy::new(self.interner, output_assoc_type.into(), args), + ); - let projection = TyBuilder::assoc_type_projection( - self.db, - output_assoc_type, - Some(trait_ref.substitution.clone()), - ) - .fill_with_unknown() - .build(); - - let goal: Goal = trait_ref.clone().cast(Interner); - if !self.try_obligation(goal.clone()).no_solution() { - self.register_obligation(goal.to_nextsolver(self.interner)); - let return_ty = - self.normalize_projection_ty(projection).to_nextsolver(self.interner); + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + if !self.try_obligation(pred).no_solution() { + self.register_obligation(pred); + let return_ty = self.normalize_alias_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let goal = trait_ref.clone().cast(Interner); - if !self.try_obligation(goal).no_solution() { + let trait_ref = + crate::next_solver::TraitRef::new(self.interner, fn_x_trait.into(), args); + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + if !self.try_obligation(pred).no_solution() { return Some((fn_x, arg_tys, return_ty)); } } @@ -1171,12 +1148,11 @@ impl<'db> InferenceTable<'db> { let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else { return false; }; - let sized_pred = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(sized), - substitution: Substitution::from1(Interner, ty), - }); - let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); - self.try_obligation(goal).certain() + let sized_pred = Predicate::upcast_from( + TraitRef::new(self.interner, sized.into(), [ty.to_nextsolver(self.interner)]), + self.interner, + ); + self.try_obligation(sized_pred).certain() } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 451622ef7472..2accf4884344 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -93,7 +93,10 @@ use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::SliceLike; +use rustc_type_ir::{ + UpcastFrom, + inherent::{SliceLike, Ty as _}, +}; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; @@ -106,7 +109,7 @@ use crate::{ infer::unify::InferenceTable, next_solver::{ DbInterner, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, }; @@ -957,26 +960,32 @@ pub fn callable_sig_from_fn_trait( // Register two obligations: // - Self: FnOnce // - >::Output == ?ret_ty - let args_ty = table.new_type_var(); - let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build(); - let projection = TyBuilder::assoc_type_projection( - db, - output_assoc_type, - Some(trait_ref.substitution.clone()), - ) - .build(); + let args_ty = table.next_ty_var(); + let args = [self_ty.to_nextsolver(table.interner), args_ty]; + let trait_ref = crate::next_solver::TraitRef::new(table.interner, fn_once_trait.into(), args); + let projection = crate::next_solver::Ty::new_alias( + table.interner, + rustc_type_ir::AliasTyKind::Projection, + crate::next_solver::AliasTy::new(table.interner, output_assoc_type.into(), args), + ); - let goal: Goal = trait_ref.clone().cast(Interner); - let pred = goal.to_nextsolver(table.interner); - if !table.try_obligation(goal).no_solution() { + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner); + if !table.try_obligation(pred).no_solution() { table.register_obligation(pred); - let return_ty = table.normalize_projection_ty(projection); + let return_ty = table.normalize_alias_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { - let ret_ty = table.resolve_completely(return_ty); - let args_ty = table.resolve_completely(args_ty); + let trait_ref = + crate::next_solver::TraitRef::new(table.interner, fn_x_trait.into(), args); + if !table + .try_obligation(crate::next_solver::Predicate::upcast_from( + trait_ref, + table.interner, + )) + .no_solution() + { + let ret_ty = table.resolve_completely(return_ty.to_chalk(table.interner)); + let args_ty = table.resolve_completely(args_ty.to_chalk(table.interner)); let params = args_ty .as_tuple()? .iter(Interner) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 0076446a958b..6ecf8874c46d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1355,6 +1355,18 @@ pub(crate) fn generic_predicates_for_param_cycle_result( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenericPredicates<'db>(Option]>>); +impl<'db> GenericPredicates<'db> { + pub fn instantiate( + &self, + interner: DbInterner<'db>, + args: GenericArgs<'db>, + ) -> Option>> { + self.0 + .as_ref() + .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) + } +} + impl<'db> ops::Deref for GenericPredicates<'db> { type Target = [Clause<'db>]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 7fa3d31fe5fd..5cd4879a5404 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -32,9 +32,12 @@ use crate::{ lang_items::is_box, next_solver::{ self, SolverDefId, - fulfill::FulfillmentCtxt, - infer::DefineOpaqueTypes, + infer::{ + DefineOpaqueTypes, + traits::{ObligationCause, PredicateObligation}, + }, mapping::{ChalkToNextSolver, NextSolverToChalk}, + obligation_ctxt::ObligationCtxt, }, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, @@ -907,10 +910,11 @@ fn find_matching_impl( .into_iter() .map(|b| -> Goal { b.cast(Interner) }); for goal in wcs { - if table.try_obligation(goal.clone()).no_solution() { + let goal = goal.to_nextsolver(table.interner); + if table.try_obligation(goal).no_solution() { return None; } - table.register_obligation(goal.to_nextsolver(table.interner)); + table.register_obligation(goal); } Some(( impl_.impl_items(db), @@ -1395,7 +1399,7 @@ fn iterate_trait_method_candidates( let db = table.db; let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner)); - let TraitEnvironment { krate, .. } = *table.trait_env; + let krate = table.trait_env.krate; 'traits: for &t in traits_in_scope { let data = db.trait_signature(t); @@ -1635,7 +1639,6 @@ pub(crate) fn resolve_indexing_op<'db>( let ty = table.instantiate_canonical_ns(ty); let deref_chain = autoderef_method_receiver(table, ty); for (ty, adj) in deref_chain { - //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty); let goal = generic_implements_goal_ns(table, index_trait, ty); if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() { return Some(adj); @@ -1752,10 +1755,7 @@ fn is_valid_trait_method_candidate( }; let res = table .infer_ctxt - .at( - &next_solver::infer::traits::ObligationCause::dummy(), - table.trait_env.env.to_nextsolver(table.interner), - ) + .at(&next_solver::infer::traits::ObligationCause::dummy(), table.param_env) .relate( DefineOpaqueTypes::No, expected_receiver.to_nextsolver(table.interner), @@ -1767,12 +1767,10 @@ fn is_valid_trait_method_candidate( }; if !infer_ok.obligations.is_empty() { - let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt); - for pred in infer_ok.into_obligations() { - ctxt.register_predicate_obligation(&table.infer_ctxt, pred); - } + let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); + ctxt.register_obligations(infer_ok.into_obligations()); // FIXME: Are we doing this correctly? Probably better to follow rustc more closely. - check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty()); + check_that!(ctxt.select_where_possible().is_empty()); } check_that!(table.unify(receiver_ty, &expected_receiver)); @@ -1815,9 +1813,11 @@ fn is_valid_impl_fn_candidate( } table.run_in_snapshot(|table| { let _p = tracing::info_span!("subst_for_def").entered(); - let impl_subst = - TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build(); - let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst); + let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into()); + let expect_self_ty = db + .impl_self_ty_ns(impl_id) + .instantiate(table.interner, &impl_subst) + .to_chalk(table.interner); check_that!(table.unify(&expect_self_ty, self_ty)); @@ -1825,9 +1825,8 @@ fn is_valid_impl_fn_candidate( let _p = tracing::info_span!("check_receiver_ty").entered(); check_that!(data.has_self_param()); - let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone())) - .fill_with_inference_vars(table) - .build(); + let fn_subst: crate::Substitution = + table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner); let sig = db.callable_item_signature(fn_id.into()); let expected_receiver = @@ -1838,48 +1837,25 @@ fn is_valid_impl_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. - let predicates = db.generic_predicates(impl_id.into()); - let goals = predicates.iter().map(|p| { - let (p, b) = p - .clone() - .substitute(Interner, &impl_subst) - // Skipping the inner binders is ok, as we don't handle quantified where - // clauses yet. - .into_value_and_skipped_binders(); - stdx::always!(b.len(Interner) == 0); + let predicates = db.generic_predicates_ns(impl_id.into()); + let Some(predicates) = predicates.instantiate(table.interner, impl_subst) else { + return IsValidCandidate::Yes; + }; - p.cast::(Interner) - }); + let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); - for goal in goals.clone() { - match table.solve_obligation(goal) { - Ok(_) => {} - Err(_) => { - return IsValidCandidate::No; - } - } + ctxt.register_obligations(predicates.into_iter().map(|p| { + PredicateObligation::new(table.interner, ObligationCause::new(), table.param_env, p.0) + })); + + if ctxt.select_where_possible().is_empty() { + IsValidCandidate::Yes + } else { + IsValidCandidate::No } - - for goal in goals { - if table.try_obligation(goal).no_solution() { - return IsValidCandidate::No; - } - } - - IsValidCandidate::Yes }) } -pub fn implements_trait( - ty: &Canonical, - db: &dyn HirDatabase, - env: &TraitEnvironment, - trait_: TraitId, -) -> bool { - let goal = generic_implements_goal(db, env, trait_, ty); - !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution() -} - pub fn implements_trait_unique( ty: &Canonical, db: &dyn HirDatabase, @@ -1891,7 +1867,7 @@ pub fn implements_trait_unique( } /// This creates Substs for a trait with the given Self type and type variables -/// for all other parameters, to query Chalk with it. +/// for all other parameters, to query next solver with it. #[tracing::instrument(skip_all)] fn generic_implements_goal( db: &dyn HirDatabase, @@ -1934,11 +1910,7 @@ fn generic_implements_goal_ns<'db>( let trait_ref = rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args) .with_replaced_self_ty(table.infer_ctxt.interner, self_ty); - let goal = next_solver::Goal::new( - table.infer_ctxt.interner, - table.trait_env.env.to_nextsolver(table.infer_ctxt.interner), - trait_ref, - ); + let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.param_env, trait_ref); table.canonicalize(goal) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 8095d702be48..3ce78e83c129 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -1,4 +1,4 @@ -//! Trait solving using Chalk. +//! Trait solving using next trait solver. use core::fmt; use std::hash::Hash; @@ -128,7 +128,7 @@ fn identity_subst( chalk_ir::Canonical { binders, value: identity_subst } } -/// Solve a trait goal using Chalk. +/// Solve a trait goal using next trait solver. pub(crate) fn trait_solve_query( db: &dyn HirDatabase, krate: Crate, @@ -325,7 +325,7 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>( } } -/// Solve a trait goal using Chalk. +/// Solve a trait goal using next trait solver. pub fn next_trait_solve_in_ctxt<'db, 'a>( infer_ctxt: &'a InferCtxt<'db>, goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>, From bd98e73fe0da34a9c57cf87f3ac248a2e653f970 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 17:45:51 +0200 Subject: [PATCH 157/537] Update tests/rustdoc/reexport/private-mod-override-reexport.rs --- tests/rustdoc/reexport/private-mod-override-reexport.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rustdoc/reexport/private-mod-override-reexport.rs b/tests/rustdoc/reexport/private-mod-override-reexport.rs index 8deafe242225..849acc5fdaec 100644 --- a/tests/rustdoc/reexport/private-mod-override-reexport.rs +++ b/tests/rustdoc/reexport/private-mod-override-reexport.rs @@ -1,6 +1,5 @@ // https://github.com/rust-lang/rust/issues/60926 #![crate_name = "foo"] -#![crate_type = "lib"] mod m1 { pub mod m2 { From 293e0a3aa0dee0cacb4e7aad80f1007e5f06cf39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 17:36:20 +0200 Subject: [PATCH 158/537] fix SIFA logic --- .../tree_borrows/foreign_access_skipping.rs | 2 +- .../src/borrow_tracker/tree_borrows/tree.rs | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs index 928b3e6baef4..90df05d36d96 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs @@ -24,7 +24,7 @@ use super::tree::AccessRelatedness; /// "manually" reset the parent's SIFA to be at least as strong as the new child's. This is accomplished with the `ensure_no_stronger_than` method. /// /// Note that we derive Ord and PartialOrd, so the order in which variants are listed below matters: -/// None < Read < Write. Do not change that order. See the `test_order` test. +/// None < Read < Write (weaker to stronger). Do not change that order. See the `test_order` test. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] pub enum IdempotentForeignAccess { #[default] diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index be2a07eee150..c4345c63289f 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -640,13 +640,18 @@ impl<'tcx> Tree { // Register new_tag as a child of parent_tag self.nodes.get_mut(parent_idx).unwrap().children.push(idx); - // We need to know the biggest SIFA for `update_last_accessed_after_retag` below. - let mut max_sifa = default_strongest_idempotent; + // We need to know the weakest SIFA for `update_idempotent_foreign_access_after_retag`. + let mut min_sifa = default_strongest_idempotent; for (Range { start, end }, &perm) in inside_perms.iter(Size::from_bytes(0), inside_perms.size()) { assert!(perm.permission.is_initial()); - max_sifa = cmp::max(max_sifa, perm.idempotent_foreign_access); + assert_eq!( + perm.idempotent_foreign_access, + perm.permission.strongest_idempotent_foreign_access(protected) + ); + + min_sifa = cmp::min(min_sifa, perm.idempotent_foreign_access); for (_perms_range, perms) in self .rperms .iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start)) @@ -656,22 +661,28 @@ impl<'tcx> Tree { } // Inserting the new perms might have broken the SIFA invariant (see - // `foreign_access_skipping.rs`). We now weaken the recorded SIFA for our parents, until the - // invariant is restored. We could weaken them all to `LocalAccess`, but it is more - // efficient to compute the SIFA for the new permission statically, and use that. For this - // we need the *maximum* SIFA (`Write` needs more fixup than `None`). - self.update_last_accessed_after_retag(parent_idx, max_sifa); + // `foreign_access_skipping.rs`) if the SIFA we inserted is weaker than that of some parent. + // We now weaken the recorded SIFA for our parents, until the invariant is restored. We + // could weaken them all to `None`, but it is more efficient to compute the SIFA for the new + // permission statically, and use that. For this we need the *minimum* SIFA (`None` needs + // more fixup than `Write`). + self.update_idempotent_foreign_access_after_retag(parent_idx, min_sifa); interp_ok(()) } - /// Restores the SIFA "children are stronger" invariant after a retag. - /// See `foreign_access_skipping` and `new_child`. - fn update_last_accessed_after_retag( + /// Restores the SIFA "children are stronger"/"parents are weaker" invariant after a retag: + /// reduce the SIFA of `current` and its parents to be no stronger than `strongest_allowed`. + /// See `foreign_access_skipping.rs` and [`Tree::new_child`]. + fn update_idempotent_foreign_access_after_retag( &mut self, mut current: UniIndex, strongest_allowed: IdempotentForeignAccess, ) { + if strongest_allowed == IdempotentForeignAccess::Write { + // Nothing is stronger than `Write`. + return; + } // We walk the tree upwards, until the invariant is restored loop { let current_node = self.nodes.get_mut(current).unwrap(); From 2dc1354cd0ed52bedc4f7c823e6fa6af581a3109 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 5 Sep 2025 19:58:01 +0200 Subject: [PATCH 159/537] tests/run-make/crate-loading: Rename source files for clarity To make the code easier to understand. --- .../{multiple-dep-versions-3.rs => dep-2-reexport.rs} | 0 .../{multiple-dep-versions-1.rs => dependency-1.rs} | 0 .../{multiple-dep-versions-2.rs => dependency-2.rs} | 0 tests/run-make/crate-loading/rmake.rs | 9 +++------ 4 files changed, 3 insertions(+), 6 deletions(-) rename tests/run-make/crate-loading/{multiple-dep-versions-3.rs => dep-2-reexport.rs} (100%) rename tests/run-make/crate-loading/{multiple-dep-versions-1.rs => dependency-1.rs} (100%) rename tests/run-make/crate-loading/{multiple-dep-versions-2.rs => dependency-2.rs} (100%) diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/dep-2-reexport.rs similarity index 100% rename from tests/run-make/crate-loading/multiple-dep-versions-3.rs rename to tests/run-make/crate-loading/dep-2-reexport.rs diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/dependency-1.rs similarity index 100% rename from tests/run-make/crate-loading/multiple-dep-versions-1.rs rename to tests/run-make/crate-loading/dependency-1.rs diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/dependency-2.rs similarity index 100% rename from tests/run-make/crate-loading/multiple-dep-versions-2.rs rename to tests/run-make/crate-loading/dependency-2.rs diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 6ad456e3e3e5..8f2577861239 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -6,12 +6,9 @@ use run_make_support::{diff, rust_lib_name, rustc}; fn main() { - rustc().input("multiple-dep-versions-1.rs").run(); - rustc().input("multiple-dep-versions-2.rs").extra_filename("2").metadata("2").run(); - rustc() - .input("multiple-dep-versions-3.rs") - .extern_("dependency", rust_lib_name("dependency2")) - .run(); + rustc().input("dependency-1.rs").run(); + rustc().input("dependency-2.rs").extra_filename("2").metadata("2").run(); + rustc().input("dep-2-reexport.rs").extern_("dependency", rust_lib_name("dependency2")).run(); let out = rustc() .input("multiple-dep-versions.rs") From 5e7d34636447a6ae155f4140e7e4cc1ab2b33944 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:01:13 +0200 Subject: [PATCH 160/537] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index 3e9dc46aa563..33f1af40cc44 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 3e9dc46aa563ca0c53ec826c41b05f10c5915925 +Subproject commit 33f1af40cc44dde7e3e892f7a508e6f427d2cbc6 diff --git a/src/doc/reference b/src/doc/reference index b3ce60628c6f..cc7247d8dfae 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b3ce60628c6f55ab8ff3dba9f3d20203df1c0dee +Subproject commit cc7247d8dfaef4c39000bb12c55c32ba5b5ba976 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index dd26bc8e726d..2c9b490d70e5 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit dd26bc8e726dc2e73534c8972d4dccd1bed7495f +Subproject commit 2c9b490d70e535cf166bf17feba59e594579843f From 24144ff499852b0fab63cf0c93d4c8d8b2fad8ef Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 22 Sep 2025 21:02:37 +0200 Subject: [PATCH 161/537] make rust-analyzer settings use dedicated directory This avoids rust-analyzer having to wait for a build lock due to ./x running other commands (and the other way around). --- src/bootstrap/src/core/build_steps/setup.rs | 4 ++++ src/etc/rust_analyzer_eglot.el | 8 +++++-- src/etc/rust_analyzer_helix.toml | 14 ++++++------- src/etc/rust_analyzer_settings.json | 8 +++++-- src/etc/rust_analyzer_zed.json | 23 +++++++++++++++++---- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 9f9af1d9abe3..4b0080f1c80a 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -587,6 +587,7 @@ Select which editor you would like to set up [default: None]: "; "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", + "e260553b71e4773c30a63c4b23b42b279fc73e72f95b775c47b7b7c511c51595", ], EditorKind::Helix => &[ "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", @@ -594,6 +595,7 @@ Select which editor you would like to set up [default: None]: "; "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", + "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", ], EditorKind::Vim | EditorKind::VsCode => &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", @@ -610,6 +612,7 @@ Select which editor you would like to set up [default: None]: "; "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", ], EditorKind::Zed => &[ "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", @@ -617,6 +620,7 @@ Select which editor you would like to set up [default: None]: "; "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", + "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", ], } } diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index 3151cb1a6e75..e5abf67235a5 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -6,6 +6,8 @@ :overrideCommand ["python3" "x.py" "check" + "--build-dir" + "build-rust-analyzer" "--json-output"]) :linkedProjects ["Cargo.toml" "compiler/rustc_codegen_cranelift/Cargo.toml" @@ -13,9 +15,9 @@ "library/Cargo.toml" "src/bootstrap/Cargo.toml" "src/tools/rust-analyzer/Cargo.toml"] - :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + :rustfmt ( :overrideCommand ["build-rust-analyzer/host/rustfmt/bin/rustfmt" "--edition=2024"]) - :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :procMacro ( :server "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" :enable t) :cargo ( :buildScripts ( :enable t :invocationLocation "root" @@ -23,6 +25,8 @@ :overrideCommand ["python3" "x.py" "check" + "--build-dir" + "build-rust-analyzer" "--json-output" "--compile-time-deps"])] :sysrootSrc "./library" diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml index 8c1782a1abce..e2de2a374cbe 100644 --- a/src/etc/rust_analyzer_helix.toml +++ b/src/etc/rust_analyzer_helix.toml @@ -1,10 +1,10 @@ # This config uses a separate build directory for rust-analyzer, # so that r-a's checks don't block user `x` commands and vice-verse. -# R-a's build directory is located in `build/rust-analyzer`. +# R-a's build directory is located in `build-rust-analyzer`. # # To build rustfmt and proc macro server for r-a run the following command: # ``` -# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer +# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build-rust-analyzer # ``` [language-server.rust-analyzer.config] @@ -26,17 +26,17 @@ overrideCommand = [ "check", "--json-output", "--build-dir", - "build/rust-analyzer", + "build-rust-analyzer", ] [language-server.rust-analyzer.config.rustfmt] overrideCommand = [ - "build/rust-analyzer/host/rustfmt/bin/rustfmt", + "build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ] [language-server.rust-analyzer.config.procMacro] -server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" +server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" enable = true [language-server.rust-analyzer.config.rustc] @@ -58,6 +58,6 @@ overrideCommand = [ "check", "--json-output", "--build-dir", - "build/rust-analyzer", - "--compile-time-deps" + "build-rust-analyzer", + "--compile-time-deps", ] diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index b31169857c5e..f89e8a2df187 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -5,6 +5,8 @@ "python3", "x.py", "check", + "--build-dir", + "build-rust-analyzer", "--json-output" ], "rust-analyzer.linkedProjects": [ @@ -16,10 +18,10 @@ "src/tools/rust-analyzer/Cargo.toml" ], "rust-analyzer.rustfmt.overrideCommand": [ - "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", + "${workspaceFolder}/build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ], - "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv", + "rust-analyzer.procMacro.server": "${workspaceFolder}/build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv", "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.buildScripts.enable": true, "rust-analyzer.cargo.buildScripts.invocationStrategy": "once", @@ -27,6 +29,8 @@ "python3", "x.py", "check", + "--build-dir", + "build-rust-analyzer", "--json-output", "--compile-time-deps" ], diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json index 7eace92500e8..d98a082a9b8a 100644 --- a/src/etc/rust_analyzer_zed.json +++ b/src/etc/rust_analyzer_zed.json @@ -7,7 +7,15 @@ "enable": true, "invocationLocation": "root", "invocationStrategy": "once", - "overrideCommand": ["python3", "x.py", "check", "--json-output", "--compile-time-deps"] + "overrideCommand": [ + "python3", + "x.py", + "check", + "--build-dir", + "build-rust-analyzer", + "--compile-time-deps", + "--json-output" + ] }, "extraEnv": { "RUSTC_BOOTSTRAP": "1" @@ -17,7 +25,14 @@ "check": { "invocationLocation": "root", "invocationStrategy": "once", - "overrideCommand": ["python3", "x.py", "check", "--json-output"] + "overrideCommand": [ + "python3", + "x.py", + "check", + "--json-output", + "--build-dir", + "build-rust-analyzer" + ] }, "linkedProjects": [ "Cargo.toml", @@ -29,14 +44,14 @@ ], "procMacro": { "enable": true, - "server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + "server": "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" }, "rustc": { "source": "./Cargo.toml" }, "rustfmt": { "overrideCommand": [ - "build/host/rustfmt/bin/rustfmt", + "build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ] }, From 2d18c886f5754258109fad2e1e0c3bcca0cc9fa5 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 22 Sep 2025 15:10:41 -0400 Subject: [PATCH 162/537] Fix a crash/mislex when more than one frontmatter closing possibility is considered --- compiler/rustc_lexer/src/lib.rs | 4 +++- tests/ui/frontmatter/unclosed-6.rs | 12 ++++++++++++ tests/ui/frontmatter/unclosed-6.stderr | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/frontmatter/unclosed-6.rs create mode 100644 tests/ui/frontmatter/unclosed-6.stderr diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c29ab569f479..f6790f7ed1e9 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -599,14 +599,16 @@ impl Cursor<'_> { if potential_closing.is_none() { // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace // on a standalone line. Might be wrong. + let mut base_index = 0; while let Some(closing) = rest.find("---") { let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) { // candidate found - potential_closing = Some(closing); + potential_closing = Some(closing + base_index); break; } else { rest = &rest[closing + 3..]; + base_index += closing + 3; } } } diff --git a/tests/ui/frontmatter/unclosed-6.rs b/tests/ui/frontmatter/unclosed-6.rs new file mode 100644 index 000000000000..ea8d4702f630 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-6.rs @@ -0,0 +1,12 @@ +--- +//~^ ERROR unclosed frontmatter +🦀--- + --- + +// This test checks the location of the --- recovered by the parser is not +// incorrectly tracked during the less fortunate recovery case and multiple +// candidates are found, as seen with #146847 + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-6.stderr b/tests/ui/frontmatter/unclosed-6.stderr new file mode 100644 index 000000000000..01a13e87268c --- /dev/null +++ b/tests/ui/frontmatter/unclosed-6.stderr @@ -0,0 +1,19 @@ +error: unclosed frontmatter + --> $DIR/unclosed-6.rs:1:1 + | +LL | / --- +LL | | +LL | | 🦀--- +LL | | --- +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-6.rs:1:1 + | +LL | --- + | ^^^ + +error: aborting due to 1 previous error + From 819f8b05b90adcf976d9b76e00fe3a9542781bf5 Mon Sep 17 00:00:00 2001 From: Peter Lyons Kehl Date: Mon, 22 Sep 2025 11:40:53 -0700 Subject: [PATCH 163/537] Mutex/RwLock/ReentrantLock::data_ptr to be const fn --- library/std/src/sync/nonpoison/mutex.rs | 2 +- library/std/src/sync/nonpoison/rwlock.rs | 2 +- library/std/src/sync/poison/mutex.rs | 2 +- library/std/src/sync/poison/rwlock.rs | 2 +- library/std/src/sync/reentrant_lock.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index 07430ce3a139..eeecf5d71076 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -373,7 +373,7 @@ impl Mutex { /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_mutex", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs index eb0aef99cc1e..b2f26edc083e 100644 --- a/library/std/src/sync/nonpoison/rwlock.rs +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -495,7 +495,7 @@ impl RwLock { /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 7e9d920d92f8..6fdb4f6799ee 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -668,7 +668,7 @@ impl Mutex { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0a463f3f9c7e..e3a72c73bf4e 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -667,7 +667,7 @@ impl RwLock { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 4140718560c6..f560b616dd92 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -355,7 +355,7 @@ impl ReentrantLock { /// properly synchronized to avoid data races, and that it is not read /// through after the lock is dropped. #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *const T { + pub const fn data_ptr(&self) -> *const T { &raw const self.data } From 82c4018619b8ec48807151ce1164c9649e998b4d Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 22 Sep 2025 11:20:52 -0500 Subject: [PATCH 164/537] fix ICE in rustdoc::invalid_html_tags --- src/librustdoc/passes/lint/html_tags.rs | 3 +- .../lints/invalid-html-tags-ice-146890.rs | 25 ++++++++++++ .../lints/invalid-html-tags-ice-146890.stderr | 38 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs create mode 100644 tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index da09117b1bba..136ff258048b 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -364,6 +364,7 @@ impl TagParser { } else { if !self.tag_name.is_empty() { self.in_attrs = true; + // range of the entire tag within dox let mut r = Range { start: range.start + start_pos, end: range.start + pos }; if c == '>' { // In case we have a tag without attribute, we can consider the span to @@ -381,7 +382,7 @@ impl TagParser { for (new_pos, c) in text[pos..].char_indices() { if !c.is_whitespace() { if c == '>' { - r.end = range.start + new_pos + 1; + r.end = range.start + pos + new_pos + 1; found = true; } else if c == '<' { self.handle_lt_in_tag(range.clone(), pos + new_pos, f); diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs new file mode 100644 index 000000000000..d7efc201e7e3 --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs @@ -0,0 +1,25 @@ +// this test ensures that bad HTML with multiline tags doesn't cause an ICE +// regression test for https://github.com/rust-lang/rust/issues/146890 +#[deny(rustdoc::invalid_html_tags)] + +/// +/// +/// +///
key +/// +/// value +/// +///
+pub fn foo() {} diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr new file mode 100644 index 000000000000..64a82b3a952a --- /dev/null +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr @@ -0,0 +1,38 @@ +error: unopened HTML tag `TD` + --> $DIR/invalid-html-tags-ice-146890.rs:12:5 + | +LL | /// + | |_____^ + | +note: the lint level is defined here + --> $DIR/invalid-html-tags-ice-146890.rs:3:8 + | +LL | #[deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unopened HTML tag `TD` + --> $DIR/invalid-html-tags-ice-146890.rs:18:5 + | +LL | /// + | |_____^ + +error: unclosed HTML tag `TH` + --> $DIR/invalid-html-tags-ice-146890.rs:9:5 + | +LL | /// $DIR/invalid-html-tags-ice-146890.rs:15:5 + | +LL | /// Date: Mon, 22 Sep 2025 22:02:24 +0200 Subject: [PATCH 165/537] add regression test for issue 146537 --- .../suggestions/non_copy_move_out_of_tuple.rs | 8 ++++++ .../non_copy_move_out_of_tuple.stderr | 26 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/ui/suggestions/non_copy_move_out_of_tuple.rs create mode 100644 tests/ui/suggestions/non_copy_move_out_of_tuple.stderr diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.rs b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs new file mode 100644 index 000000000000..baf15dba33a9 --- /dev/null +++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs @@ -0,0 +1,8 @@ +// Regression test for #146537. + +struct NonCopy; +fn main() { + let tuple = &(NonCopy,); + let b: NonCopy; + (b,) = *tuple; //~ ERROR: cannot move out of `tuple.0` which is behind a shared reference [E0507] +} diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr new file mode 100644 index 000000000000..62f24324fcc1 --- /dev/null +++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr @@ -0,0 +1,26 @@ +error[E0507]: cannot move out of `tuple.0` which is behind a shared reference + --> $DIR/non_copy_move_out_of_tuple.rs:7:12 + | +LL | (b,) = *tuple; + | - ^^^^^^ + | | + | data moved here + | move occurs because the place has type `NonCopy`, which does not implement the `Copy` trait + | +note: if `NonCopy` implemented `Clone`, you could clone the value + --> $DIR/non_copy_move_out_of_tuple.rs:3:1 + | +LL | struct NonCopy; + | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | (b,) = *tuple; + | - you could clone this value +help: consider removing the dereference here + | +LL - (b,) = *tuple; +LL + (b,) = tuple; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. From 389a502ade65e82d8a0c4d323118121c1c09c4f8 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 19 Sep 2025 17:16:05 -0700 Subject: [PATCH 166/537] Fix a dangling reference in `rustc_thread_pool` --- compiler/rustc_thread_pool/src/latch.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs index 18d654d9f782..58dabaf35c00 100644 --- a/compiler/rustc_thread_pool/src/latch.rs +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -388,13 +388,17 @@ impl Latch for CountLatch { #[inline] unsafe fn set(this: *const Self) { if unsafe { (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 } { - // NOTE: Once we call `set` on the internal `latch`, + // SAFETY: Once we call `set` on the internal `latch`, // the target may proceed and invalidate `this`! match unsafe { &(*this).kind } { CountLatchKind::Stealing { latch, registry, worker_index } => { let registry = Arc::clone(registry); + let worker_index = *worker_index; + // SAFETY: We don't use any references from `this` after this call. if unsafe { CoreLatch::set(latch) } { - registry.notify_worker_latch_is_set(*worker_index); + // We **must not** access any part of `this` anymore, which + // is why we read and shadowed these fields beforehand. + registry.notify_worker_latch_is_set(worker_index); } } CountLatchKind::Blocking { latch } => unsafe { LockLatch::set(latch) }, From 2ba71fba652720807a2c8cd5c35c230943ce06e9 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Fri, 15 Aug 2025 15:59:28 +0000 Subject: [PATCH 167/537] Use ns versions of with_diagnostics queries --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f8dacf0fb863..f231348d24a4 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -680,7 +680,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(s.id.into()).1, + db.field_types_with_diagnostics_ns(s.id.into()).1, source_map, ); } @@ -692,7 +692,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(u.id.into()).1, + db.field_types_with_diagnostics_ns(u.id.into()).1, source_map, ); } @@ -722,7 +722,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(v.into()).1, + db.field_types_with_diagnostics_ns(v.into()).1, source_map, ); expr_store_diagnostics(db, acc, source_map); @@ -738,7 +738,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics(type_alias.id).1, + db.type_for_type_alias_with_diagnostics_ns(type_alias.id).1, &source_map, ); acc.extend(def.diagnostics(db, style_lints)); @@ -913,13 +913,13 @@ impl Module { push_ty_diagnostics( db, acc, - db.impl_self_ty_with_diagnostics(impl_def.id).1, + db.impl_self_ty_with_diagnostics_ns(impl_def.id).1, &source_map, ); push_ty_diagnostics( db, acc, - db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + db.impl_trait_with_diagnostics_ns(impl_def.id).and_then(|it| it.1), &source_map, ); @@ -3646,7 +3646,7 @@ impl AssocItem { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics(type_alias.id).1, + db.type_for_type_alias_with_diagnostics_ns(type_alias.id).1, &db.type_alias_signature_with_source_map(type_alias.id).1, ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { @@ -3782,7 +3782,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( + db.const_param_ty_with_diagnostics_ns(ConstParamId::from_unchecked( TypeOrConstParamId { parent: def, local_id: param_id }, )) .1, From 9e8f6e82b1b76055edb33b1d8de1263344c50cc0 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Sun, 17 Aug 2025 16:02:17 +0000 Subject: [PATCH 168/537] Make Field::ty return TypeNs --- .../crates/hir-ty/src/next_solver/mapping.rs | 2 +- .../rust-analyzer/crates/hir/src/display.rs | 8 ++++- src/tools/rust-analyzer/crates/hir/src/lib.rs | 33 ++++++++++--------- .../src/handlers/add_missing_match_arms.rs | 2 +- .../src/handlers/expand_rest_pattern.rs | 7 ++-- .../ide-completion/src/completions/record.rs | 12 +++++-- .../crates/ide/src/goto_type_definition.rs | 2 +- .../rust-analyzer/crates/ide/src/hover.rs | 4 +-- .../crates/ide/src/hover/render.rs | 8 ++--- .../crates/ide/src/signature_help.rs | 2 +- .../crates/ide/src/view_memory_layout.rs | 2 +- 11 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index b24b996b0927..5dcb1e62329d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -1266,7 +1266,7 @@ pub fn convert_args_for_result<'db>( Substitution::from_iter(Interner, substs) } -pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty { +pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty { use crate::{Scalar, TyKind}; use chalk_ir::{FloatTy, IntTy, UintTy}; match ty.kind() { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 833a9ef03065..2bf9bb85e50d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -24,7 +24,7 @@ use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, TyBuilder, - Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, + Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -437,6 +437,12 @@ impl HirDisplay for Type<'_> { } } +impl HirDisplay for TypeNs<'_> { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + self.ty.hir_fmt(f) + } +} + impl HirDisplay for ExternCrateDecl { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f231348d24a4..1cec01da6008 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -86,7 +86,9 @@ use hir_ty::{ method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, mapping::ChalkToNextSolver, + ClauseKind, DbInterner, GenericArgs, + infer::InferCtxt, + mapping::{ChalkToNextSolver, convert_ty_for_result}, }, primitive::UintTy, traits::FnTrait, @@ -1346,19 +1348,12 @@ impl Field { u32::from(self.id.into_raw()) as usize } - /// Returns the type as in the signature of the struct (i.e., with - /// placeholder types for type parameters). Only use this in the context of - /// the field definition. - pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { + /// Returns the type as in the signature of the struct. Only use this in the + /// context of the field definition. + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { let var_id = self.parent.into(); - let generic_def_id: GenericDefId = match self.parent { - VariantDef::Struct(it) => it.id.into(), - VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.id.lookup(db).parent.into(), - }; - let substs = TyBuilder::placeholder_subst(db, generic_def_id); - let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); - Type::new(db, var_id, ty) + let ty = db.field_types_ns(var_id)[self.id].skip_binder(); + TypeNs::new(db, var_id, ty) } // FIXME: Find better API to also handle const generics @@ -1388,9 +1383,8 @@ impl Field { } pub fn layout(&self, db: &dyn HirDatabase) -> Result { - let interner = DbInterner::new_with(db, None, None); db.layout_of_ty( - self.ty(db).ty.to_nextsolver(interner), + self.ty(db).ty, db.trait_environment(match hir_def::VariantId::from(self.parent) { hir_def::VariantId::EnumVariantId(id) => { GenericDefId::AdtId(id.lookup(db).parent.into()) @@ -5969,6 +5963,11 @@ impl<'db> TypeNs<'db> { TypeNs { env: environment, ty, _pd: PhantomCovariantLifetime::new() } } + pub fn to_type(&self, db: &'db dyn HirDatabase) -> Type<'db> { + let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + Type { env: self.env.clone(), ty: convert_ty_for_result(interner, self.ty), _pd: self._pd } + } + // FIXME: Find better API that also handles const generics pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool { let args = GenericArgs::new_from_iter( @@ -5992,6 +5991,10 @@ impl<'db> TypeNs<'db> { let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal); res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) } + + pub fn is_bool(&self) -> bool { + matches!(self.ty.kind(), rustc_type_ir::TyKind::Bool) + } } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 4d3212c515f2..3910921fbe03 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -521,7 +521,7 @@ fn build_pat( hir::StructKind::Tuple => { let mut name_generator = suggest_name::NameGenerator::default(); let pats = fields.into_iter().map(|f| { - let name = name_generator.for_type(&f.ty(db), db, edition); + let name = name_generator.for_type(&f.ty(db).to_type(db), db, edition); match name { Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(), None => make.wildcard_pat().into(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index c80b78fd9705..1c0d330fc379 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -145,8 +145,11 @@ fn expand_tuple_struct_rest_pattern( make.ident_pat( false, false, - match name_gen.for_type(&f.ty(ctx.sema.db), ctx.sema.db, ctx.edition()) - { + match name_gen.for_type( + &f.ty(ctx.sema.db).to_type(ctx.sema.db), + ctx.sema.db, + ctx.edition(), + ) { Some(name) => make.name(&name), None => make.name(&format!("_{}", f.index())), }, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 36f38a70db63..2f5abd18934f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -28,7 +28,11 @@ pub(crate) fn complete_record_pattern_fields( record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some(); match were_fields_specified { - false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), + false => un + .fields(ctx.db) + .into_iter() + .map(|f| (f, f.ty(ctx.db).to_type(ctx.db))) + .collect(), true => return, } } @@ -56,7 +60,11 @@ pub(crate) fn complete_record_expr_fields( record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some(); match were_fields_specified { - false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), + false => un + .fields(ctx.db) + .into_iter() + .map(|f| (f, f.ty(ctx.db).to_type(ctx.db))) + .collect(), true => return, } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index ffd144a827e3..ae208fe1b561 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -88,7 +88,7 @@ pub(crate) fn goto_type_definition( ast::Pat(it) => sema.type_of_pat(&it)?.original, ast::SelfParam(it) => sema.type_of_self(&it)?, ast::Type(it) => sema.resolve_type(&it)?, - ast::RecordField(it) => sema.to_def(&it)?.ty(db), + ast::RecordField(it) => sema.to_def(&it)?.ty(db).to_type(db), // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise ast::NameRef(it) => { if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 03b9b3677511..c4fb6d1a5b4b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -440,7 +440,7 @@ pub(crate) fn hover_for_definition( Definition::Local(it) => Some(it.ty(db)), Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), - Definition::Field(field) => Some(field.ty(db)), + Definition::Field(field) => Some(field.ty(db).to_type(db)), Definition::TupleField(it) => Some(it.ty(db)), Definition::Function(it) => Some(it.ty(db)), Definition::Adt(it) => Some(it.ty(db)), @@ -602,7 +602,7 @@ fn goto_type_action_for_def( let ty = match def { Definition::Local(it) => Some(it.ty(db)), - Definition::Field(field) => Some(field.ty(db)), + Definition::Field(field) => Some(field.ty(db).to_type(db)), Definition::TupleField(field) => Some(field.ty(db)), Definition::Const(it) => Some(it.ty(db)), Definition::Static(it) => Some(it.ty(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 65375ed8f78c..c5d695ccec3a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -692,14 +692,14 @@ pub(super) fn definition( } let drop_info = match def { Definition::Field(field) => { - DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None } + DropInfo { drop_glue: field.ty(db).to_type(db).drop_glue(db), has_dtor: None } } Definition::Adt(Adt::Struct(strukt)) => { let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db); let mut fields_drop_glue = strukt .fields(db) .iter() - .map(|field| field.ty(db).drop_glue(db)) + .map(|field| field.ty(db).to_type(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None); let has_dtor = match (fields_drop_glue, struct_drop_glue) { @@ -727,7 +727,7 @@ pub(super) fn definition( variant .fields(db) .iter() - .map(|field| field.ty(db).drop_glue(db)) + .map(|field| field.ty(db).to_type(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None) }) @@ -742,7 +742,7 @@ pub(super) fn definition( let fields_drop_glue = variant .fields(db) .iter() - .map(|field| field.ty(db).drop_glue(db)) + .map(|field| field.ty(db).to_type(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None); DropInfo { drop_glue: fields_drop_glue, has_dtor: None } diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index f45d096ac190..e74d997e97c5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -526,7 +526,7 @@ fn signature_help_for_tuple_struct_pat( pat.syntax(), token, pat.fields(), - fields.into_iter().map(|it| it.ty(db)), + fields.into_iter().map(|it| it.ty(db).to_type(db)), display_target, )) } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 950f3f6c6470..5457d57b3976 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -99,7 +99,7 @@ pub(crate) fn view_memory_layout( Definition::BuiltinType(it) => it.ty(db), Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), - Definition::Field(it) => it.ty(db), + Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)), Definition::Const(it) => it.ty(db), Definition::Static(it) => it.ty(db), _ => return None, From 263b2a5c277a26c3d686bbbe1c4a194ad601f341 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Thu, 11 Sep 2025 04:47:39 -0400 Subject: [PATCH 169/537] Add 'db to TraitEnvironment --- .../crates/hir-ty/src/autoderef.rs | 8 ++-- .../crates/hir-ty/src/consteval.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 21 +++++---- .../crates/hir-ty/src/diagnostics/expr.rs | 8 ++-- .../diagnostics/match_check/pat_analysis.rs | 4 +- .../crates/hir-ty/src/display.rs | 10 ++-- .../rust-analyzer/crates/hir-ty/src/drop.rs | 12 +++-- .../rust-analyzer/crates/hir-ty/src/infer.rs | 2 +- .../crates/hir-ty/src/infer/coerce.rs | 8 ++-- .../crates/hir-ty/src/infer/unify.rs | 10 ++-- .../crates/hir-ty/src/inhabitedness.rs | 6 +-- .../rust-analyzer/crates/hir-ty/src/layout.rs | 6 +-- .../crates/hir-ty/src/layout/adt.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 6 +-- .../rust-analyzer/crates/hir-ty/src/lower.rs | 8 ++-- .../crates/hir-ty/src/method_resolution.rs | 46 +++++++++---------- .../crates/hir-ty/src/mir/eval.rs | 14 +++--- .../crates/hir-ty/src/mir/lower.rs | 2 +- .../crates/hir-ty/src/mir/monomorphization.rs | 20 ++++---- .../rust-analyzer/crates/hir-ty/src/traits.rs | 20 +++++--- src/tools/rust-analyzer/crates/hir/src/lib.rs | 10 ++-- .../crates/hir/src/source_analyzer.rs | 2 +- 22 files changed, 122 insertions(+), 109 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index fd60ffcf24b0..4c79c800fcf3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -32,11 +32,11 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20; /// - the yielded types don't contain inference variables (but may contain `TyKind::Error`). /// - a type won't be yielded more than once; in other words, the returned iterator will stop if it /// detects a cycle in the deref chain. -pub fn autoderef( - db: &dyn HirDatabase, - env: Arc, +pub fn autoderef<'db>( + db: &'db dyn HirDatabase, + env: Arc>, ty: crate::Canonical, -) -> impl Iterator { +) -> impl Iterator + use<> { let mut table = InferenceTable::new(db, env); let interner = table.interner; let ty = table.instantiate_canonical(ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 0f2cc17f563d..e2a8d1cedc28 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -229,7 +229,7 @@ pub(crate) fn const_eval_cycle_result( _: &dyn HirDatabase, _: GeneralConstId, _: Substitution, - _: Option>, + _: Option>>, ) -> Result { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -252,7 +252,7 @@ pub(crate) fn const_eval_query( db: &dyn HirDatabase, def: GeneralConstId, subst: Substitution, - trait_env: Option>, + trait_env: Option>>, ) -> Result { let body = match def { GeneralConstId::ConstId(c) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 448fc4aede03..24e617135160 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -49,7 +49,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &self, def: DefWithBodyId, subst: Substitution, - env: Arc, + env: Arc>, ) -> Result, MirLowerError>; #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)] @@ -57,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &self, def: InternedClosureId, subst: Substitution, - env: Arc, + env: Arc>, ) -> Result, MirLowerError>; #[salsa::invoke(crate::mir::borrowck_query)] @@ -70,7 +70,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &self, def: GeneralConstId, subst: Substitution, - trait_env: Option>, + trait_env: Option>>, ) -> Result; #[salsa::invoke(crate::consteval::const_eval_static_query)] @@ -84,7 +84,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] fn lookup_impl_method( &self, - env: Arc, + env: Arc>, func: FunctionId, fn_subst: Substitution, ) -> (FunctionId, Substitution); @@ -97,7 +97,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: AdtId, args: crate::next_solver::GenericArgs<'db>, - trait_env: Arc, + trait_env: Arc>, ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::layout_of_ty_query)] @@ -105,7 +105,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn layout_of_ty<'db>( &'db self, ty: crate::next_solver::Ty<'db>, - env: Arc, + env: Arc>, ) -> Result, LayoutError>; #[salsa::invoke(crate::layout::target_data_layout_query)] @@ -184,10 +184,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] - fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc; + fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) + -> Arc>; #[salsa::invoke(crate::lower::trait_environment_query)] - fn trait_environment(&self, def: GenericDefId) -> Arc; + fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] @@ -258,7 +259,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn normalize_projection( &self, projection: crate::ProjectionTy, - env: Arc, + env: Arc>, ) -> Ty; #[salsa::invoke(crate::traits::trait_solve_query)] @@ -272,7 +273,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::drop::has_drop_glue)] #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)] - fn has_drop_glue(&self, ty: Ty, env: Arc) -> DropGlue; + fn has_drop_glue(&self, ty: Ty, env: Arc>) -> DropGlue; // next trait solver diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 403ea05a4f53..d05814e0e7e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -81,17 +81,17 @@ impl BodyValidationDiagnostic { } } -struct ExprValidator { +struct ExprValidator<'db> { owner: DefWithBodyId, body: Arc, infer: Arc, - env: Arc, + env: Arc>, diagnostics: Vec, validate_lints: bool, } -impl ExprValidator { - fn validate_body(&mut self, db: &dyn HirDatabase) { +impl<'db> ExprValidator<'db> { + fn validate_body(&mut self, db: &'db dyn HirDatabase) { let mut filter_map_next_checker = None; // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint let body = Arc::clone(&self.body); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 56fd12e1f2b4..eb20d3c51ff4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -70,7 +70,7 @@ pub(crate) struct MatchCheckCtx<'db> { body: DefWithBodyId, pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, - env: Arc, + env: Arc>, } impl<'db> MatchCheckCtx<'db> { @@ -78,7 +78,7 @@ impl<'db> MatchCheckCtx<'db> { module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, ) -> Self { let def_map = module.crate_def_map(db); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 519e4b59237f..02f3eb39a4e0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -799,12 +799,12 @@ fn render_const_scalar_ns( render_const_scalar_inner(f, b, memory_map, ty, trait_env) } -fn render_const_scalar_inner( +fn render_const_scalar_inner<'db>( f: &mut HirFormatter<'_>, b: &[u8], memory_map: &MemoryMap<'_>, - ty: crate::next_solver::Ty<'_>, - trait_env: Arc, + ty: crate::next_solver::Ty<'db>, + trait_env: Arc>, ) -> Result<(), HirDisplayError> { use rustc_type_ir::TyKind; match ty.kind() { @@ -1068,11 +1068,11 @@ fn render_const_scalar_inner( } } -fn render_variant_after_name( +fn render_variant_after_name<'db>( data: &VariantFields, f: &mut HirFormatter<'_>, field_types: &ArenaMap>, - trait_env: Arc, + trait_env: Arc>, layout: &Layout, args: GenericArgs<'_>, b: &[u8], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index f5c2f41069ea..88a7d15d8ea7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -43,7 +43,11 @@ pub enum DropGlue { HasDropGlue, } -pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc) -> DropGlue { +pub(crate) fn has_drop_glue( + db: &dyn HirDatabase, + ty: Ty, + env: Arc>, +) -> DropGlue { match ty.kind(Interner) { TyKind::Adt(adt, subst) => { if has_destructor(db, adt.0) { @@ -165,7 +169,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc, + env: Arc>, projection: ProjectionTy, ty: Ty, ) -> DropGlue { @@ -178,7 +182,7 @@ fn projection_has_drop_glue( } } -fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { +fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc>) -> bool { let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else { return false; }; @@ -193,7 +197,7 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { pub(crate) fn has_drop_glue_cycle_result( _db: &dyn HirDatabase, _ty: Ty, - _env: Arc, + _env: Arc>, ) -> DropGlue { DropGlue::None } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 017119781a70..3ece62ec35b6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -152,7 +152,7 @@ pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc, ty: Ty) -> Ty { +pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc>, ty: Ty) -> Ty { // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only // works for the type case, so we check array unconditionally. Remove the array part // when the bug in chalk becomes fixed. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 7930d8b0ed68..42948ccb9306 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -1564,9 +1564,9 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { } } -pub fn could_coerce( - db: &dyn HirDatabase, - env: Arc, +pub fn could_coerce<'db>( + db: &'db dyn HirDatabase, + env: Arc>, tys: &crate::Canonical<(crate::Ty, crate::Ty)>, ) -> bool { coerce(db, env, tys).is_ok() @@ -1574,7 +1574,7 @@ pub fn could_coerce( fn coerce<'db>( db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, tys: &crate::Canonical<(crate::Ty, crate::Ty)>, ) -> Result<(Vec, crate::Ty), TypeError>> { let mut table = InferenceTable::new(db, env); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index cee95d3880df..1204fb06d2fe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -121,7 +121,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> { /// unresolved goal `T = U`. pub fn could_unify( db: &dyn HirDatabase, - env: Arc, + env: Arc>, tys: &Canonical<(Ty, Ty)>, ) -> bool { unify(db, env, tys).is_some() @@ -133,7 +133,7 @@ pub fn could_unify( /// them. For example `Option` and `Option` do not unify as we cannot show that `T = U` pub fn could_unify_deeply( db: &dyn HirDatabase, - env: Arc, + env: Arc>, tys: &Canonical<(Ty, Ty)>, ) -> bool { let mut table = InferenceTable::new(db, env); @@ -151,7 +151,7 @@ pub fn could_unify_deeply( pub(crate) fn unify( db: &dyn HirDatabase, - env: Arc, + env: Arc>, tys: &Canonical<(Ty, Ty)>, ) -> Option { let mut table = InferenceTable::new(db, env); @@ -212,7 +212,7 @@ bitflags::bitflags! { pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) interner: DbInterner<'db>, - pub(crate) trait_env: Arc, + pub(crate) trait_env: Arc>, pub(crate) param_env: ParamEnv<'db>, pub(crate) tait_coercion_table: Option>, pub(crate) infer_ctxt: InferCtxt<'db>, @@ -227,7 +227,7 @@ pub(crate) struct InferenceTableSnapshot<'db> { } impl<'db> InferenceTable<'db> { - pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc) -> Self { + pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc>) -> Self { let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block); let infer_ctxt = interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis { defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index b16b6a117846..bdebe41b2998 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -20,7 +20,7 @@ pub(crate) fn is_ty_uninhabited_from( db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId, - env: Arc, + env: Arc>, ) -> bool { let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = @@ -36,7 +36,7 @@ pub(crate) fn is_enum_variant_uninhabited_from( variant: EnumVariantId, subst: &Substitution, target_mod: ModuleId, - env: Arc, + env: Arc>, ) -> bool { let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); @@ -52,7 +52,7 @@ struct UninhabitedFrom<'a> { // guard for preventing stack overflow in non trivial non terminating types max_depth: usize, db: &'a dyn HirDatabase, - env: Arc, + env: Arc>, } const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index f21673c732e4..4071b9a1d5e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -132,7 +132,7 @@ fn layout_of_simd_ty<'db>( id: StructId, repr_packed: bool, args: &GenericArgs<'db>, - env: Arc, + env: Arc>, dl: &TargetDataLayout, ) -> Result, LayoutError> { // Supported SIMD vectors are homogeneous ADTs with exactly one array field: @@ -160,7 +160,7 @@ fn layout_of_simd_ty<'db>( pub fn layout_of_ty_query<'db>( db: &'db dyn HirDatabase, ty: Ty<'db>, - trait_env: Arc, + trait_env: Arc>, ) -> Result, LayoutError> { let krate = trait_env.krate; let interner = DbInterner::new_with(db, Some(krate), trait_env.block); @@ -371,7 +371,7 @@ pub fn layout_of_ty_query<'db>( pub(crate) fn layout_of_ty_cycle_result<'db>( _: &dyn HirDatabase, _: Ty<'db>, - _: Arc, + _: Arc>, ) -> Result, LayoutError> { Err(LayoutError::RecursiveTypeWithoutIndirection) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 9a746ca88858..a8f04bf8c132 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -23,7 +23,7 @@ pub fn layout_of_adt_query<'db>( db: &'db dyn HirDatabase, def: AdtId, args: GenericArgs<'db>, - trait_env: Arc, + trait_env: Arc>, ) -> Result, LayoutError> { let krate = trait_env.krate; let Ok(target) = db.target_data_layout(krate) else { @@ -99,7 +99,7 @@ pub(crate) fn layout_of_adt_cycle_result<'db>( _: &'db dyn HirDatabase, _def: AdtId, _args: GenericArgs<'db>, - _trait_env: Arc, + _trait_env: Arc>, ) -> Result, LayoutError> { Err(LayoutError::RecursiveTypeWithoutIndirection) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2accf4884344..05c5a7a28b9a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -940,10 +940,10 @@ where Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } } -pub fn callable_sig_from_fn_trait( +pub fn callable_sig_from_fn_trait<'db>( self_ty: &Ty, - trait_env: Arc, - db: &dyn HirDatabase, + trait_env: Arc>, + db: &'db dyn HirDatabase, ) -> Option<(FnTrait, CallableSig)> { let krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 4d5172fd4f24..eeec9d0454d3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1089,7 +1089,7 @@ pub(crate) fn generic_predicates_for_param_cycle_result( pub(crate) fn trait_environment_for_body_query( db: &dyn HirDatabase, def: DefWithBodyId, -) -> Arc { +) -> Arc> { let Some(def) = def.as_generic_def_id(db) else { let krate = def.module(db).krate(); return TraitEnvironment::empty(krate); @@ -1097,10 +1097,10 @@ pub(crate) fn trait_environment_for_body_query( db.trait_environment(def) } -pub(crate) fn trait_environment_query( - db: &dyn HirDatabase, +pub(crate) fn trait_environment_query<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> Arc { +) -> Arc> { let generics = generics(db, def); if generics.has_no_predicates() && generics.is_empty() { return TraitEnvironment::empty(def.krate(db)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 5cd4879a5404..db74ca258732 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -545,7 +545,7 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option( db: &'db dyn HirDatabase, ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, - env: Arc, + env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: &Name, @@ -714,7 +714,7 @@ impl ReceiverAdjustments { pub(crate) fn iterate_method_candidates<'db, T>( ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, @@ -742,9 +742,9 @@ pub(crate) fn iterate_method_candidates<'db, T>( slot } -pub fn lookup_impl_const( - db: &dyn HirDatabase, - env: Arc, +pub fn lookup_impl_const<'db>( + db: &'db dyn HirDatabase, + env: Arc>, const_id: ConstId, subs: Substitution, ) -> (ConstId, Substitution) { @@ -770,9 +770,9 @@ pub fn lookup_impl_const( /// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should /// call the method using the vtable. -pub fn is_dyn_method( - db: &dyn HirDatabase, - _env: Arc, +pub fn is_dyn_method<'db>( + db: &'db dyn HirDatabase, + _env: Arc>, func: FunctionId, fn_subst: Substitution, ) -> Option { @@ -812,9 +812,9 @@ pub fn is_dyn_method( /// Looks up the impl method that actually runs for the trait method `func`. /// /// Returns `func` if it's not a method defined in a trait or the lookup failed. -pub(crate) fn lookup_impl_method_query( - db: &dyn HirDatabase, - env: Arc, +pub(crate) fn lookup_impl_method_query<'db>( + db: &'db dyn HirDatabase, + env: Arc>, func: FunctionId, fn_subst: Substitution, ) -> (FunctionId, Substitution) { @@ -845,10 +845,10 @@ pub(crate) fn lookup_impl_method_query( ) } -fn lookup_impl_assoc_item_for_trait_ref( +fn lookup_impl_assoc_item_for_trait_ref<'db>( trait_ref: TraitRef, - db: &dyn HirDatabase, - env: Arc, + db: &'db dyn HirDatabase, + env: Arc>, name: &Name, ) -> Option<(AssocItemId, Substitution)> { let hir_trait_id = trait_ref.hir_trait_id(); @@ -1067,7 +1067,7 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { pub fn iterate_path_candidates<'db>( ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, @@ -1089,7 +1089,7 @@ pub fn iterate_path_candidates<'db>( pub fn iterate_method_candidates_dyn<'db>( ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, @@ -1351,7 +1351,7 @@ fn iterate_method_candidates_by_receiver<'db>( fn iterate_method_candidates_for_self_ty<'db>( self_ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>, db: &'db dyn HirDatabase, - env: Arc, + env: Arc>, traits_in_scope: &FxHashSet, visible_from_module: VisibleFromModule, name: Option<&Name>, @@ -1856,10 +1856,10 @@ fn is_valid_impl_fn_candidate( }) } -pub fn implements_trait_unique( +pub fn implements_trait_unique<'db>( ty: &Canonical, - db: &dyn HirDatabase, - env: &TraitEnvironment, + db: &'db dyn HirDatabase, + env: &TraitEnvironment<'db>, trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env, trait_, ty); @@ -1869,9 +1869,9 @@ pub fn implements_trait_unique( /// This creates Substs for a trait with the given Self type and type variables /// for all other parameters, to query next solver with it. #[tracing::instrument(skip_all)] -fn generic_implements_goal( - db: &dyn HirDatabase, - env: &TraitEnvironment, +fn generic_implements_goal<'db>( + db: &'db dyn HirDatabase, + env: &TraitEnvironment<'db>, trait_: TraitId, self_ty: &Canonical, ) -> Canonical> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 3e658cb93ed8..3d7ad8d3b069 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -165,7 +165,7 @@ enum MirOrDynIndex { pub struct Evaluator<'a> { db: &'a dyn HirDatabase, - trait_env: Arc, + trait_env: Arc>, target_data_layout: Arc, stack: Vec, heap: Vec, @@ -582,8 +582,8 @@ impl MirOutput { } } -pub fn interpret_mir( - db: &dyn HirDatabase, +pub fn interpret_mir<'db>( + db: &'db dyn HirDatabase, body: Arc, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which @@ -591,7 +591,7 @@ pub fn interpret_mir( // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can // (and probably should) do better here, for example by excluding bindings outside of the target expression. assert_placeholder_ty_is_unused: bool, - trait_env: Option>, + trait_env: Option>>, ) -> Result<(Result, MirOutput)> { let ty = body.locals[return_slot()].ty.clone(); let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?; @@ -632,11 +632,11 @@ const EXECUTION_LIMIT: usize = 10_000_000; impl<'db> Evaluator<'db> { pub fn new( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, owner: DefWithBodyId, assert_placeholder_ty_is_unused: bool, - trait_env: Option>, - ) -> Result> { + trait_env: Option>>, + ) -> Result> { let crate_id = owner.module(db).krate(); let target_data_layout = match db.target_data_layout(crate_id) { Ok(target_data_layout) => target_data_layout, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 50e416a66a64..0416f4315d4d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -82,7 +82,7 @@ struct MirLowerCtx<'db> { infer: &'db InferenceResult, resolver: Resolver<'db>, drop_scopes: Vec, - env: Arc, + env: Arc>, } // FIXME: Make this smaller, its stored in database queries diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 555b87850924..f293f38c7698 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -35,7 +35,7 @@ macro_rules! not_supported { struct Filler<'a> { db: &'a dyn HirDatabase, - trait_env: Arc, + trait_env: Arc>, subst: &'a Substitution, generics: Option, } @@ -301,11 +301,11 @@ impl Filler<'_> { } } -pub fn monomorphized_mir_body_query( - db: &dyn HirDatabase, +pub fn monomorphized_mir_body_query<'db>( + db: &'db dyn HirDatabase, owner: DefWithBodyId, subst: Substitution, - trait_env: Arc, + trait_env: Arc>, ) -> Result, MirLowerError> { let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); let filler = &mut Filler { db, subst: &subst, trait_env, generics }; @@ -315,20 +315,20 @@ pub fn monomorphized_mir_body_query( Ok(Arc::new(body)) } -pub(crate) fn monomorphized_mir_body_cycle_result( - _db: &dyn HirDatabase, +pub(crate) fn monomorphized_mir_body_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: DefWithBodyId, _: Substitution, - _: Arc, + _: Arc>, ) -> Result, MirLowerError> { Err(MirLowerError::Loop) } -pub fn monomorphized_mir_body_for_closure_query( - db: &dyn HirDatabase, +pub fn monomorphized_mir_body_for_closure_query<'db>( + db: &'db dyn HirDatabase, closure: InternedClosureId, subst: Substitution, - trait_env: Arc, + trait_env: Arc>, ) -> Result, MirLowerError> { let InternedClosure(owner, _) = db.lookup_intern_closure(closure); let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 3ce78e83c129..d6a86c13978b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -39,21 +39,23 @@ use crate::{ /// ``` /// we assume that `T: Default`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct TraitEnvironment { +pub struct TraitEnvironment<'db> { pub krate: Crate, pub block: Option, // FIXME make this a BTreeMap traits_from_clauses: Box<[(Ty, TraitId)]>, pub env: chalk_ir::Environment, + _db: std::marker::PhantomData<&'db ()>, } -impl TraitEnvironment { +impl<'db> TraitEnvironment<'db> { pub fn empty(krate: Crate) -> Arc { Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: Box::default(), env: chalk_ir::Environment::new(Interner), + _db: std::marker::PhantomData, }) } @@ -63,7 +65,13 @@ impl TraitEnvironment { traits_from_clauses: Box<[(Ty, TraitId)]>, env: chalk_ir::Environment, ) -> Arc { - Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) + Arc::new(TraitEnvironment { + krate, + block, + traits_from_clauses, + env, + _db: std::marker::PhantomData, + }) } // pub fn with_block(self: &mut Arc, block: BlockId) { @@ -78,10 +86,10 @@ impl TraitEnvironment { } } -pub(crate) fn normalize_projection_query( - db: &dyn HirDatabase, +pub(crate) fn normalize_projection_query<'db>( + db: &'db dyn HirDatabase, projection: ProjectionTy, - env: Arc, + env: Arc>, ) -> Ty { if projection.substitution.iter(Interner).any(|arg| { arg.ty(Interner) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1cec01da6008..eaae15835d0b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -3808,12 +3808,12 @@ impl GenericDef { pub struct GenericSubstitution<'db> { def: GenericDefId, subst: Substitution, - env: Arc, + env: Arc>, _pd: PhantomCovariantLifetime<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: Substitution, env: Arc) -> Self { + fn new(def: GenericDefId, subst: Substitution, env: Arc>) -> Self { Self { def, subst, env, _pd: PhantomCovariantLifetime::new() } } @@ -4567,7 +4567,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - env: Arc, + env: Arc>, trait_ref: hir_ty::next_solver::TraitRef<'db>, _pd: PhantomCovariantLifetime<'db>, } @@ -4790,7 +4790,7 @@ impl CaptureUsageSource { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type<'db> { - env: Arc, + env: Arc>, ty: Ty, _pd: PhantomCovariantLifetime<'db>, } @@ -5945,7 +5945,7 @@ impl<'db> Type<'db> { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeNs<'db> { - env: Arc, + env: Arc>, ty: hir_ty::next_solver::Ty<'db>, _pd: PhantomCovariantLifetime<'db>, } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 539b25387aef..a19183fa1302 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -219,7 +219,7 @@ impl<'db> SourceAnalyzer<'db> { }) } - fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc { + fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc> { self.body_().map(|(def, ..)| def).map_or_else( || TraitEnvironment::empty(self.resolver.krate()), |def| db.trait_environment_for_body(def), From 06078dfa9782115e83fb2a02bec9253e927aeee3 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:38:31 -0400 Subject: [PATCH 170/537] Use ParamEnv in TraitEnvironment --- .../crates/hir-ty/src/autoderef.rs | 2 +- .../crates/hir-ty/src/chalk_ext.rs | 14 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 4 +- .../crates/hir-ty/src/display.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 7 +- .../crates/hir-ty/src/infer/closure.rs | 6 +- .../crates/hir-ty/src/infer/coerce.rs | 20 +-- .../crates/hir-ty/src/infer/expr.rs | 5 +- .../crates/hir-ty/src/infer/unify.rs | 18 ++- .../rust-analyzer/crates/hir-ty/src/lower.rs | 111 +-------------- .../crates/hir-ty/src/lower_nextsolver.rs | 130 +++++++++++++++++- .../crates/hir-ty/src/method_resolution.rs | 21 ++- .../crates/hir-ty/src/tests/regression.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 18 +-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 11 +- .../crates/ide-completion/src/tests.rs | 8 +- .../crates/ide/src/view_memory_layout.rs | 4 +- 17 files changed, 216 insertions(+), 170 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 4c79c800fcf3..21a86d3e4372 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -298,7 +298,7 @@ fn structurally_normalize_ty<'db>( ) -> Option<(Ty<'db>, PredicateObligations<'db>)> { let mut ocx = ObligationCtxt::new(&table.infer_ctxt); let Ok(normalized_ty) = - ocx.structurally_normalize_ty(&ObligationCause::misc(), table.param_env, ty) + ocx.structurally_normalize_ty(&ObligationCause::misc(), table.trait_env.env, ty) else { // We shouldn't have errors here in the old solver, except for // evaluate/fulfill mismatches, but that's not a reason for an ICE. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 1faf9f66dc54..6956a0a12328 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -15,8 +15,13 @@ use crate::{ AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, - WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, + WhereClause, + db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, + generics::generics, + next_solver::{DbInterner, mapping::NextSolverToChalk}, + to_chalk_trait_id, + utils::ClosureSubst, }; pub trait TyExt { @@ -372,7 +377,10 @@ impl TyExt for Ty { let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); let env = db.trait_environment_for_body(owner); let goal = Canonical { - value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), + value: InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; !db.trait_solve(crate_id, None, goal).no_solution() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 24e617135160..44f48069ab24 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -182,12 +182,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; - #[salsa::invoke(crate::lower::trait_environment_for_body_query)] + #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> Arc>; - #[salsa::invoke(crate::lower::trait_environment_query)] + #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)] fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 02f3eb39a4e0..dc42304e1cab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -792,10 +792,7 @@ fn render_const_scalar_ns( let trait_env = TraitEnvironment::empty(f.krate()); let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis); - let ty = infcx - .at(&ObligationCause::new(), trait_env.env.to_nextsolver(interner)) - .deeply_normalize(ty) - .unwrap_or(ty); + let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, trait_env) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 88a7d15d8ea7..413f70532a54 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -7,6 +7,8 @@ use hir_def::signatures::StructFlags; use stdx::never; use triomphe::Arc; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, @@ -188,7 +190,10 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc>) -> bool }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); let goal = Canonical { - value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), + value: InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; db.trait_solve(env.krate, env.block, goal).certain() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 1d5d8dd13edd..4a57b2f37510 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -318,7 +318,7 @@ impl<'db> InferenceContext<'db> { _ = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::new(), self.table.trait_env.env) .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); @@ -703,7 +703,7 @@ impl<'db> InferenceContext<'db> { let cause = ObligationCause::new(); let InferOk { value: (), obligations } = table .infer_ctxt - .at(&cause, table.param_env) + .at(&cause, table.trait_env.env) .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?; all_obligations.extend(obligations); } @@ -711,7 +711,7 @@ impl<'db> InferenceContext<'db> { let supplied_output_ty = supplied_sig.output(); let cause = ObligationCause::new(); let InferOk { value: (), obligations } = - table.infer_ctxt.at(&cause, table.param_env).eq( + table.infer_ctxt.at(&cause, table.trait_env.env).eq( DefineOpaqueTypes::Yes, expected_sigs.liberated_sig.output(), supplied_output_ty, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 42948ccb9306..219b519e46bb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -144,7 +144,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { fn unify_raw(&mut self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|this| { - let at = this.infer_ctxt().at(&this.cause, this.table.param_env); + let at = this.infer_ctxt().at(&this.cause, this.table.trait_env.env); let res = if this.use_lub { at.lub(b, a) @@ -330,7 +330,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { obligations.push(Obligation::new( self.interner(), self.cause.clone(), - self.table.param_env, + self.table.trait_env.env, Binder::dummy(PredicateKind::Coerce(CoercePredicate { a: source_ty, b: target_ty, @@ -718,7 +718,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new( self.interner(), cause, - self.table.param_env, + self.table.trait_env.env, TraitRef::new( self.interner(), coerce_unsized_did.into(), @@ -1114,8 +1114,12 @@ impl<'db> InferenceContext<'db> { match self.table.commit_if_ok(|table| { // We need to eagerly handle nested obligations due to lazy norm. let mut ocx = ObligationCtxt::new(&table.infer_ctxt); - let value = - ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?; + let value = ocx.lub( + &ObligationCause::new(), + table.trait_env.env, + prev_ty, + new_ty, + )?; if ocx.select_where_possible().is_empty() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { @@ -1158,7 +1162,7 @@ impl<'db> InferenceContext<'db> { let sig = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::new(), self.table.trait_env.env) .lub(a_sig, b_sig) .map(|ok| self.table.register_infer_ok(ok))?; @@ -1248,7 +1252,7 @@ impl<'db> InferenceContext<'db> { .commit_if_ok(|table| { table .infer_ctxt - .at(&ObligationCause::new(), table.param_env) + .at(&ObligationCause::new(), table.trait_env.env) .lub(prev_ty, new_ty) }) .unwrap_err()) @@ -1498,7 +1502,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { assert!(expression_ty.is_unit(), "if let hack without unit type"); icx.table .infer_ctxt - .at(cause, icx.table.param_env) + .at(cause, icx.table.trait_env.env) .eq( // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs DefineOpaqueTypes::Yes, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index c5a51dfc4cf9..b4a332f1da84 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1662,7 +1662,6 @@ impl<'db> InferenceContext<'db> { }); self.resolver.reset_to_guard(g); if let Some(prev_env) = prev_env { - self.table.param_env = prev_env.env.to_nextsolver(self.table.interner); self.table.trait_env = prev_env; } @@ -2132,7 +2131,7 @@ impl<'db> InferenceContext<'db> { let origin = ObligationCause::new(); ocx.sup( &origin, - self.table.param_env, + self.table.trait_env.env, expected_output.to_nextsolver(interner), formal_output, )?; @@ -2239,7 +2238,7 @@ impl<'db> InferenceContext<'db> { let formal_ty_error = this .table .infer_ctxt - .at(&ObligationCause::new(), this.table.param_env) + .at(&ObligationCause::new(), this.table.trait_env.env) .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty); // If neither check failed, the types are compatible diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 1204fb06d2fe..6df9cbaa2939 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -29,8 +29,8 @@ use crate::{ db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{ - self, ClauseKind, DbInterner, ErrorGuaranteed, ParamEnv, Predicate, PredicateKind, - SolverDefIds, Term, TraitRef, + self, ClauseKind, DbInterner, ErrorGuaranteed, Predicate, PredicateKind, SolverDefIds, + Term, TraitRef, fulfill::FulfillmentCtxt, infer::{ DbInternerInferExt, InferCtxt, InferOk, @@ -213,7 +213,6 @@ pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) interner: DbInterner<'db>, pub(crate) trait_env: Arc>, - pub(crate) param_env: ParamEnv<'db>, pub(crate) tait_coercion_table: Option>, pub(crate) infer_ctxt: InferCtxt<'db>, diverging_tys: FxHashSet, @@ -235,7 +234,6 @@ impl<'db> InferenceTable<'db> { InferenceTable { db, interner, - param_env: trait_env.env.to_nextsolver(interner), trait_env, tait_coercion_table: None, fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), @@ -426,7 +424,7 @@ impl<'db> InferenceTable<'db> { { let ty = self.resolve_vars_with_obligations(ty); self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) + .at(&ObligationCause::new(), self.trait_env.env) .deeply_normalize(ty.clone()) .unwrap_or(ty) } @@ -741,7 +739,7 @@ impl<'db> InferenceTable<'db> { ) -> InferResult<'db, ()> { let variance = rustc_type_ir::Variance::Invariant; let span = crate::next_solver::Span::dummy(); - match self.infer_ctxt.relate(self.param_env, lhs, variance, rhs, span) { + match self.infer_ctxt.relate(self.trait_env.env, lhs, variance, rhs, span) { Ok(goals) => Ok(crate::infer::InferOk { goals, value: () }), Err(_) => Err(TypeError), } @@ -798,7 +796,7 @@ impl<'db> InferenceTable<'db> { fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> { self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) + .at(&ObligationCause::new(), self.trait_env.env) .structurally_normalize_term(term, &mut self.fulfillment_cx) .unwrap_or(term) } @@ -818,7 +816,7 @@ impl<'db> InferenceTable<'db> { // in a reentrant borrow, causing an ICE. let result = self .infer_ctxt - .at(&ObligationCause::misc(), self.param_env) + .at(&ObligationCause::misc(), self.trait_env.env) .structurally_normalize_ty(ty, &mut self.fulfillment_cx); match result { Ok(normalized_ty) => normalized_ty, @@ -874,14 +872,14 @@ impl<'db> InferenceTable<'db> { /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { - let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let goal = next_solver::Goal { param_env: self.trait_env.env, predicate }; let canonicalized = self.canonicalize(goal); next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let goal = next_solver::Goal { param_env: self.trait_env.env, predicate }; self.register_obligation_in_env(goal) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index eeec9d0454d3..20f421dbbcd9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -24,9 +24,9 @@ use chalk_ir::{ use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, - Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, + GenericDefId, GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, + StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, @@ -46,11 +46,10 @@ use stdx::{impl_from, never}; use triomphe::{Arc, ThinArc}; use crate::{ - AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi, - FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, - LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, - all_super_traits, + AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, + FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, + LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, + TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, all_super_traits, consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, @@ -1086,102 +1085,6 @@ pub(crate) fn generic_predicates_for_param_cycle_result( GenericPredicates(None) } -pub(crate) fn trait_environment_for_body_query( - db: &dyn HirDatabase, - def: DefWithBodyId, -) -> Arc> { - let Some(def) = def.as_generic_def_id(db) else { - let krate = def.module(db).krate(); - return TraitEnvironment::empty(krate); - }; - db.trait_environment(def) -} - -pub(crate) fn trait_environment_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> Arc> { - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return TraitEnvironment::empty(def.krate(db)); - } - - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(ParamLoweringMode::Placeholder); - let mut traits_in_scope = Vec::new(); - let mut clauses = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - for pred in ctx.lower_where_predicate(pred, false) { - if let WhereClause::Implemented(tr) = pred.skip_binders() { - traits_in_scope - .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); - } - let program_clause: Binders = - pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner)); - clauses.push(program_clause); - } - } - } - - if let Some(trait_id) = def.assoc_trait_container(db) { - // add `Self: Trait` to the environment in trait - // function default implementations (and speculative code - // inside consts or type aliases) - cov_mark::hit!(trait_self_implements_self); - let substs = TyBuilder::placeholder_subst(db, trait_id); - let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; - let pred = WhereClause::Implemented(trait_ref); - clauses.push(Binders::empty( - Interner, - pred.cast::(Interner).into_from_env_goal(Interner), - )); - } - - let subst = generics.placeholder_subst(db); - if !subst.is_empty(Interner) { - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_clauses) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - clauses.extend(implicitly_sized_clauses.map(|pred| { - Binders::empty( - Interner, - pred.into_from_env_goal(Interner).cast::(Interner), - ) - })); - }; - } - - let clauses = chalk_ir::ProgramClauses::from_iter( - Interner, - clauses.into_iter().map(|g| { - chalk_ir::ProgramClause::new( - Interner, - chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication { - consequence: g, - conditions: chalk_ir::Goals::empty(Interner), - constraints: chalk_ir::Constraints::empty(Interner), - priority: chalk_ir::ClausePriority::High, - })), - ) - }), - ); - let env = chalk_ir::Environment { clauses }; - - TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenericPredicates(Option]>>); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 6ecf8874c46d..1ca56feb099a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -19,9 +19,9 @@ use base_db::Crate; use either::Either; use hir_def::item_tree::FieldsShape; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId, - TypeOrConstParamId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, + GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, expr_store::{ ExpressionStore, path::{GenericArg, Path}, @@ -57,7 +57,7 @@ use triomphe::Arc; use crate::ValueTyDefId; use crate::{ - FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic, + FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic}, db::HirDatabase, @@ -66,8 +66,10 @@ use crate::{ next_solver::{ AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder, - EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, - TraitPredicate, TraitRef, Ty, Tys, abi::Safety, mapping::ChalkToNextSolver, + EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region, + SolverDefId, TraitPredicate, TraitRef, Ty, Tys, + abi::Safety, + mapping::{ChalkToNextSolver, convert_ty_for_result}, }, }; @@ -1375,6 +1377,122 @@ impl<'db> ops::Deref for GenericPredicates<'db> { } } +pub(crate) fn trait_environment_for_body_query( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Arc> { + let Some(def) = def.as_generic_def_id(db) else { + let krate = def.module(db).krate(); + return TraitEnvironment::empty(krate); + }; + db.trait_environment(def) +} + +pub(crate) fn trait_environment_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> Arc> { + let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return TraitEnvironment::empty(def.krate(db)); + } + + let interner = DbInterner::new_with(db, Some(def.krate(db)), None); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + let mut traits_in_scope = Vec::new(); + let mut clauses = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { + if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { + traits_in_scope + .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0)); + } + clauses.push(pred); + } + } + } + + if let Some(trait_id) = def.assoc_trait_container(db) { + // add `Self: Trait` to the environment in trait + // function default implementations (and speculative code + // inside consts or type aliases) + cov_mark::hit!(trait_self_implements_self); + let trait_ref = TraitRef::identity(ctx.interner, trait_id.into()); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive }, + ))), + )); + clauses.push(clause); + } + + let explicitly_unsized_tys = ctx.unsized_types; + + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + if let Some(sized_trait) = sized_trait { + let (mut generics, mut def_id) = + (crate::next_solver::generics::generics(db, def.into()), def); + loop { + let self_idx = trait_self_param_idx(db, def_id); + for (idx, p) in generics.own_params.iter().enumerate() { + if let Some(self_idx) = self_idx + && p.index() as usize == self_idx + { + continue; + } + let GenericParamId::TypeParamId(param_id) = p.id else { + continue; + }; + let idx = idx as u32 + generics.parent_count as u32; + let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone()); + if explicitly_unsized_tys.contains(¶m_ty) { + continue; + } + let trait_ref = TraitRef::new_from_args( + ctx.interner, + sized_trait.into(), + GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]), + ); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + clauses.push(clause); + } + + if let Some(g) = generics.parent { + generics = crate::next_solver::generics::generics(db, g.into()); + def_id = g; + } else { + break; + } + } + } + + let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses); + let clauses = Clauses::new_from_iter(ctx.interner, clauses); + let env = ParamEnv { clauses }; + + TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) +} + #[derive(Copy, Clone, Debug)] pub(crate) enum PredicateFilter { SelfTrait, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index db74ca258732..fd28159b49cb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -31,7 +31,7 @@ use crate::{ infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, lang_items::is_box, next_solver::{ - self, SolverDefId, + self, DbInterner, SolverDefId, infer::{ DefineOpaqueTypes, traits::{ObligationCause, PredicateObligation}, @@ -1755,7 +1755,10 @@ fn is_valid_trait_method_candidate( }; let res = table .infer_ctxt - .at(&next_solver::infer::traits::ObligationCause::dummy(), table.param_env) + .at( + &next_solver::infer::traits::ObligationCause::dummy(), + table.trait_env.env, + ) .relate( DefineOpaqueTypes::No, expected_receiver.to_nextsolver(table.interner), @@ -1845,7 +1848,12 @@ fn is_valid_impl_fn_candidate( let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); ctxt.register_obligations(predicates.into_iter().map(|p| { - PredicateObligation::new(table.interner, ObligationCause::new(), table.param_env, p.0) + PredicateObligation::new( + table.interner, + ObligationCause::new(), + table.trait_env.env, + p.0, + ) })); if ctxt.select_where_possible().is_empty() { @@ -1893,7 +1901,10 @@ fn generic_implements_goal<'db>( let binders = CanonicalVarKinds::from_iter(Interner, kinds); let obligation = trait_ref.cast(Interner); - let value = InEnvironment::new(&env.env, obligation); + let value = InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + obligation, + ); Canonical { binders, value } } @@ -1910,7 +1921,7 @@ fn generic_implements_goal_ns<'db>( let trait_ref = rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args) .with_replaced_self_ty(table.infer_ctxt.interner, self_ty); - let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.param_env, trait_ref); + let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref); table.canonicalize(goal) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 2ba1e2341b29..a6215ef8fe4f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -632,7 +632,7 @@ fn issue_4053_diesel_where_clauses() { 488..522 '{ ... }': as BoxedDsl>::Output 498..502 'self': SelectStatement 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment + '? + 498..515 'self.o...into()': dyn QueryFragment + 'static "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index d6a86c13978b..8ac152341e75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -25,7 +25,7 @@ use crate::{ db::HirDatabase, infer::unify::InferenceTable, next_solver::{ - DbInterner, GenericArg, Predicate, SolverContext, Span, + DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span, infer::{DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, util::mini_canonicalize, @@ -44,8 +44,7 @@ pub struct TraitEnvironment<'db> { pub block: Option, // FIXME make this a BTreeMap traits_from_clauses: Box<[(Ty, TraitId)]>, - pub env: chalk_ir::Environment, - _db: std::marker::PhantomData<&'db ()>, + pub env: ParamEnv<'db>, } impl<'db> TraitEnvironment<'db> { @@ -54,8 +53,7 @@ impl<'db> TraitEnvironment<'db> { krate, block: None, traits_from_clauses: Box::default(), - env: chalk_ir::Environment::new(Interner), - _db: std::marker::PhantomData, + env: ParamEnv::empty(), }) } @@ -63,15 +61,9 @@ impl<'db> TraitEnvironment<'db> { krate: Crate, block: Option, traits_from_clauses: Box<[(Ty, TraitId)]>, - env: chalk_ir::Environment, + env: ParamEnv<'db>, ) -> Arc { - Arc::new(TraitEnvironment { - krate, - block, - traits_from_clauses, - env, - _db: std::marker::PhantomData, - }) + Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) } // pub fn with_block(self: &mut Arc, block: BlockId) { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index eaae15835d0b..862067e5916c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -88,7 +88,7 @@ use hir_ty::{ next_solver::{ ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, primitive::UintTy, traits::FnTrait, @@ -5171,7 +5171,14 @@ impl<'db> Type<'db> { .build(); let goal = Canonical { - value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)), + value: hir_ty::InEnvironment::new( + &self.env.env.to_chalk(DbInterner::new_with( + db, + Some(self.env.krate), + self.env.block, + )), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 809a26bf5de4..b20b570c2b8d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -26,6 +26,7 @@ mod visibility; use base_db::{SourceDatabase, salsa}; use expect_test::Expect; +use hir::db::HirDatabase; use hir::{PrefixKind, setup_tracing}; use ide_db::{ FilePosition, RootDatabase, SnippetCap, @@ -306,8 +307,11 @@ pub(crate) fn get_all_items( trigger_character: Option, ) -> Vec { let (db, position) = position(code); - let res = salsa::attach(&db, || crate::completions(&db, &config, position, trigger_character)) - .map_or_else(Vec::default, Into::into); + let res = salsa::attach(&db, || { + HirDatabase::zalsa_register_downcaster(&db); + crate::completions(&db, &config, position, trigger_character) + }) + .map_or_else(Vec::default, Into::into); // validate res.iter().for_each(|it| { let sr = it.source_range; diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 5457d57b3976..04537f908fbb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -100,8 +100,8 @@ pub(crate) fn view_memory_layout( Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)), - Definition::Const(it) => it.ty(db), - Definition::Static(it) => it.ty(db), + Definition::Const(it) => salsa::attach(db, || it.ty(db)), + Definition::Static(it) => salsa::attach(db, || it.ty(db)), _ => return None, }; From 4c1595a93b349fa755d84f8943860589c27b64f0 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 22 Sep 2025 21:13:38 -0400 Subject: [PATCH 171/537] Skip the panic-immediate-abort-works test when cross-compiling --- tests/run-make-cargo/panic-immediate-abort-works/rmake.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs index bb15bd41e79c..3eeef38c962d 100644 --- a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs +++ b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs @@ -4,7 +4,12 @@ // cleaner and more portable). So this test ensures that we didn't mix up a cfg or a compiler // implementation detail in a way that makes panic=immediate-abort encounter errors at link time. +// Ideally this test would be run for most targets, but unfortunately: +// This test is currently written using `fn main() {}` which requires std. +// And since the default linker is only a linker for the host, we can't handle cross-compilation. +// Both of these shortcomings could be addressed at the cost of making the test more complicated. //@ needs-target-std +//@ ignore-cross-compile #![deny(warnings)] From c241ff4089bf4619ec327c6da0955ee71a08c0a2 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 23 Sep 2025 11:26:52 +0800 Subject: [PATCH 172/537] Add const parameter keyword completion Example --- ```rust fn foo() {} ``` -> ```rust fn foo() {} ``` --- .../crates/ide-completion/src/completions.rs | 4 ++- .../ide-completion/src/tests/special.rs | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index e36e0e570458..eb2bb31f963e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -691,6 +691,9 @@ pub(super) fn complete_name( NameKind::RecordField => { field::complete_field_list_record_variant(acc, ctx); } + NameKind::TypeParam => { + acc.add_keyword_snippet(ctx, "const", "const $1: $0"); + } NameKind::ConstParam | NameKind::Enum | NameKind::MacroDef @@ -700,7 +703,6 @@ pub(super) fn complete_name( | NameKind::Static | NameKind::Struct | NameKind::Trait - | NameKind::TypeParam | NameKind::Union | NameKind::Variant => (), } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 84ddff8f617a..c438ca788062 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -1510,3 +1510,28 @@ fn foo() { "#]], ); } + +#[test] +fn fn_generic_params_const_param_snippet() { + check_edit("const", "fn foo() {}", "fn foo() {}"); + check_edit("const", "fn foo() {}", "fn foo() {}"); + check( + r#" +fn foo() {} +"#, + expect![[r#" + kw crate:: + kw self:: + "#]], + ); + check( + r#" +fn foo() {} +"#, + expect![[r#" + bt u32 u32 + kw crate:: + kw self:: + "#]], + ); +} From aaa82aea053bfbb226916b38c66243a28a296b6e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Sep 2025 21:52:48 +0530 Subject: [PATCH 173/537] move config check logic from get_toml to parse_inner --- src/bootstrap/src/core/builder/tests.rs | 4 ++-- src/bootstrap/src/core/config/config.rs | 12 +++++++++++ src/bootstrap/src/core/config/tests.rs | 25 ++++++++--------------- src/bootstrap/src/core/config/toml/mod.rs | 6 ------ 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index f838149977d0..4555f0d20912 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -308,14 +308,14 @@ mod sysroot_target_dirs { /// cg_gcc tests instead. #[test] fn test_test_compiler() { - let config = configure_with_args(&["test", "compiler"], &[], &[TEST_TRIPLE_1]); + let config = configure_with_args(&["test", "compiler"], &[&host_target()], &[TEST_TRIPLE_1]); let cache = run_build(&config.paths.clone(), config); let compiler = cache.contains::(); let cranelift = cache.contains::(); let gcc = cache.contains::(); - assert_eq!((compiler, cranelift, gcc), (false, false, false)); + assert_eq!((compiler, cranelift, gcc), (true, false, false)); } #[test] diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 280ae088f3f3..1e207380a0a1 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -424,6 +424,18 @@ impl Config { src = src_; } + #[cfg(test)] + { + if let Some(config_path) = flags_config.as_ref() { + assert!( + !config_path.starts_with(&src), + "Path {config_path:?} should not be inside or equal to src dir {src:?}" + ); + } else { + panic!("During test the config should be explicitly added"); + } + } + // Now load the TOML config, as soon as possible let (mut toml, toml_path) = load_toml_config(&src, flags_config, &get_toml); diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 3390e9586a4c..4f2df76a1565 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -175,20 +175,14 @@ fn override_toml_duplicate() { #[test] fn profile_user_dist() { - fn get_toml(file: &Path) -> Result { - let contents = if file.ends_with("bootstrap.toml") - || file.ends_with("config.toml") - || env::var_os("RUST_BOOTSTRAP_CONFIG").is_some() - { - "profile = \"user\"".to_owned() - } else { - assert!(file.ends_with("config.dist.toml") || file.ends_with("bootstrap.dist.toml")); - std::fs::read_to_string(file).unwrap() - }; - - toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table)) - } - Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml); + TestCtx::new() + .config("check") + .with_default_toml_config( + r#" + profile = "user" + "#, + ) + .create_config(); } #[test] @@ -224,8 +218,6 @@ fn verify_file_integrity() { config .verify(&tempfile, "7e255dd9542648a8779268a0f268b891a198e9828e860ed23f826440e786eae5") ); - - remove_file(tempfile).unwrap(); } #[test] @@ -648,6 +640,7 @@ fn test_include_precedence_over_profile() { .config("check") .with_default_toml_config( r#" + profile = "dist" include = ["./extension.toml"] "#, ) diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs index 5f86d2e72818..f6dc5b67e101 100644 --- a/src/bootstrap/src/core/config/toml/mod.rs +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -152,12 +152,6 @@ impl Config { } pub(crate) fn get_toml(file: &Path) -> Result { - #[cfg(test)] - { - let tmp = std::env::temp_dir(); - assert!(file.starts_with(&tmp), "Expected path in temp dir {:?}, got {:?}", tmp, file); - } - Self::get_toml_inner(file) } From 2d495ccaaa874666768b1a9e47e06d7de9e9aceb Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 23 Sep 2025 12:14:14 +0800 Subject: [PATCH 174/537] Migrate `expand_record_rest_pattern` assist to use `SyntaxEditor` Because `add_field` uses `ted` --- .../src/handlers/expand_rest_pattern.rs | 21 +++++++++---------- .../crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index c80b78fd9705..44fe7957bca0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -24,7 +24,7 @@ use crate::{AssistContext, AssistId, Assists}; // struct Bar { y: Y, z: Z } // // fn foo(bar: Bar) { -// let Bar { y, z } = bar; +// let Bar { y, z } = bar; // } // ``` fn expand_record_rest_pattern( @@ -53,18 +53,17 @@ fn expand_record_rest_pattern( |builder| { let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(rest_pat.syntax()); - let new_field_list = make.record_pat_field_list(old_field_list.fields(), None); - for (f, _) in missing_fields.iter() { - let field = make.record_pat_field_shorthand( + let new_fields = old_field_list.fields().chain(missing_fields.iter().map(|(f, _)| { + make.record_pat_field_shorthand( make.ident_pat( false, false, make.name(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()), ) .into(), - ); - new_field_list.add_field(field); - } + ) + })); + let new_field_list = make.record_pat_field_list(new_fields, None); editor.replace(old_field_list.syntax(), new_field_list.syntax()); @@ -211,7 +210,7 @@ enum Foo { fn bar(foo: Foo) { match foo { Foo::A(_) => false, - Foo::B{ y, z } => true, + Foo::B{ y, z } => true, }; } "#, @@ -272,7 +271,7 @@ struct Bar { } fn foo(bar: Bar) { - let Bar { y, z } = bar; + let Bar { y, z } = bar; } "#, ); @@ -376,7 +375,7 @@ macro_rules! position { position!(usize); fn macro_call(pos: Pos) { - let Pos { x, y } = pos; + let Pos { x, y } = pos; } "#, ); @@ -420,7 +419,7 @@ enum_gen!(usize); fn macro_call(foo: Foo) { match foo { Foo::A(_) => false, - Foo::B{ x, y } => true, + Foo::B{ x, y } => true, } } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 91348be97eb7..71ffaa23fc64 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1035,7 +1035,7 @@ fn foo(bar: Bar) { struct Bar { y: Y, z: Z } fn foo(bar: Bar) { - let Bar { y, z } = bar; + let Bar { y, z } = bar; } "#####, ) From 9ae7aef06d1146ee30190fb399d548e1db3652dd Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Mon, 22 Sep 2025 15:02:02 +0800 Subject: [PATCH 175/537] prevent line number from being copied in chrome --- src/librustdoc/html/static/js/main.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 75febd6f737e..3ea9de381eca 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -2227,11 +2227,18 @@ function preLoadCss(cssUrl) { }); }()); -// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds -// extra backline characters. + +// Workaround for browser-specific bugs when copying code snippets. // -// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464 -// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836 +// * In Firefox, copying text that includes elements with `user-select: none` +// inserts extra blank lines. +// - Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836 +// - Rust issue: https://github.com/rust-lang/rust/issues/141464 +// +// * In Chromium-based browsers, `document.getSelection()` includes elements +// with `user-select: none`, causing unwanted line numbers to be copied. +// - Chromium issue: https://issues.chromium.org/issues/446539520 +// - Rust issue: https://github.com/rust-lang/rust/issues/146816 (function() { document.body.addEventListener("copy", event => { let target = nonnull(event.target); @@ -2248,9 +2255,13 @@ function preLoadCss(cssUrl) { if (!isInsideCode) { return; } - const selection = document.getSelection(); - // @ts-expect-error - nonnull(event.clipboardData).setData("text/plain", selection.toString()); + const selection = nonnull(document.getSelection()); + const text = Array.from({ length: selection.rangeCount }, (_, i) => { + const fragment = selection.getRangeAt(i).cloneContents(); + fragment.querySelectorAll("[data-nosnippet]").forEach(el => el.remove()); + return fragment.textContent; + }).join(""); + nonnull(event.clipboardData).setData("text/plain", text); event.preventDefault(); }); }()); From 465e373542b529055cd1302849f79db13a617a98 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 07:55:43 +0200 Subject: [PATCH 176/537] add regression test --- tests/ui/methods/overflow-if-subtyping.rs | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ui/methods/overflow-if-subtyping.rs diff --git a/tests/ui/methods/overflow-if-subtyping.rs b/tests/ui/methods/overflow-if-subtyping.rs new file mode 100644 index 000000000000..a97f29f1f6df --- /dev/null +++ b/tests/ui/methods/overflow-if-subtyping.rs @@ -0,0 +1,30 @@ +//@ check-pass + +// Regression test for #128887. +#![allow(unconditional_recursion)] +trait Mappable { + type Output; +} + +trait Bound {} +// Deleting this impl made it compile on beta +impl Bound for T {} + +trait Generic {} + +// Deleting the `: Mappable` already made it error on stable. +struct IndexWithIter, T>(I, M, T); + +impl IndexWithIter +where + >::Output: Bound, + // Flipping these where bounds causes this to succeed, even when removing + // the where-clause on the struct definition. + M: Mappable, + I: Generic, +{ + fn new(x: I) { + IndexWithIter::<_, _, _>::new(x); + } +} +fn main() {} From 3c8d8da693eb5d63099eef5cf4a73106a3a2ba25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Sep 2025 09:09:53 +0200 Subject: [PATCH 177/537] Prepare for merging from rust-lang/rust This updates the rust-version file to f6092f224d2b1774b31033f12d0bee626943b02f. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 7333f7968f77..388e88fe43eb 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ec38671075266e9cee0348701da2e133379e7c6c +f6092f224d2b1774b31033f12d0bee626943b02f From c960e9c218e5adac9b61a3cd044d40ebc0cb1ace Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 22 Sep 2025 23:46:40 -0400 Subject: [PATCH 178/537] Remove lower::ty in favor of lower_nextsolver::ty --- .../crates/hir-ty/src/builder.rs | 35 ++++++++------ .../rust-analyzer/crates/hir-ty/src/db.rs | 14 ++---- .../rust-analyzer/crates/hir-ty/src/infer.rs | 46 ++++++++++++++----- .../crates/hir-ty/src/infer/unify.rs | 2 +- .../crates/hir-ty/src/layout/tests.rs | 23 +++++----- .../rust-analyzer/crates/hir-ty/src/lower.rs | 22 --------- .../crates/hir-ty/src/lower/path.rs | 15 ++++-- .../crates/hir-ty/src/method_resolution.rs | 6 ++- .../crates/hir-ty/src/mir/eval/shim.rs | 6 +-- .../crates/hir-ty/src/next_solver/interner.rs | 4 +- .../crates/hir-ty/src/tests/incremental.rs | 2 - .../hir-ty/src/tests/method_resolution.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 23 +++++++--- .../crates/ide/src/view_memory_layout.rs | 4 +- 14 files changed, 112 insertions(+), 92 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 3755175cf516..4957c69ae165 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -3,17 +3,20 @@ use chalk_ir::{ AdtId, DebruijnIndex, Scalar, cast::{Cast, CastTo, Caster}, - fold::TypeFoldable, - interner::HasInterner, }; use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType}; use smallvec::SmallVec; use crate::{ - Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, - Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, consteval::unknown_const_as_generic, - db::HirDatabase, error_lifetime, generics::generics, infer::unify::InferenceTable, primitive, - to_assoc_type_id, to_chalk_trait_id, + BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, + TraitRef, Ty, TyDefId, TyExt, TyKind, + consteval::unknown_const_as_generic, + db::HirDatabase, + error_lifetime, + generics::generics, + infer::unify::InferenceTable, + next_solver::{DbInterner, EarlyBinder, mapping::ChalkToNextSolver}, + primitive, to_assoc_type_id, to_chalk_trait_id, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -345,19 +348,20 @@ impl TyBuilder { } } -impl + TypeFoldable> TyBuilder> { - pub fn build(self) -> T { +impl<'db, T: rustc_type_ir::TypeFoldable>> TyBuilder> { + pub fn build(self, interner: DbInterner<'db>) -> T { let (b, subst) = self.build_internal(); - b.substitute(Interner, &subst) + let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner); + b.instantiate(interner, args) } } -impl TyBuilder> { +impl<'db> TyBuilder>> { pub fn def_ty( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: TyDefId, parent_subst: Option, - ) -> TyBuilder> { + ) -> TyBuilder>> { let poly_ty = db.ty(def); let id: GenericDefId = match def { TyDefId::BuiltinType(_) => { @@ -370,7 +374,10 @@ impl TyBuilder> { TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty) } - pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder> { - TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def)) + pub fn impl_self_ty( + db: &'db dyn HirDatabase, + def: hir_def::ImplId, + ) -> TyBuilder>> { + TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty_ns(def)) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 44f48069ab24..41540f328b23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -114,9 +114,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; - #[salsa::invoke(crate::lower::ty_query)] + #[salsa::invoke(crate::lower_nextsolver::ty_query)] #[salsa::transparent] - fn ty(&self, def: TyDefId) -> Binders; + fn ty<'db>( + &'db self, + def: TyDefId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)] @@ -277,13 +280,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - #[salsa::invoke(crate::lower_nextsolver::ty_query)] - #[salsa::transparent] - fn ty_ns<'db>( - &'db self, - def: TyDefId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; - /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. #[salsa::invoke(crate::lower_nextsolver::value_ty_query)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 3ece62ec35b6..0a095ea64458 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1708,6 +1708,7 @@ impl<'db> InferenceContext<'db> { LifetimeElisionKind::Infer, ); let mut path_ctx = ctx.at_path(path, node); + let interner = DbInterner::conjure(); let (resolution, unresolved) = if value_ns { let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else { return (self.err_ty(), None); @@ -1717,15 +1718,27 @@ impl<'db> InferenceContext<'db> { ValueNs::EnumVariantId(var) => { let substs = path_ctx.substs_from_path(var.into(), true, false); drop(ctx); - let ty = self.db.ty(var.lookup(self.db).parent.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let args: crate::next_solver::GenericArgs<'_> = + substs.to_nextsolver(interner); + let ty = self + .db + .ty(var.lookup(self.db).parent.into()) + .instantiate(interner, args) + .to_chalk(interner); + let ty = self.insert_type_vars(ty); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { let substs = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); - let ty = self.db.ty(strukt.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let args: crate::next_solver::GenericArgs<'_> = + substs.to_nextsolver(interner); + let ty = self + .db + .ty(strukt.into()) + .instantiate(interner, args) + .to_chalk(interner); + let ty = self.insert_type_vars(ty); return (ty, Some(strukt.into())); } ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None), @@ -1746,22 +1759,29 @@ impl<'db> InferenceContext<'db> { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = path_ctx.substs_from_path(strukt.into(), true, false); drop(ctx); - let ty = self.db.ty(strukt.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = self.db.ty(strukt.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.insert_type_vars(ty); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } TypeNs::AdtId(AdtId::UnionId(u)) => { let substs = path_ctx.substs_from_path(u.into(), true, false); drop(ctx); - let ty = self.db.ty(u.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = self.db.ty(u.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.insert_type_vars(ty); forbid_unresolved_segments((ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { let substs = path_ctx.substs_from_path(var.into(), true, false); drop(ctx); - let ty = self.db.ty(var.lookup(self.db).parent.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = self + .db + .ty(var.lookup(self.db).parent.into()) + .instantiate(interner, args) + .to_chalk(interner); + let ty = self.insert_type_vars(ty); forbid_unresolved_segments((ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { @@ -1844,8 +1864,10 @@ impl<'db> InferenceContext<'db> { }; let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false); drop(ctx); - let ty = self.db.ty(it.into()); - let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); + let interner = DbInterner::conjure(); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = self.db.ty(it.into()).instantiate(interner, args).to_chalk(interner); + let ty = self.insert_type_vars(ty); self.resolve_variant_on_alias(ty, unresolved, mod_path) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 6df9cbaa2939..dd7e77ba8c09 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -780,7 +780,7 @@ impl<'db> InferenceTable<'db> { } pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty { - if let TyKind::Alias(..) = ty.kind(Interner) { + if let TyKind::Alias(chalk_ir::AliasTy::Projection(..)) = ty.kind(Interner) { self.structurally_normalize_ty(ty) } else { self.resolve_vars_with_obligations(ty.to_nextsolver(self.interner)) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 523ddad94666..6960e230a685 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -1,18 +1,17 @@ use base_db::target::TargetData; -use chalk_ir::{AdtId, TyKind}; use either::Either; use hir_def::db::DefDatabase; use project_model::{Sysroot, toolchain_info::QueryConfig}; use rustc_hash::FxHashMap; +use rustc_type_ir::inherent::{GenericArgs as _, Ty as _}; use syntax::ToSmolStr; use test_fixture::WithFixture; use triomphe::Arc; use crate::{ - Interner, Substitution, db::HirDatabase, layout::{Layout, LayoutError}, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, + next_solver::{AdtDef, DbInterner, GenericArgs, mapping::ChalkToNextSolver}, setup_tracing, test_db::TestDB, }; @@ -80,18 +79,18 @@ fn eval_goal( Some(adt_or_type_alias_id) }) .unwrap(); - let goal_ty = match adt_or_type_alias_id { - Either::Left(adt_id) => { - TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner) - } - Either::Right(ty_id) => { - db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner)) - } - }; salsa::attach(&db, || { let interner = DbInterner::new_with(&db, None, None); + let goal_ty = match adt_or_type_alias_id { + Either::Left(adt_id) => crate::next_solver::Ty::new_adt( + interner, + AdtDef::new(adt_id, interner), + GenericArgs::identity_for_item(interner, adt_id.into()), + ), + Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(), + }; db.layout_of_ty( - goal_ty.to_nextsolver(interner), + goal_ty, db.trait_environment(match adt_or_type_alias_id { Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 20f421dbbcd9..97005e5d466a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1458,16 +1458,6 @@ fn type_for_enum_variant_constructor( } } -#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)] -fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders { - type_for_adt(db, adt) -} - -fn type_for_adt_cycle_result(db: &dyn HirDatabase, adt: AdtId) -> Binders { - let generics = generics(db, adt.into()); - make_binders(db, &generics, TyKind::Error.intern(Interner)) -} - fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { let generics = generics(db, adt.into()); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); @@ -1547,18 +1537,6 @@ impl ValueTyDefId { } } -/// Build the declared type of an item. This depends on the namespace; e.g. for -/// `struct Foo(usize)`, we have two types: The type of the struct itself, and -/// the constructor function `(usize) -> Foo` which lives in the values -/// namespace. -pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders { - match def { - TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), - TyDefId::AdtId(it) => type_for_adt_tracked(db, it), - TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, - } -} - pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option> { match def { ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index bc03298e3bbb..279bbff7c0d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -28,6 +28,10 @@ use crate::{ error_lifetime, generics::{Generics, generics}, lower::{LifetimeElisionKind, named_associated_type_shorthand_candidates}, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::associated_type_by_name_including_super_traits, }; @@ -256,7 +260,8 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id) .fill_with_bound_vars(self.ctx.in_binders, 0) - .build(), + .build(DbInterner::conjure()) + .to_chalk(DbInterner::conjure()), } } TypeNs::AdtSelfType(adt) => { @@ -267,7 +272,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders) } }; - self.ctx.db.ty(adt.into()).substitute(Interner, &substs) + let interner = DbInterner::conjure(); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner) } TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args), @@ -537,7 +544,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { TyDefId::TypeAliasId(it) => it.into(), }; let substs = self.substs_from_path_segment(generic_def, infer_args, None, false); - self.ctx.db.ty(typeable).substitute(Interner, &substs) + let interner = DbInterner::conjure(); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner) } /// Collect generic arguments from a path into a `Substs`. See also diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index fd28159b49cb..66687490b4a4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -1697,8 +1697,10 @@ fn is_valid_impl_method_candidate( return IsValidCandidate::NotVisible; } let self_ty_matches = table.run_in_snapshot(|table| { - let expected_self_ty = - TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build(); + let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id) + .fill_with_inference_vars(table) + .build(DbInterner::conjure()) + .to_chalk(DbInterner::conjure()); table.unify(&expected_self_ty, self_ty) }); if !self_ty_matches { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index f67778b0f12f..bb0d1f70fbb2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -14,6 +14,7 @@ use hir_expand::name::Name; use intern::{Symbol, sym}; use stdx::never; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ DropGlue, display::DisplayTarget, @@ -1371,9 +1372,8 @@ impl Evaluator<'_> { result = (l as i8).cmp(&(r as i8)); } if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { - let ty = self.db.ty(e.into()); - let r = self - .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?; + let ty = self.db.ty(e.into()).skip_binder().to_chalk(interner); + let r = self.compute_discriminant(ty.clone(), &[result as i8 as u8])?; destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?; Ok(()) } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 9cf56bef9578..6c4212e6ecd4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1091,9 +1091,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ItemContainerId::ImplId(it) => it, _ => panic!("assoc ty value should be in impl"), }; - self.db().ty_ns(id.into()) + self.db().ty(id.into()) } - SolverDefId::AdtId(id) => self.db().ty_ns(id.into()), + SolverDefId::AdtId(id) => self.db().ty(id.into()), // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. // // We currently always use the type from HIR typeck which ignores regions. This diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index c0b930e5e123..0d922de9aeb0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -511,7 +511,6 @@ impl SomeStruct { "struct_signature_shim", "struct_signature_with_source_map_shim", "attrs_shim", - "type_for_adt_tracked", ] "#]], ); @@ -609,7 +608,6 @@ fn main() { "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", - "type_for_adt_tracked", "impl_trait_with_diagnostics_ns_shim", "impl_self_ty_with_diagnostics_ns_shim", "generic_predicates_ns_shim", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index b14ce35aa99c..6a566a505579 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -2053,7 +2053,7 @@ impl dyn Error + Send { // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) - //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> + //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> } } "#, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 862067e5916c..a1d9e6d365f8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1504,7 +1504,7 @@ impl<'db> InstantiatedStruct<'db> { let krate = self.inner.krate(db); let interner = DbInterner::new_with(db, Some(krate.base()), None); - let ty = db.ty_ns(self.inner.id.into()); + let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) } } @@ -1664,7 +1664,7 @@ impl<'db> InstantiatedEnum<'db> { let krate = self.inner.krate(db); let interner = DbInterner::new_with(db, Some(krate.base()), None); - let ty = db.ty_ns(self.inner.id.into()); + let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) } } @@ -1851,7 +1851,8 @@ impl Adt { ParamKind::Lifetime => error_lifetime().cast(Interner), } }) - .build(); + .build(DbInterner::conjure()) + .to_chalk(DbInterner::conjure()); Type::new(db, id, ty) } @@ -4828,32 +4829,40 @@ impl<'db> Type<'db> { } fn from_def(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { + let interner = DbInterner::new_with(db, None, None); let ty = db.ty(def.into()); let substs = TyBuilder::unknown_subst( db, match def.into() { TyDefId::AdtId(it) => GenericDefId::AdtId(it), TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), + TyDefId::BuiltinType(_) => { + return Type::new(db, def, ty.skip_binder().to_chalk(interner)); + } }, ); - Type::new(db, def, ty.substitute(Interner, &substs)) + let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) } fn from_def_placeholders( db: &'db dyn HirDatabase, def: impl Into + HasResolver, ) -> Self { + let interner = DbInterner::new_with(db, None, None); let ty = db.ty(def.into()); let substs = TyBuilder::placeholder_subst( db, match def.into() { TyDefId::AdtId(it) => GenericDefId::AdtId(it), TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), + TyDefId::BuiltinType(_) => { + return Type::new(db, def, ty.skip_binder().to_chalk(interner)); + } }, ); - Type::new(db, def, ty.substitute(Interner, &substs)) + let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) } fn from_value_def( diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 04537f908fbb..ddd58a0a3c9f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -94,8 +94,8 @@ pub(crate) fn view_memory_layout( let def = get_definition(&sema, token)?; let ty = match def { - Definition::Adt(it) => it.ty(db), - Definition::TypeAlias(it) => it.ty(db), + Definition::Adt(it) => salsa::attach(db, || it.ty(db)), + Definition::TypeAlias(it) => salsa::attach(db, || it.ty(db)), Definition::BuiltinType(it) => it.ty(db), Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), From 9e34268e24b753355a96bc9326d8e4e2a2ca916a Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 23 Sep 2025 00:26:28 -0400 Subject: [PATCH 179/537] Remove lower::value_ty in favor of lower_nextsolver::value_ty --- .../rust-analyzer/crates/hir-ty/src/db.rs | 15 +-- .../crates/hir-ty/src/infer/expr.rs | 42 +++++--- .../crates/hir-ty/src/infer/path.rs | 13 ++- .../rust-analyzer/crates/hir-ty/src/lower.rs | 99 +------------------ .../crates/hir-ty/src/next_solver/interner.rs | 6 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 8 +- .../crates/hir/src/source_analyzer.rs | 10 +- .../ide-db/src/syntax_helpers/suggest_name.rs | 2 +- 8 files changed, 61 insertions(+), 134 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 41540f328b23..6eb5f8defaa1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -127,8 +127,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. - #[salsa::invoke(crate::lower::value_ty_query)] - fn value_ty(&self, def: ValueTyDefId) -> Option>; + #[salsa::invoke(crate::lower_nextsolver::value_ty_query)] + fn value_ty<'db>( + &'db self, + def: ValueTyDefId, + ) -> Option>>; #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)] @@ -280,14 +283,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is - /// a `StructId` or `EnumVariantId` with a record constructor. - #[salsa::invoke(crate::lower_nextsolver::value_ty_query)] - fn value_ty_ns<'db>( - &'db self, - def: ValueTyDefId, - ) -> Option>>; - #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] fn type_for_type_alias_with_diagnostics_ns<'db>( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index b4a332f1da84..ddf632c1c81b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -23,13 +23,13 @@ use syntax::ast::RangeOp; use tracing::debug; use crate::autoderef::overloaded_deref_ty; -use crate::next_solver::ErrorGuaranteed; use crate::next_solver::infer::DefineOpaqueTypes; use crate::next_solver::obligation_ctxt::ObligationCtxt; +use crate::next_solver::{DbInterner, ErrorGuaranteed}; use crate::{ - Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext, - DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, - Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval, + Adjust, Adjustment, AdtId, AutoBorrow, CallableDefId, CallableSig, DeclContext, DeclOrigin, + IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution, + TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval, generics::generics, infer::{ AllowTwoPhase, BreakableKind, @@ -1481,7 +1481,10 @@ impl<'db> InferenceContext<'db> { self.write_method_resolution(tgt_expr, func, subst.clone()); - let method_ty = self.db.value_ty(func.into()).unwrap().substitute(Interner, &subst); + let interner = DbInterner::new_with(self.db, None, None); + let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); + let method_ty = + self.db.value_ty(func.into()).unwrap().instantiate(interner, args).to_chalk(interner); self.register_obligations_for_call(&method_ty); self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()), ExprIsRead::Yes); @@ -1800,11 +1803,17 @@ impl<'db> InferenceContext<'db> { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); self.write_method_resolution(tgt_expr, func, substs.clone()); + let interner = DbInterner::new_with(self.db, None, None); + let args: crate::next_solver::GenericArgs<'_> = + substs.to_nextsolver(interner); self.check_method_call( tgt_expr, &[], - self.db.value_ty(func.into()).unwrap(), - substs, + self.db + .value_ty(func.into()) + .unwrap() + .instantiate(interner, args) + .to_chalk(interner), ty, expected, ) @@ -1963,11 +1972,16 @@ impl<'db> InferenceContext<'db> { let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args); self.write_method_resolution(tgt_expr, func, substs.clone()); + let interner = DbInterner::new_with(self.db, None, None); + let gen_args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); self.check_method_call( tgt_expr, args, - self.db.value_ty(func.into()).expect("we have a function def"), - substs, + self.db + .value_ty(func.into()) + .expect("we have a function def") + .instantiate(interner, gen_args) + .to_chalk(interner), ty, expected, ) @@ -2012,11 +2026,15 @@ impl<'db> InferenceContext<'db> { let recovered = match assoc_func_with_same_name { Some(f) => { let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args); + let interner = DbInterner::new_with(self.db, None, None); + let args: crate::next_solver::GenericArgs<'_> = + substs.to_nextsolver(interner); let f = self .db .value_ty(f.into()) .expect("we have a function def") - .substitute(Interner, &substs); + .instantiate(interner, args) + .to_chalk(interner); let sig = f.callable_sig(self.db).expect("we have a function def"); Some((f, sig, true)) } @@ -2056,12 +2074,10 @@ impl<'db> InferenceContext<'db> { &mut self, tgt_expr: ExprId, args: &[ExprId], - method_ty: Binders, - substs: Substitution, + method_ty: Ty, receiver_ty: Ty, expected: &Expectation, ) -> Ty { - let method_ty = method_ty.substitute(Interner, &substs); self.register_obligations_for_call(&method_ty); let interner = self.table.interner; let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 80f7324e58b2..3a50b832cf19 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -17,7 +17,10 @@ use crate::{ generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, method_resolution::{self, VisibleFromModule}, - next_solver::mapping::ChalkToNextSolver, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, to_chalk_trait_id, }; @@ -36,7 +39,9 @@ impl<'db> InferenceContext<'db> { self.add_required_obligations_for_value_path(generic_def, &substs); - let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs); + let interner = DbInterner::new_with(self.db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner); let ty = self.process_remote_user_written_ty(ty); Some(ty) } @@ -89,9 +94,9 @@ impl<'db> InferenceContext<'db> { let generic_def = value_def.to_generic_def_id(self.db); if let GenericDefId::StaticId(_) = generic_def { + let interner = DbInterner::new_with(self.db, None, None); // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type. - let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders(); - stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",); + let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner); return Some(ValuePathResolution::NonGeneric(ty)); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 97005e5d466a..756769a2174f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -30,7 +30,6 @@ use hir_def::{ builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, - item_tree::FieldsShape, lang_item::LangItem, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, @@ -59,7 +58,7 @@ use crate::{ path::{PathDiagnosticCallback, PathLoweringContext}, }, make_binders, - mapping::{ToChalk, from_chalk_trait_id, lt_to_placeholder_idx}, + mapping::{from_chalk_trait_id, lt_to_placeholder_idx}, static_lifetime, to_chalk_trait_id, to_placeholder_idx, utils::all_super_trait_refs, variable_kinds_from_iter, @@ -1352,51 +1351,6 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { make_binders(db, &generics, sig) } -/// Build the declared type of a function. This should not need to look at the -/// function body. -fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders { - let generics = generics(db, def.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner), - ) -} - -/// Build the declared type of a const. -fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { - let data = db.const_signature(def); - let generics = generics(db, def.into()); - let resolver = def.resolver(db); - let parent = def.loc(db).container; - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_const(parent), - ) - .with_type_param_mode(ParamLoweringMode::Variable); - - make_binders(db, &generics, ctx.lower_ty(data.type_ref)) -} - -/// Build the declared type of a static. -fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders { - let data = db.static_signature(def); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::Elided(static_lifetime()), - ); - - Binders::empty(Interner, ctx.lower_ty(data.type_ref)) -} - fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { let field_tys = db.field_types(def.into()); let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); @@ -1407,24 +1361,6 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS ) } -/// Build the type of a tuple struct constructor. -fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option> { - let struct_data = def.fields(db); - match struct_data.shape { - FieldsShape::Record => None, - FieldsShape::Unit => Some(type_for_adt(db, def.into())), - FieldsShape::Tuple => { - let generics = generics(db, AdtId::from(def).into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - Some(make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner), - )) - } - } -} - fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { let field_tys = db.field_types(def.into()); let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); @@ -1436,28 +1372,6 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) ) } -/// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor( - db: &dyn HirDatabase, - def: EnumVariantId, -) -> Option> { - let e = def.lookup(db).parent; - match def.fields(db).shape { - FieldsShape::Record => None, - FieldsShape::Unit => Some(type_for_adt(db, e.into())), - FieldsShape::Tuple => { - let generics = generics(db, e.into()); - let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - Some(make_binders( - db, - &generics, - TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs) - .intern(Interner), - )) - } - } -} - fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { let generics = generics(db, adt.into()); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); @@ -1537,17 +1451,6 @@ impl ValueTyDefId { } } -pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option> { - match def { - ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), - ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), - ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), - ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), - ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), - ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), - } -} - pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { db.impl_self_ty_with_diagnostics(impl_id).0 } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 6c4212e6ecd4..3f61b9f02621 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1099,15 +1099,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { // We currently always use the type from HIR typeck which ignores regions. This // should be fine. SolverDefId::InternedOpaqueTyId(_) => self.type_of_opaque_hir_typeck(def_id), - SolverDefId::FunctionId(id) => self.db.value_ty_ns(id.into()).unwrap(), + SolverDefId::FunctionId(id) => self.db.value_ty(id.into()).unwrap(), SolverDefId::Ctor(id) => { let id = match id { Ctor::Struct(id) => id.into(), Ctor::Enum(id) => id.into(), }; - self.db - .value_ty_ns(id) - .expect("`SolverDefId::Ctor` should have a function-like ctor") + self.db.value_ty(id).expect("`SolverDefId::Ctor` should have a function-like ctor") } _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index a1d9e6d365f8..8b440611e6cc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4872,6 +4872,7 @@ impl<'db> Type<'db> { let Some(ty) = db.value_ty(def.into()) else { return Type::new(db, def, TyKind::Error.intern(Interner)); }; + let interner = DbInterner::new_with(db, None, None); let substs = TyBuilder::unknown_subst( db, match def.into() { @@ -4882,10 +4883,13 @@ impl<'db> Type<'db> { ValueTyDefId::EnumVariantId(it) => { GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) } - ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()), + ValueTyDefId::StaticId(_) => { + return Type::new(db, def, ty.skip_binder().to_chalk(interner)); + } }, ); - Type::new(db, def, ty.substitute(Interner, &substs)) + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner)) } pub fn new_slice(ty: Self) -> Self { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index a19183fa1302..c6b7e84dc20f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -46,6 +46,10 @@ use hir_ty::{ from_assoc_type_id, lang_items::lang_items_for_bin_op, method_resolution, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, }; use intern::sym; use itertools::Itertools; @@ -372,8 +376,10 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let (func, substs) = self.infer()?.method_resolution(expr_id)?; - let ty = db.value_ty(func.into())?.substitute(Interner, &substs); - let ty = Type::new_with_resolver(db, &self.resolver, ty); + let interner = DbInterner::new_with(db, None, None); + let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = db.value_ty(func.into())?.instantiate(interner, args); + let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner)); let mut res = ty.as_callable(db)?; res.is_bound_method = true; Some(res) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 995bf72dca16..2e03665765f3 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -473,7 +473,7 @@ mod tests { frange.range, "selection is not an expression(yet contained in one)" ); - let name = NameGenerator::default().for_variable(&expr, &sema); + let name = salsa::attach(sema.db, || NameGenerator::default().for_variable(&expr, &sema)); assert_eq!(&name, expected); } From bc7986ec791ded521f3f75ab82645b6be0c39508 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 18 Sep 2025 17:09:14 +0200 Subject: [PATCH 180/537] Add attributes for #[global_allocator] functions Emit `#[rustc_allocator]` etc. attributes on the functions generated by the `#[global_allocator]` macro, which will emit LLVM attributes like `"alloc-family"`. If the module with the global allocator participates in LTO, this ensures that the attributes typically emitted on the allocator declarations are not lost if the definition is imported. --- .../src/global_allocator.rs | 16 ++++++-- .../global-allocator-attributes.rs | 41 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/codegen-llvm/global-allocator-attributes.rs diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index f14b1920722f..96bece2a368c 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> { body, define_opaque: None, })); - let item = self.cx.item(self.span, self.attrs(), kind); + let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) } @@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> { self.cx.expr_call(self.ty_span, method, args) } - fn attrs(&self) -> AttrVec { - thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] + fn attrs(&self, method: &AllocatorMethod) -> AttrVec { + let alloc_attr = match method.name { + sym::alloc => sym::rustc_allocator, + sym::dealloc => sym::rustc_deallocator, + sym::realloc => sym::rustc_reallocator, + sym::alloc_zeroed => sym::rustc_allocator_zeroed, + _ => unreachable!("Unknown allocator method!"), + }; + thin_vec![ + self.cx.attr_word(sym::rustc_std_internal_symbol, self.span), + self.cx.attr_word(alloc_attr, self.span) + ] } fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec) -> Box { diff --git a/tests/codegen-llvm/global-allocator-attributes.rs b/tests/codegen-llvm/global-allocator-attributes.rs new file mode 100644 index 000000000000..472ca7720750 --- /dev/null +++ b/tests/codegen-llvm/global-allocator-attributes.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] + +mod foobar { + use std::alloc::{GlobalAlloc, Layout}; + + struct Allocator; + + unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_alloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,uninitialized,aligned") allocsize(0){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc(i[[SIZE:[0-9]+]] {{.*}}%size, i[[SIZE]] allocalign{{.*}} %align) + panic!() + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // CHECK-LABEL: ; __rustc::__rust_dealloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("free"){{.*}} + // CHECK-NEXT: define{{.*}} void @{{.*}}__rust_dealloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] {{.*}} %align) + panic!() + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_realloc + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("realloc,aligned") allocsize(3){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_realloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align, i[[SIZE]] {{.*}} %new_size) + panic!() + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // CHECK-LABEL: ; __rustc::__rust_alloc_zeroed + // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,zeroed,aligned") allocsize(0){{.*}} + // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc_zeroed(i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align) + panic!() + } + } + + #[global_allocator] + static GLOBAL: Allocator = Allocator; +} From a025cacc600fe1848db29cdaf199ac2d33f83181 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Wed, 17 Sep 2025 21:19:53 +0200 Subject: [PATCH 181/537] Expose iterators over an inference result's types (This re-introduces a reduced access to a couple of previously public fields on `InferenceResult`) --- .../rust-analyzer/crates/hir-ty/src/infer.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 3ece62ec35b6..b5e9aece364c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -632,6 +632,26 @@ impl InferenceResult { pub fn binding_mode(&self, id: PatId) -> Option { self.binding_modes.get(id).copied() } + + // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. + pub fn expression_types(&self) -> impl Iterator { + self.type_of_expr.iter() + } + + // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. + pub fn pattern_types(&self) -> impl Iterator { + self.type_of_pat.iter() + } + + // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. + pub fn binding_types(&self) -> impl Iterator { + self.type_of_binding.iter() + } + + // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. + pub fn return_position_impl_trait_types(&self) -> impl Iterator { + self.type_of_rpit.iter() + } } impl Index for InferenceResult { From ffca2f0a1e5366221c3b81925089e4fa14cd3a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 23 Sep 2025 11:39:40 +0200 Subject: [PATCH 182/537] Make it possible to `x install` Cranelift and LLVM bitcode linker --- src/bootstrap/src/core/builder/mod.rs | 2 ++ src/bootstrap/src/core/builder/tests.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8226b4325b6b..10587b02c716 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1221,6 +1221,8 @@ impl<'a> Builder<'a> { install::Miri, install::LlvmTools, install::Src, + install::RustcCodegenCranelift, + install::LlvmBitcodeLinker ), Kind::Run => describe!( run::BuildManifest, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 229adf714598..87bea431a058 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2911,6 +2911,9 @@ mod snapshot { [build] rustc 1 -> cargo-miri 2 [dist] rustc 1 -> miri 2 [dist] src <> + [build] rustc 1 -> rustc_codegen_cranelift 2 + [dist] rustc 1 -> rustc_codegen_cranelift 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 "); } From 739e89980f2c5602851c9271fd61f7381007e87a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 11 Jun 2025 11:32:57 +0000 Subject: [PATCH 183/537] Add proper name mangling for pattern types --- compiler/rustc_symbol_mangling/src/v0.rs | 14 +++++------ src/doc/rustc/src/symbol-mangling/v0.md | 28 ++++++++++++++++++++++ tests/codegen-llvm/pattern_type_symbols.rs | 4 ++-- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 9fa7e2f10039..d24924b424a5 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> { fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> { Ok(match *pat { ty::PatternKind::Range { start, end } => { - let consts = [start, end]; - for ct in consts { - Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?; - } + self.push("R"); + self.print_const(start)?; + self.print_const(end)?; } ty::PatternKind::Or(patterns) => { + self.push("O"); for pat in patterns { self.print_pat(pat)?; } + self.push("E"); } }) } @@ -498,12 +499,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { } ty::Pat(ty, pat) => { - // HACK: Represent as tuple until we have something better. - // HACK: constants are used in arrays, even if the types don't match. - self.push("T"); + self.push("W"); ty.print(self)?; self.print_pat(pat)?; - self.push("E"); } ty::Array(ty, len) => { diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md index 109942518fc9..2bcc453a5326 100644 --- a/src/doc/rustc/src/symbol-mangling/v0.md +++ b/src/doc/rustc/src/symbol-mangling/v0.md @@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re [mut-ptr-type]: #mut-ptr-type [fn-type]: #fn-type [dyn-trait-type]: #dyn-trait-type +[pattern-type]: #pattern-type > type → \ >       *[basic-type]* \ @@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re >    | *[mut-ptr-type]* \ >    | *[fn-type]* \ >    | *[dyn-trait-type]* \ +>    | *[pattern-type]* \ >    | *[path]* \ >    | *[backref]* @@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`. [fn-sig]: #fn-sig [abi]: #abi +* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`. + > pattern-type → `W` *[pattern-kind]* + > + > pattern-kind → \ + >       *[range-pattern-kind]* \ + >    *[or-pattern-kind]* + > + > range-pattern-kind → `R` *[const]* *[const]* + > + > or-pattern-kind → `O` *[pattern-kind]* `E` + + While or patterns can be nested in theory, in practice this does not happen and they are instead flattened. + + Range patterns have a start and end constant that are both included in the range. + The end must be larger than the start (there can be no wraparound). To emulate wraparound, + you need to use an or pattern of the two ranges to the upper limit and from the lower limit. + * `D` — A [trait object][reference-trait-object] `dyn Trait + Send + 'a`. > dyn-trait-type → `D` *[dyn-bounds]* *[lifetime]* @@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar. >    | *[mut-ptr-type]* \ >    | *[fn-type]* \ >    | *[dyn-trait-type]* \ +>    | *[pattern-type]* \ >    | *[path]* \ >    | *[backref]* > @@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar. > [mut-ptr-type] → `O` *[type]* \ > [fn-type] → `F` *[fn-sig]* \ > [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]* +> [pattern-type] → `W` *[pattern-kind]* +> +> [pattern-kind] → \ +>       *[range-pattern-kind]* \ +>    *[or-pattern-kind]* +> +> [range-pattern-kind] -> `R` *[const]* *[const]* \ +> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \ > > [namespace] → *[lower]* | *[upper]* > diff --git a/tests/codegen-llvm/pattern_type_symbols.rs b/tests/codegen-llvm/pattern_type_symbols.rs index e86a9ef27de1..a90262ff12d2 100644 --- a/tests/codegen-llvm/pattern_type_symbols.rs +++ b/tests/codegen-llvm/pattern_type_symbols.rs @@ -16,7 +16,7 @@ pub fn bar() { // CHECK: call pattern_type_symbols::foo:: // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_ foo::(); - // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])> - // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_ + // CHECK: call pattern_type_symbols::foo:: + // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooWmRm0_m3b9ac9ff_EB2_ foo::(); } From 08020def99d2851af0dabde12cc6d203017fa72c Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Wed, 10 Sep 2025 15:40:27 +0100 Subject: [PATCH 184/537] Changes some aarch64 CIs g++ install & ubuntu ver. GCS support was added to GCC in version 15, thus the rmake test for this patch requires GCC15 Similarly, the ubuntu version is updated so the newer clang version is available, and/or GCC15 is the default. --- src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile | 2 +- src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile | 2 +- src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile index 71de8f917fa2..04b46226acfa 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile index adbb1f03378a..095624d6fb71 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:25.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index e6133fce83e2..4b61fd94a6cf 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:25.10 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ From 58c7505d868515eb55971cf1ad8744c81d5ea7d2 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 00:34:05 +0300 Subject: [PATCH 185/537] Make `render_example_with_highlighting` return an `impl fmt::Display` --- src/librustdoc/html/highlight.rs | 116 ++++++++++++++----------------- src/librustdoc/html/markdown.rs | 17 +++-- 2 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 0e06361024b9..3ddfb3470f2f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -8,6 +8,7 @@ use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display, Write}; +use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; @@ -15,8 +16,9 @@ use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, DUMMY_SP, Span}; -use super::format::{self, write_str}; +use super::format; use crate::clean::PrimitiveType; +use crate::display::Joined as _; use crate::html::escape::EscapeBodyText; use crate::html::macro_expansion::ExpandedCode; use crate::html::render::{Context, LinkFromSrc}; @@ -51,26 +53,26 @@ pub(crate) enum Tooltip { /// Highlights `src` as an inline example, returning the HTML output. pub(crate) fn render_example_with_highlighting( src: &str, - out: &mut String, - tooltip: Tooltip, + tooltip: &Tooltip, playground_button: Option<&str>, extra_classes: &[String], -) { - write_header(out, "rust-example-rendered", None, tooltip, extra_classes); - write_code(out, src, None, None, None); - write_footer(out, playground_button); +) -> impl Display { + fmt::from_fn(move |f| { + write_header("rust-example-rendered", None, tooltip, extra_classes).fmt(f)?; + write_code(f, src, None, None, None); + write_footer(playground_button).fmt(f) + }) } fn write_header( - out: &mut String, class: &str, extra_content: Option<&str>, - tooltip: Tooltip, + tooltip: &Tooltip, extra_classes: &[String], -) { - write_str( - out, - format_args!( +) -> impl Display { + fmt::from_fn(move |f| { + write!( + f, "", playground_button.unwrap_or_default())); +fn write_footer(playground_button: Option<&str>) -> impl Display { + fmt::from_fn(move |f| write!(f, "{}", playground_button.unwrap_or_default())) } /// How a span of text is classified. Mostly corresponds to token kinds. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4addf2c3c964..46923d1f6982 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -337,15 +337,14 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { // insert newline to clearly separate it from the // previous block so we can shorten the html output - let mut s = String::new(); - s.push('\n'); - - highlight::render_example_with_highlighting( - &text, - &mut s, - tooltip, - playground_button.as_deref(), - &added_classes, + let s = format!( + "\n{}", + highlight::render_example_with_highlighting( + &text, + &tooltip, + playground_button.as_deref(), + &added_classes, + ) ); Some(Event::Html(s.into())) } From aaff372f4b45f88dc3b28fe3c1c8ec22cb3b3411 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 01:04:04 +0300 Subject: [PATCH 186/537] Remove `Tooltip::None` variant, use `Option::None` --- src/librustdoc/html/highlight.rs | 23 +++++++++++------------ src/librustdoc/html/markdown.rs | 30 +++++++++++++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 3ddfb3470f2f..b1257999c070 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -47,13 +47,12 @@ pub(crate) enum Tooltip { CompileFail, ShouldPanic, Edition(Edition), - None, } /// Highlights `src` as an inline example, returning the HTML output. pub(crate) fn render_example_with_highlighting( src: &str, - tooltip: &Tooltip, + tooltip: Option<&Tooltip>, playground_button: Option<&str>, extra_classes: &[String], ) -> impl Display { @@ -67,23 +66,24 @@ pub(crate) fn render_example_with_highlighting( fn write_header( class: &str, extra_content: Option<&str>, - tooltip: &Tooltip, + tooltip: Option<&Tooltip>, extra_classes: &[String], ) -> impl Display { fmt::from_fn(move |f| { write!( f, "
", - match tooltip { - Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", - Tooltip::CompileFail => " compile_fail", - Tooltip::ShouldPanic => " should_panic", - Tooltip::Edition(_) => " edition", - Tooltip::None => "", - } + tooltip + .map(|tooltip| match tooltip { + Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + }) + .unwrap_or_default() )?; - if *tooltip != Tooltip::None { + if let Some(tooltip) = tooltip { let tooltip = fmt::from_fn(|f| match tooltip { Tooltip::IgnoreAll => f.write_str("This example is not tested"), Tooltip::IgnoreSome(platforms) => { @@ -104,7 +104,6 @@ fn write_header( Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), Tooltip::ShouldPanic => f.write_str("This example panics"), Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), - Tooltip::None => unreachable!(), }); write!(f, "")?; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 46923d1f6982..7065de14c8ea 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -321,18 +321,22 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { )) }); - let tooltip = if ignore == Ignore::All { - highlight::Tooltip::IgnoreAll - } else if let Ignore::Some(platforms) = ignore { - highlight::Tooltip::IgnoreSome(platforms) - } else if compile_fail { - highlight::Tooltip::CompileFail - } else if should_panic { - highlight::Tooltip::ShouldPanic - } else if explicit_edition { - highlight::Tooltip::Edition(edition) - } else { - highlight::Tooltip::None + let tooltip = { + use highlight::Tooltip::*; + + if ignore == Ignore::All { + Some(IgnoreAll) + } else if let Ignore::Some(platforms) = ignore { + Some(IgnoreSome(platforms)) + } else if compile_fail { + Some(CompileFail) + } else if should_panic { + Some(ShouldPanic) + } else if explicit_edition { + Some(Edition(edition)) + } else { + None + } }; // insert newline to clearly separate it from the @@ -341,7 +345,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { "\n{}", highlight::render_example_with_highlighting( &text, - &tooltip, + tooltip.as_ref(), playground_button.as_deref(), &added_classes, ) From e697f206fe4eba49f8984ef2d436bc0cd19ff8fc Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 01:04:14 +0300 Subject: [PATCH 187/537] Remove unused param from `write_header` --- src/librustdoc/html/highlight.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index b1257999c070..fe2b2fc60312 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -57,18 +57,13 @@ pub(crate) fn render_example_with_highlighting( extra_classes: &[String], ) -> impl Display { fmt::from_fn(move |f| { - write_header("rust-example-rendered", None, tooltip, extra_classes).fmt(f)?; + write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?; write_code(f, src, None, None, None); write_footer(playground_button).fmt(f) }) } -fn write_header( - class: &str, - extra_content: Option<&str>, - tooltip: Option<&Tooltip>, - extra_classes: &[String], -) -> impl Display { +fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display { fmt::from_fn(move |f| { write!( f, @@ -109,10 +104,6 @@ fn write_header( write!(f, "")?; } - if let Some(extra) = extra_content { - f.write_str(extra)?; - } - let classes = fmt::from_fn(|f| { iter::once("rust") .chain(Some(class).filter(|class| !class.is_empty())) From 4fcafc9daad24e5811546896b80e4e18578bf9f3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 08:25:07 +0200 Subject: [PATCH 188/537] yeet fastpath --- compiler/rustc_trait_selection/src/infer.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 4c50c44b8418..cd076d1cb692 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -9,7 +9,7 @@ use rustc_middle::infer::canonical::{ Canonical, CanonicalQueryInput, CanonicalQueryResponse, QueryResponse, }; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, Upcast}; use rustc_span::DUMMY_SP; use tracing::instrument; @@ -31,19 +31,7 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - - // FIXME(#132279): This should be removed as it causes us to incorrectly - // handle opaques in their defining scope, and stalled coroutines. - if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() { - return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); - } - let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); - - // This can get called from typeck (by euv), and `moves_by_default` - // rightly refuses to work with inference variables, but - // moves_by_default has a cache, which we want to use in other - // cases. traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } From 83532f8544e18dfc2025ab33e7c01fb27865667f Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 17:08:29 +0200 Subject: [PATCH 189/537] remove test for no_core --- .../missing-copy-lang-item-issue-19660.rs | 19 ------------------- .../missing-copy-lang-item-issue-19660.stderr | 8 -------- 2 files changed, 27 deletions(-) delete mode 100644 tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs delete mode 100644 tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs deleted file mode 100644 index 35d5d079c689..000000000000 --- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(lang_items, no_core)] -#![no_core] -#![no_main] - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -trait Sized: MetaSized { } - -struct S; - -#[no_mangle] -extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { - argc //~ ERROR requires `copy` lang_item -} diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr deleted file mode 100644 index 7b9541f734fa..000000000000 --- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: requires `copy` lang_item - --> $DIR/missing-copy-lang-item-issue-19660.rs:18:5 - | -LL | argc - | ^^^^ - -error: aborting due to 1 previous error - From af1b14bb9b1b3d301c1e8e0a989d814deaf054c9 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 23 Sep 2025 17:13:35 +0200 Subject: [PATCH 190/537] std: move WinSock abstractions to `sys::pal` --- .../src/sys/net/connection/socket/windows.rs | 80 +------------------ library/std/src/sys/pal/windows/mod.rs | 1 + library/std/src/sys/pal/windows/winsock.rs | 80 +++++++++++++++++++ 3 files changed, 84 insertions(+), 77 deletions(-) create mode 100644 library/std/src/sys/pal/windows/winsock.rs diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index b71d8b1357b5..5b6f4cedf1b7 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -8,9 +8,8 @@ use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; -use crate::sync::atomic::Atomic; -use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; use crate::sys::c; +use crate::sys::pal::winsock::last_error; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{cmp, mem, ptr, sys}; @@ -112,84 +111,11 @@ pub(super) mod netc { } } +pub use crate::sys::pal::winsock::{cleanup, cvt, cvt_gai, cvt_r, startup as init}; + #[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); -static WSA_INITIALIZED: Atomic = Atomic::::new(false); - -/// Checks whether the Windows socket interface has been started already, and -/// if not, starts it. -#[inline] -pub fn init() { - if !WSA_INITIALIZED.load(Relaxed) { - wsa_startup(); - } -} - -#[cold] -fn wsa_startup() { - unsafe { - let mut data: c::WSADATA = mem::zeroed(); - let ret = c::WSAStartup( - 0x202, // version 2.2 - &mut data, - ); - assert_eq!(ret, 0); - if WSA_INITIALIZED.swap(true, AcqRel) { - // If another thread raced with us and called WSAStartup first then call - // WSACleanup so it's as though WSAStartup was only called once. - c::WSACleanup(); - } - } -} - -pub fn cleanup() { - // We don't need to call WSACleanup here because exiting the process will cause - // the OS to clean everything for us, which is faster than doing it manually. - // See #141799. -} - -/// Returns the last error from the Windows socket interface. -fn last_error() -> io::Error { - io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) -} - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i8 i16 i32 i64 isize } - -/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) -/// and if so, returns the last error from the Windows socket interface. This -/// function must be called before another call to the socket API is made. -pub fn cvt(t: T) -> io::Result { - if t.is_minus_one() { Err(last_error()) } else { Ok(t) } -} - -/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { Ok(()) } else { Err(last_error()) } -} - -/// Just to provide the same interface as sys/pal/unix/net.rs -pub fn cvt_r(mut f: F) -> io::Result -where - T: IsMinusOne, - F: FnMut() -> T, -{ - cvt(f()) -} - impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { let family = match *addr { diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3357946b8f71..85a4d3ca6db2 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -30,6 +30,7 @@ cfg_select! { pub use self::stack_overflow_uwp as stack_overflow; } } +pub mod winsock; /// Map a [`Result`] to [`io::Result`](crate::io::Result). pub trait IoResult { diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs new file mode 100644 index 000000000000..b110a43ef3aa --- /dev/null +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -0,0 +1,80 @@ +use super::c; +use crate::ffi::c_int; +use crate::sync::atomic::Atomic; +use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; +use crate::{io, mem}; + +static WSA_STARTED: Atomic = Atomic::::new(false); + +/// Checks whether the Windows socket interface has been started already, and +/// if not, starts it. +#[inline] +pub fn startup() { + if !WSA_STARTED.load(Relaxed) { + wsa_startup(); + } +} + +#[cold] +fn wsa_startup() { + unsafe { + let mut data: c::WSADATA = mem::zeroed(); + let ret = c::WSAStartup( + 0x202, // version 2.2 + &mut data, + ); + assert_eq!(ret, 0); + if WSA_STARTED.swap(true, AcqRel) { + // If another thread raced with us and called WSAStartup first then call + // WSACleanup so it's as though WSAStartup was only called once. + c::WSACleanup(); + } + } +} + +pub fn cleanup() { + // We don't need to call WSACleanup here because exiting the process will cause + // the OS to clean everything for us, which is faster than doing it manually. + // See #141799. +} + +/// Returns the last error from the Windows socket interface. +pub fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) +/// and if so, returns the last error from the Windows socket interface. This +/// function must be called before another call to the socket API is made. +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(last_error()) } else { Ok(t) } +} + +/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { Ok(()) } else { Err(last_error()) } +} + +/// Just to provide the same interface as sys/pal/unix/net.rs +pub fn cvt_r(mut f: F) -> io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + cvt(f()) +} From 42cf78f762ecad22de89d914904887afc073278f Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 22 Sep 2025 15:44:30 -0400 Subject: [PATCH 191/537] llvm: update remarks support on LLVM 22 LLVM change dfbd76bda01e removed separate remark support entirely, but it turns out we can just drop the parameter and everything appears to work fine. Fixes 146912 as far as I can tell (the test passes.) @rustbot label llvm-main --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 414274f24fb5..ef85ce153b88 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1779,9 +1779,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( // Do not delete the file after we gather remarks RemarkFile->keep(); +#if LLVM_VERSION_GE(22, 0) + auto RemarkSerializer = remarks::createRemarkSerializer( + llvm::remarks::Format::YAML, RemarkFile->os()); +#else auto RemarkSerializer = remarks::createRemarkSerializer( llvm::remarks::Format::YAML, remarks::SerializerMode::Separate, RemarkFile->os()); +#endif if (Error E = RemarkSerializer.takeError()) { std::string Error = std::string("Cannot create remark serializer: ") + toString(std::move(E)); From 60b35635e8084be2e4f8b55f170e8665edb8e275 Mon Sep 17 00:00:00 2001 From: ash Date: Tue, 23 Sep 2025 12:37:59 -0600 Subject: [PATCH 192/537] revert change removing `has_infer` check. Commit conservatively patches for now, but more development proceeding. Also contains a more concise test --- compiler/rustc_middle/src/ty/util.rs | 11 ++++++++++- tests/ui/type-inference/box_has_sigdrop.rs | 9 +++++++++ tests/ui/type-inference/box_has_sigdrop.stderr | 17 +++++++++++++++++ .../{has_sigdrop.rs => dropper_has_sigdrop.rs} | 0 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/ui/type-inference/box_has_sigdrop.rs create mode 100644 tests/ui/type-inference/box_has_sigdrop.stderr rename tests/ui/type-inference/{has_sigdrop.rs => dropper_has_sigdrop.rs} (100%) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4f039381e500..a4422abc6883 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1368,7 +1368,6 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { - assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1381,6 +1380,16 @@ impl<'tcx> Ty<'tcx> { _ => self, }; + // FIXME + // We should be canonicalizing, or else moving this to a method of inference + // context, or *something* like that, + // but for now just avoid passing inference variables + // to queries that can't cope with them. + // Instead, conservatively return "true" (may change drop order). + if query_ty.has_infer() { + return true; + } + // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/tests/ui/type-inference/box_has_sigdrop.rs b/tests/ui/type-inference/box_has_sigdrop.rs new file mode 100644 index 000000000000..3e801197a78e --- /dev/null +++ b/tests/ui/type-inference/box_has_sigdrop.rs @@ -0,0 +1,9 @@ +//@ should-fail +//@ compile-flags: -Wrust-2021-incompatible-closure-captures +// Inference, canonicalization, and significant drops should work nicely together. +// Related issue: #86868 + +fn main() { + let mut state = 0; + Box::new(move || state) +} diff --git a/tests/ui/type-inference/box_has_sigdrop.stderr b/tests/ui/type-inference/box_has_sigdrop.stderr new file mode 100644 index 000000000000..b61b6322c107 --- /dev/null +++ b/tests/ui/type-inference/box_has_sigdrop.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/box_has_sigdrop.rs:8:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | let mut state = 0; +LL | Box::new(move || state) + | ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `Box<{closure@box_has_sigdrop.rs:8:14}>` + | + = note: expected unit type `()` + found struct `Box<{closure@$DIR/box_has_sigdrop.rs:8:14: 8:21}>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/dropper_has_sigdrop.rs similarity index 100% rename from tests/ui/type-inference/has_sigdrop.rs rename to tests/ui/type-inference/dropper_has_sigdrop.rs From 489f0179e789620c1b94b2451749a4d1ed7b80f4 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 23 Sep 2025 02:51:21 -0400 Subject: [PATCH 193/537] Use lower_nextsolver::callable_item_signature instead of lower::callable_item_signature --- .../rust-analyzer/crates/hir-ty/src/db.rs | 17 ++-- .../crates/hir-ty/src/display.rs | 6 +- .../crates/hir-ty/src/dyn_compatibility.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 90 ++----------------- .../crates/hir-ty/src/method_resolution.rs | 15 +++- .../crates/hir-ty/src/mir/lower.rs | 14 ++- .../crates/hir-ty/src/next_solver/interner.rs | 2 +- .../crates/hir-ty/src/next_solver/mapping.rs | 45 ++++++++++ .../hir-ty/src/tests/method_resolution.rs | 2 +- .../crates/hir-ty/src/tests/traits.rs | 14 +-- .../crates/hir-ty/src/variance.rs | 19 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 80 ++++++++++++++--- .../ide-completion/src/context/analysis.rs | 13 ++- .../crates/ide/src/inlay_hints/bind_pat.rs | 2 +- .../crates/ide/src/signature_help.rs | 4 +- 16 files changed, 188 insertions(+), 141 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 6eb5f8defaa1..84c6c0471b5b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -16,8 +16,8 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Binders, Const, ImplTraitId, ImplTraits, InferenceResult, PolyFnSig, Substitution, - TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db, + Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, + TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db, consteval::ConstEvalError, drop::DropGlue, dyn_compatibility::DynCompatibilityViolation, @@ -167,8 +167,11 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::transparent] fn field_types(&self, var: VariantId) -> Arc>>; - #[salsa::invoke(crate::lower::callable_item_signature_query)] - fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; + #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)] + fn callable_item_signature<'db>( + &'db self, + def: CallableDefId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>; #[salsa::invoke(crate::lower::return_type_impl_traits)] fn return_type_impl_traits(&self, def: FunctionId) -> Option>>; @@ -354,12 +357,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { ArenaMap>>, >; - #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)] - fn callable_item_signature_ns<'db>( - &'db self, - def: CallableDefId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>; - #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)] fn return_type_impl_traits_ns<'db>( &'db self, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index dc42304e1cab..e11ce51cdb8f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -46,8 +46,8 @@ use span::Edition; use stdx::never; use triomphe::Arc; -use crate::next_solver::infer::DbInternerInferExt; use crate::next_solver::infer::traits::ObligationCause; +use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk}; use crate::{ AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, @@ -1298,7 +1298,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { let def = def.0; let sig = db .callable_item_signature(def) - .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); if f.display_kind.is_source_code() { // `FnDef` is anonymous and there's no surface syntax for it. Show it as a diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index b87c99821774..f033c511acd6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -329,7 +329,7 @@ where cb(MethodViolationCode::AsyncFn)?; } - let sig = db.callable_item_signature_ns(func.into()); + let sig = db.callable_item_signature(func.into()); if sig .skip_binder() .inputs() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 05c5a7a28b9a..c2acfc4142e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -578,8 +578,10 @@ impl CallableSig { pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { let callable_def = ToChalk::from_chalk(db, def); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); let sig = db.callable_item_signature(callable_def); - sig.substitute(Interner, substs) + sig.instantiate(interner, args).skip_binder().to_chalk(interner) } pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { CallableSig { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 756769a2174f..598fd38b4b8e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -24,9 +24,9 @@ use chalk_ir::{ use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, - GenericDefId, GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, - StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, + GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, + TypeOrConstParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, @@ -45,10 +45,10 @@ use stdx::{impl_from, never}; use triomphe::{Arc, ThinArc}; use crate::{ - AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, - FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, - LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, - TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, all_super_traits, + AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, + ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives, + QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty, + TyBuilder, TyKind, WhereClause, all_super_traits, consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, @@ -824,15 +824,6 @@ impl<'a> TyLoweringContext<'a> { } } -/// Build the signature of a callable item (function, struct or enum variant). -pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { - match def { - CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), - CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), - CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), - } -} - fn named_associated_type_shorthand_candidates( db: &dyn HirDatabase, // If the type parameter is defined in an impl and we're in a method, there @@ -1312,73 +1303,6 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result( (GenericDefaults(None), None) } -fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { - let data = db.function_signature(def); - let resolver = def.resolver(db); - let mut ctx_params = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_fn_params(&data), - ) - .with_type_param_mode(ParamLoweringMode::Variable); - let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); - - let ret = match data.ret_type { - Some(ret_type) => { - let mut ctx_ret = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_fn_ret(), - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - ctx_ret.lower_ty(ret_type) - } - None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), - }; - let generics = generics(db, def.into()); - let sig = CallableSig::from_params_and_return( - params, - ret, - data.is_varargs(), - if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, - data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), - ); - make_binders(db, &generics, sig) -} - -fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { - let field_tys = db.field_types(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); - let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); - Binders::new( - binders, - CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall), - ) -} - -fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { - let field_tys = db.field_types(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); - let parent = def.lookup(db).parent; - let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders(); - Binders::new( - binders, - CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall), - ) -} - -fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { - let generics = generics(db, adt.into()); - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner); - make_binders(db, &generics, ty) -} - pub(crate) fn type_for_type_alias_with_diagnostics_query( db: &dyn HirDatabase, t: TypeAliasId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 66687490b4a4..93ef64272d14 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -1746,9 +1746,13 @@ fn is_valid_trait_method_candidate( .fill_with_inference_vars(table) .build(); + let args: crate::next_solver::GenericArgs<'_> = + fn_subst.to_nextsolver(table.interner); let sig = db.callable_item_signature(fn_id.into()); - let expected_receiver = - sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst); + let expected_receiver = sig + .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0]) + .instantiate(table.interner, args) + .to_chalk(table.interner); // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext` let variance = match mode { @@ -1833,9 +1837,12 @@ fn is_valid_impl_fn_candidate( let fn_subst: crate::Substitution = table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner); + let args: crate::next_solver::GenericArgs<'_> = fn_subst.to_nextsolver(table.interner); let sig = db.callable_item_signature(fn_id.into()); - let expected_receiver = - sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst); + let expected_receiver = sig + .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0]) + .instantiate(table.interner, args) + .to_chalk(table.interner); check_that!(table.unify(receiver_ty, &expected_receiver)); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 0416f4315d4d..3e44e8c68dda 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -43,7 +43,10 @@ use crate::{ Terminator, TerminatorKind, TupleFieldId, Ty, UnOp, VariantId, intern_const_scalar, return_slot, }, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, static_lifetime, traits::FnTrait, utils::ClosureSubst, @@ -2207,8 +2210,13 @@ pub fn lower_to_mir( // otherwise it's an inline const, and has no parameter if let DefWithBodyId::FunctionId(fid) = owner { let substs = TyBuilder::placeholder_subst(db, fid); - let callable_sig = - db.callable_item_signature(fid.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(fid.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let mut params = callable_sig.params().iter(); let self_param = body.self_param.and_then(|id| Some((id, params.next()?.clone()))); break 'b ctx.lower_params_and_bindings( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 3f61b9f02621..1a14ac9a7457 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1225,7 +1225,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::FunctionId, ) -> EarlyBinder>> { - self.db().callable_item_signature_ns(def_id.0) + self.db().callable_item_signature(def_id.0) } fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs index 5dcb1e62329d..f3f74f67c04d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs @@ -575,6 +575,17 @@ impl< } } +impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner> + NextSolverToChalk<'db, chalk_ir::Binders> for rustc_type_ir::Binder, T> +{ + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders { + chalk_ir::Binders::new( + self.bound_vars().to_chalk(interner), + self.skip_binder().to_chalk(interner), + ) + } +} + impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds { fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds { BoundVarKinds::new_from_iter( @@ -584,6 +595,12 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds NextSolverToChalk<'db, chalk_ir::VariableKinds> for BoundVarKinds { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds { + chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner))) + } +} + impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind { fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind { match self { @@ -594,6 +611,18 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind NextSolverToChalk<'db, chalk_ir::VariableKind> for BoundVarKind { + fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind { + match self { + BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), + BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime, + BoundVarKind::Const => { + chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)) + } + } + } +} + impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg { fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> { match self.data(Interner) { @@ -1233,6 +1262,22 @@ where } } +impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig> { + fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig { + crate::CallableSig { + abi: self.abi, + is_varargs: self.c_variadic, + safety: match self.safety { + super::abi::Safety::Safe => chalk_ir::Safety::Safe, + super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, + }, + params_and_return: triomphe::Arc::from_iter( + self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)), + ), + } + } +} + pub fn convert_canonical_args_for_result<'db>( interner: DbInterner<'db>, args: Canonical<'db, Vec>>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 6a566a505579..5ada14bc5342 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -2053,7 +2053,7 @@ impl dyn Error + Send { // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) - //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> + //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> } } "#, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 41f8d4ed555f..66faac09cc29 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1487,8 +1487,8 @@ fn test(x: Box>, y: &dyn Trait) { 268..269 'x': Box + '?> 275..276 'y': &'? (dyn Trait + '?) 286..287 'z': Box + '?> - 290..293 'bar': fn bar() -> Box + '?> - 290..295 'bar()': Box + '?> + 290..293 'bar': fn bar() -> Box + 'static> + 290..295 'bar()': Box + 'static> 301..302 'x': Box + '?> 301..308 'x.foo()': u64 314..315 'y': &'? (dyn Trait + '?) @@ -1535,7 +1535,7 @@ fn test(s: S) { 251..252 's': S 267..289 '{ ...z(); }': () 273..274 's': S - 273..280 's.bar()': &'? (dyn Trait + '?) + 273..280 's.bar()': &'? (dyn Trait + 'static) 273..286 's.bar().baz()': (u32, i32) "#]], ); @@ -1568,8 +1568,8 @@ fn test(x: Trait, y: &Trait) -> u64 { 106..107 'x': dyn Trait + '? 113..114 'y': &'? (dyn Trait + '?) 124..125 'z': dyn Trait + '? - 128..131 'bar': fn bar() -> dyn Trait + '? - 128..133 'bar()': dyn Trait + '? + 128..131 'bar': fn bar() -> dyn Trait + 'static + 128..133 'bar()': dyn Trait + 'static 139..140 'x': dyn Trait + '? 139..146 'x.foo()': u64 152..153 'y': &'? (dyn Trait + '?) @@ -1597,7 +1597,7 @@ fn main() { 47..48 '_': &'? (dyn Fn(S) + '?) 58..60 '{}': () 71..105 '{ ...()); }': () - 77..78 'f': fn f(&'? (dyn Fn(S) + '?)) + 77..78 'f': fn f(&'? (dyn Fn(S) + 'static)) 77..102 'f(&|nu...foo())': () 79..101 '&|numb....foo()': &'? impl Fn(S) 80..101 '|numbe....foo()': impl Fn(S) @@ -2952,7 +2952,7 @@ fn test(x: &dyn Foo) { 34..36 '{}': () 46..47 'x': &'? (dyn Foo + '?) 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&'? (dyn Foo + '?)) + 65..68 'foo': fn foo(&'? (dyn Foo + 'static)) 65..71 'foo(x)': () 69..70 'x': &'? (dyn Foo + '?) "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 8593dba301b8..a17cf3782701 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -15,6 +15,8 @@ use crate::db::HirDatabase; use crate::generics::{Generics, generics}; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime, LifetimeData, Ty, TyKind, @@ -238,14 +240,15 @@ impl Context<'_> { } GenericDefId::FunctionId(f) => { let subst = self.generics.placeholder_subst(self.db); - self.add_constraints_from_sig( - self.db - .callable_item_signature(f.into()) - .substitute(Interner, &subst) - .params_and_return - .iter(), - Variance::Covariant, - ); + let interner = DbInterner::new_with(self.db, None, None); + let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); + let sig = self + .db + .callable_item_signature(f.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); + self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant); } _ => {} } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 8b440611e6cc..709d165e0b8b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2287,7 +2287,13 @@ impl Function { pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2296,8 +2302,14 @@ impl Function { pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ty = callable_sig.ret().clone(); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .output() + .to_chalk(interner); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2326,8 +2338,14 @@ impl Function { parent_id.map(|id| TyBuilder::subst_for_def(db, id, None).fill(&mut filler).build()); let substs = TyBuilder::subst_for_def(db, self.id, parent_substs).fill(&mut filler).build(); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ty = callable_sig.ret().clone(); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .output() + .to_chalk(interner); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2337,8 +2355,14 @@ impl Function { } let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ret_ty = callable_sig.ret().clone(); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ret_ty = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .output() + .to_chalk(interner); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 { return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into(); @@ -2358,7 +2382,13 @@ impl Function { pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); callable_sig .params() .iter() @@ -2386,7 +2416,13 @@ impl Function { pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; callable_sig .params() @@ -2436,7 +2472,13 @@ impl Function { GenericArg::new(Interner, GenericArgData::Ty(ty)) }) .build(); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; callable_sig .params() @@ -2731,8 +2773,13 @@ impl SelfParam { pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let substs = TyBuilder::placeholder_subst(db, self.func); - let callable_sig = - db.callable_item_signature(self.func.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.func.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let environment = db.trait_environment(self.func.into()); let ty = callable_sig.params()[0].clone(); Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } @@ -2764,8 +2811,13 @@ impl SelfParam { let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build(); let substs = TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build(); - let callable_sig = - db.callable_item_signature(self.func.into()).substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let callable_sig = db + .callable_item_signature(self.func.into()) + .instantiate(interner, args) + .skip_binder() + .to_chalk(interner); let environment = db.trait_environment(self.func.into()); let ty = callable_sig.params()[0].clone(); Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index cdb1ad8b38e7..77a94403abb9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1,6 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; +use base_db::salsa; use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; @@ -85,9 +86,15 @@ pub(super) fn expand_and_analyze<'db>( let original_offset = expansion.original_offset + relative_offset; let token = expansion.original_file.token_at_offset(original_offset).left_biased()?; - analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| { - AnalysisResult { analysis, expected, qualifier_ctx, token, original_offset } - }) + salsa::attach(sema.db, || analyze(sema, expansion, original_token, &token)).map( + |(analysis, expected, qualifier_ctx)| AnalysisResult { + analysis, + expected, + qualifier_ctx, + token, + original_offset, + }, + ) } fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 104740cbbf74..b7c124139608 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -380,7 +380,7 @@ fn main() { let foo = foo4(); // ^^^ &dyn Fn(f64, f64) -> u32 let foo = foo5(); - // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + // ^^^ &dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 let foo = foo6(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo7(); diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index e74d997e97c5..6f55886adca4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -1097,8 +1097,8 @@ fn foo(mut r: impl WriteHandler<()>) { By default this method stops actor's `Context`. ------ - fn finished(&mut self, ctx: &mut as Actor>::Context) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + fn finished(&mut self, ctx: &mut as Actor>::Context<()>) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "#]], ); } From 8337750474dce91d285accf351c561582c1ede25 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 23 Sep 2025 03:47:30 -0400 Subject: [PATCH 194/537] Remove all non-ns diagnostics queries, naming consistenly --- .../rust-analyzer/crates/hir-ty/src/db.rs | 132 ++++++++---------- .../crates/hir-ty/src/dyn_compatibility.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 64 ++------- .../crates/hir-ty/src/lower_nextsolver.rs | 20 ++- .../crates/hir-ty/src/next_solver/interner.rs | 2 +- .../crates/hir-ty/src/tests/incremental.rs | 6 - src/tools/rust-analyzer/crates/hir/src/lib.rs | 18 +-- 7 files changed, 90 insertions(+), 154 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 84c6c0471b5b..42f7ec6b59fd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -121,9 +121,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: TyDefId, ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; - #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)] - fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders, Diagnostics); + #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] + fn type_for_type_alias_with_diagnostics<'db>( + &'db self, + def: TypeAliasId, + ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. @@ -133,35 +136,56 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: ValueTyDefId, ) -> Option>>; - #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)] - fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders, Diagnostics); + #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)] + fn impl_self_ty_with_diagnostics<'db>( + &'db self, + def: ImplId, + ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); #[salsa::invoke(crate::lower::impl_self_ty_query)] #[salsa::transparent] fn impl_self_ty(&self, def: ImplId) -> Binders; // FIXME: Make this a non-interned query. - #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)] - fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics); + #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)] + fn const_param_ty_with_diagnostics<'db>( + &'db self, + def: ConstParamId, + ) -> (crate::next_solver::Ty<'db>, Diagnostics); - #[salsa::invoke(crate::lower::const_param_ty_query)] - #[salsa::transparent] + // FIXME: Make this a non-interned query. + #[salsa::invoke_interned(crate::lower::const_param_ty_query)] + #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)] fn const_param_ty(&self, def: ConstParamId) -> Ty; - #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)] - fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders, Diagnostics)>; + #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)] + fn impl_trait_with_diagnostics<'db>( + &'db self, + def: ImplId, + ) -> Option<( + crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>, + Diagnostics, + )>; #[salsa::invoke(crate::lower::impl_trait_query)] #[salsa::transparent] fn impl_trait(&self, def: ImplId) -> Option>; - #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)] - fn field_types_with_diagnostics( - &self, + #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)] + fn field_types_with_diagnostics<'db>( + &'db self, var: VariantId, - ) -> (Arc>>, Diagnostics); + ) -> ( + Arc< + ArenaMap< + LocalFieldId, + crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, + >, + >, + Diagnostics, + ); #[salsa::invoke(crate::lower::field_types_query)] #[salsa::transparent] @@ -191,6 +215,21 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[salsa::invoke( + crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query + )] + fn generic_predicates_without_parent_with_diagnostics<'db>( + &'db self, + def: GenericDefId, + ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics); + + #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)] + #[salsa::transparent] + fn generic_predicates_without_parent<'db>( + &'db self, + def: GenericDefId, + ) -> crate::lower_nextsolver::GenericPredicates<'db>; + #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) @@ -286,20 +325,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] - fn type_for_type_alias_with_diagnostics_ns<'db>( - &'db self, - def: TypeAliasId, - ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); - - #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)] - fn impl_self_ty_with_diagnostics_ns<'db>( - &'db self, - def: ImplId, - ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); - #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)] #[salsa::transparent] fn impl_self_ty_ns<'db>( @@ -307,26 +332,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: ImplId, ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; - // FIXME: Make this a non-interned query. - #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)] - fn const_param_ty_with_diagnostics_ns<'db>( - &'db self, - def: ConstParamId, - ) -> (crate::next_solver::Ty<'db>, Diagnostics); - #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)] #[salsa::transparent] fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>; - #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)] - fn impl_trait_with_diagnostics_ns<'db>( - &'db self, - def: ImplId, - ) -> Option<( - crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>, - Diagnostics, - )>; - #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)] #[salsa::transparent] fn impl_trait_ns<'db>( @@ -334,20 +343,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: ImplId, ) -> Option>>; - #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)] - fn field_types_with_diagnostics_ns<'db>( - &'db self, - var: VariantId, - ) -> ( - Arc< - ArenaMap< - LocalFieldId, - crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, - >, - >, - Diagnostics, - ); - #[salsa::invoke(crate::lower_nextsolver::field_types_query)] #[salsa::transparent] fn field_types_ns<'db>( @@ -383,21 +378,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { &'db self, def: GenericDefId, ) -> crate::lower_nextsolver::GenericPredicates<'db>; - - #[salsa::invoke( - crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query - )] - fn generic_predicates_without_parent_with_diagnostics_ns<'db>( - &'db self, - def: GenericDefId, - ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics); - - #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)] - #[salsa::transparent] - fn generic_predicates_without_parent_ns<'db>( - &'db self, - def: GenericDefId, - ) -> crate::lower_nextsolver::GenericPredicates<'db>; } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index f033c511acd6..b2406a088958 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -364,7 +364,7 @@ where cb(MethodViolationCode::UndispatchableReceiver)?; } - let predicates = &*db.generic_predicates_without_parent_ns(func.into()); + let predicates = &*db.generic_predicates_without_parent(func.into()); for pred in predicates { let pred = pred.kind().skip_binder(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 598fd38b4b8e..b55f9cd145e2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -32,7 +32,7 @@ use hir_def::{ hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, lang_item::LangItem, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, - signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, + signatures::{FunctionSignature, TraitFlags}, type_ref::{ ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, @@ -908,7 +908,7 @@ pub(crate) fn field_types_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> Arc>> { - db.field_types_with_diagnostics(variant_id).0 + field_types_with_diagnostics_query(db, variant_id).0 } /// Build the type of all specific fields of a struct or enum variant. @@ -1303,46 +1303,6 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result( (GenericDefaults(None), None) } -pub(crate) fn type_for_type_alias_with_diagnostics_query( - db: &dyn HirDatabase, - t: TypeAliasId, -) -> (Binders, Diagnostics) { - let generics = generics(db, t.into()); - let type_alias_data = db.type_alias_signature(t); - let mut diags = None; - let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { - TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner) - } else { - let resolver = t.resolver(db); - let alias = db.type_alias_signature(t); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &alias.store, - t.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - let res = alias - .ty - .map(|type_ref| ctx.lower_ty(type_ref)) - .unwrap_or_else(|| TyKind::Error.intern(Interner)); - diags = create_diagnostics(ctx.diagnostics); - res - }; - - (make_binders(db, &generics, inner), diags) -} - -pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - adt: TypeAliasId, -) -> (Binders, Diagnostics) { - let generics = generics(db, adt.into()); - (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TyDefId { BuiltinType(BuiltinType), @@ -1376,7 +1336,7 @@ impl ValueTyDefId { } pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { - db.impl_self_ty_with_diagnostics(impl_id).0 + impl_self_ty_with_diagnostics_query(db, impl_id).0 } pub(crate) fn impl_self_ty_with_diagnostics_query( @@ -1400,16 +1360,8 @@ pub(crate) fn impl_self_ty_with_diagnostics_query( ) } -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - impl_id: ImplId, -) -> (Binders, Diagnostics) { - let generics = generics(db, impl_id.into()); - (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) -} - pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { - db.const_param_ty_with_diagnostics(def).0 + const_param_ty_with_diagnostics_query(db, def).0 } // returns None if def is a type arg @@ -1437,16 +1389,16 @@ pub(crate) fn const_param_ty_with_diagnostics_query( (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn const_param_ty_with_diagnostics_cycle_result( +pub(crate) fn const_param_ty_cycle_result( _: &dyn HirDatabase, _: crate::db::HirDatabaseData, _: ConstParamId, -) -> (Ty, Diagnostics) { - (TyKind::Error.intern(Interner), None) +) -> Ty { + TyKind::Error.intern(Interner) } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { - db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) + impl_trait_with_diagnostics_query(db, impl_id).map(|it| it.0) } pub(crate) fn impl_trait_with_diagnostics_query( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 1ca56feb099a..a537d3a10171 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -904,7 +904,7 @@ pub(crate) fn impl_trait_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> Option>> { - db.impl_trait_with_diagnostics_ns(impl_id).map(|it| it.0) + db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) } pub(crate) fn impl_trait_with_diagnostics_query<'db>( @@ -986,7 +986,7 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind AdtDef::new(it, interner), GenericArgs::identity_for_item(interner, it.into()), )), - TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics_ns(it).0, + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, } } @@ -1131,7 +1131,7 @@ pub(crate) fn impl_self_ty_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> EarlyBinder<'db, Ty<'db>> { - db.impl_self_ty_with_diagnostics_ns(impl_id).0 + db.impl_self_ty_with_diagnostics(impl_id).0 } pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( @@ -1162,7 +1162,7 @@ pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( } pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { - db.const_param_ty_with_diagnostics_ns(def).0 + db.const_param_ty_with_diagnostics(def).0 } // returns None if def is a type arg @@ -1191,11 +1191,21 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>( (ty, create_diagnostics(ctx.diagnostics)) } +pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, + _: crate::db::HirDatabaseData, + def: ConstParamId, +) -> (Ty<'db>, Diagnostics) { + let resolver = def.parent().resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + (Ty::new_error(interner, ErrorGuaranteed), None) +} + pub(crate) fn field_types_query<'db>( db: &'db dyn HirDatabase, variant_id: VariantId, ) -> Arc>>> { - db.field_types_with_diagnostics_ns(variant_id).0 + db.field_types_with_diagnostics(variant_id).0 } /// Build the type of all specific fields of a struct or enum variant. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 1a14ac9a7457..3ff9fde9768b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1320,7 +1320,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { - let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap()); + let predicates = self.db().generic_predicates_without_parent(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 0d922de9aeb0..cc5ad2045ed4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -504,10 +504,8 @@ impl SomeStruct { "crate_local_def_map", "trait_impls_in_crate_shim", "attrs_shim", - "impl_trait_with_diagnostics_shim", "impl_signature_shim", "impl_signature_with_source_map_shim", - "impl_self_ty_with_diagnostics_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", "attrs_shim", @@ -608,8 +606,6 @@ fn main() { "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", - "impl_trait_with_diagnostics_ns_shim", - "impl_self_ty_with_diagnostics_ns_shim", "generic_predicates_ns_shim", "value_ty_shim", "generic_predicates_shim", @@ -698,8 +694,6 @@ fn main() { "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", - "impl_trait_with_diagnostics_ns_shim", - "impl_self_ty_with_diagnostics_ns_shim", "generic_predicates_ns_shim", "generic_predicates_shim", ] diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 709d165e0b8b..5592ca285fb0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -682,7 +682,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics_ns(s.id.into()).1, + db.field_types_with_diagnostics(s.id.into()).1, source_map, ); } @@ -694,7 +694,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics_ns(u.id.into()).1, + db.field_types_with_diagnostics(u.id.into()).1, source_map, ); } @@ -724,7 +724,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics_ns(v.into()).1, + db.field_types_with_diagnostics(v.into()).1, source_map, ); expr_store_diagnostics(db, acc, source_map); @@ -740,7 +740,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics_ns(type_alias.id).1, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, &source_map, ); acc.extend(def.diagnostics(db, style_lints)); @@ -915,13 +915,13 @@ impl Module { push_ty_diagnostics( db, acc, - db.impl_self_ty_with_diagnostics_ns(impl_def.id).1, + db.impl_self_ty_with_diagnostics(impl_def.id).1, &source_map, ); push_ty_diagnostics( db, acc, - db.impl_trait_with_diagnostics_ns(impl_def.id).and_then(|it| it.1), + db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), &source_map, ); @@ -3693,7 +3693,7 @@ impl AssocItem { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics_ns(type_alias.id).1, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, &db.type_alias_signature_with_source_map(type_alias.id).1, ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { @@ -3821,7 +3821,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.generic_predicates_without_parent_with_diagnostics_ns(def).1, + db.generic_predicates_without_parent_with_diagnostics(def).1, &source_map, ); for (param_id, param) in generics.iter_type_or_consts() { @@ -3829,7 +3829,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.const_param_ty_with_diagnostics_ns(ConstParamId::from_unchecked( + db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( TypeOrConstParamId { parent: def, local_id: param_id }, )) .1, From 94bf6b4da632c9f34c082e0c6464d46cf1f6b2ed Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:54:29 -0400 Subject: [PATCH 195/537] Be sure to instantiate and pass up trait refs in named_associated_type_shorthand_candidates --- .../crates/hir-ty/src/lower_nextsolver.rs | 23 +++++++++++-------- .../crates/ide/src/signature_help.rs | 4 ++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index a537d3a10171..02774a63df42 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -1970,7 +1970,8 @@ fn named_associated_type_shorthand_candidates<'db, R>( let mut search = |t: TraitRef<'db>| -> Option { let trait_id = t.def_id.0; let mut checked_traits = FxHashSet::default(); - let mut check_trait = |trait_id: TraitId| { + let mut check_trait = |trait_ref: TraitRef<'db>| { + let trait_id = trait_ref.def_id.0; let name = &db.trait_signature(trait_id).name; tracing::debug!(?trait_id, ?name); if !checked_traits.insert(trait_id) { @@ -1981,37 +1982,39 @@ fn named_associated_type_shorthand_candidates<'db, R>( tracing::debug!(?data.items); for (name, assoc_id) in &data.items { if let &AssocItemId::TypeAliasId(alias) = assoc_id - && let Some(ty) = check_alias(name, t, alias) + && let Some(ty) = check_alias(name, trait_ref, alias) { return Some(ty); } } None }; - let mut stack: SmallVec<[_; 4]> = smallvec![trait_id]; - while let Some(trait_def_id) = stack.pop() { - if let Some(alias) = check_trait(trait_def_id) { + let mut stack: SmallVec<[_; 4]> = smallvec![t]; + while let Some(trait_ref) = stack.pop() { + if let Some(alias) = check_trait(trait_ref) { return Some(alias); } for pred in generic_predicates_filtered_by( db, - GenericDefId::TraitId(trait_def_id), + GenericDefId::TraitId(trait_ref.def_id.0), PredicateFilter::SelfTrait, // We are likely in the midst of lowering generic predicates of `def`. // So, if we allow `pred == def` we might fall into an infinite recursion. // Actually, we have already checked for the case `pred == def` above as we started // with a stack including `trait_id` - |pred| pred != def && pred == GenericDefId::TraitId(trait_def_id), + |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0), ) .0 .deref() { tracing::debug!(?pred); - let trait_id = match pred.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(), + let sup_trait_ref = match pred.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref, _ => continue, }; - stack.push(trait_id.0); + let sup_trait_ref = + EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args); + stack.push(sup_trait_ref); } tracing::debug!(?stack); } diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 6f55886adca4..e74d997e97c5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -1097,8 +1097,8 @@ fn foo(mut r: impl WriteHandler<()>) { By default this method stops actor's `Context`. ------ - fn finished(&mut self, ctx: &mut as Actor>::Context<()>) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + fn finished(&mut self, ctx: &mut as Actor>::Context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "#]], ); } From e8a8e061bf0187efbb33d972e31ef2b5d9f6d529 Mon Sep 17 00:00:00 2001 From: ltdk Date: Mon, 22 Sep 2025 21:02:53 -0400 Subject: [PATCH 196/537] Make missed precondition-free float intrinsics safe --- .../rustc_hir_analysis/src/check/intrinsic.rs | 8 ++++++++ library/core/src/intrinsics/mod.rs | 16 ++++++++-------- library/core/src/num/f128.rs | 3 +-- library/core/src/num/f16.rs | 3 +-- library/core/src/num/f32.rs | 6 ++---- library/core/src/num/f64.rs | 6 ++---- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 6faa67f6a904..bc3448be5823 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -90,6 +90,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::contract_check_ensures | sym::contract_check_requires | sym::contract_checks + | sym::copysignf16 + | sym::copysignf32 + | sym::copysignf64 + | sym::copysignf128 | sym::cosf16 | sym::cosf32 | sym::cosf64 @@ -106,6 +110,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::expf32 | sym::expf64 | sym::expf128 + | sym::fabsf16 + | sym::fabsf32 + | sym::fabsf64 + | sym::fabsf128 | sym::fadd_algebraic | sym::fdiv_algebraic | sym::floorf16 diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a174ced5a2a6..eaf2738d8b7f 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3170,7 +3170,7 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 { /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn fabsf16(x: f16) -> f16; +pub const fn fabsf16(x: f16) -> f16; /// Returns the absolute value of an `f32`. /// @@ -3179,7 +3179,7 @@ pub const unsafe fn fabsf16(x: f16) -> f16; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn fabsf32(x: f32) -> f32; +pub const fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. /// @@ -3188,7 +3188,7 @@ pub const unsafe fn fabsf32(x: f32) -> f32; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn fabsf64(x: f64) -> f64; +pub const fn fabsf64(x: f64) -> f64; /// Returns the absolute value of an `f128`. /// @@ -3196,7 +3196,7 @@ pub const unsafe fn fabsf64(x: f64) -> f64; /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn fabsf128(x: f128) -> f128; +pub const fn fabsf128(x: f128) -> f128; /// Copies the sign from `y` to `x` for `f16` values. /// @@ -3204,7 +3204,7 @@ pub const unsafe fn fabsf128(x: f128) -> f128; /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn copysignf16(x: f16, y: f16) -> f16; +pub const fn copysignf16(x: f16, y: f16) -> f16; /// Copies the sign from `y` to `x` for `f32` values. /// @@ -3213,7 +3213,7 @@ pub const unsafe fn copysignf16(x: f16, y: f16) -> f16; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn copysignf32(x: f32, y: f32) -> f32; +pub const fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. /// /// The stabilized version of this intrinsic is @@ -3221,7 +3221,7 @@ pub const unsafe fn copysignf32(x: f32, y: f32) -> f32; #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; +pub const fn copysignf64(x: f64, y: f64) -> f64; /// Copies the sign from `y` to `x` for `f128` values. /// @@ -3229,7 +3229,7 @@ pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -pub const unsafe fn copysignf128(x: f128, y: f128) -> f128; +pub const fn copysignf128(x: f128, y: f128) -> f128; /// Generates the LLVM body for the automatic differentiation of `f` using Enzyme, /// with `df` as the derivative function and `args` as its arguments. diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 6088fb6fa178..54d2d1c5706b 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1366,8 +1366,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f128) -> f128 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf128(self, sign) } + intrinsics::copysignf128(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3f66c5973d4a..f3e49544d259 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1343,8 +1343,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f16) -> f16 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf16(self, sign) } + intrinsics::copysignf16(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index ebce89e5b3da..ded70c825af9 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1449,8 +1449,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f32 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::fabsf32(self) } + intrinsics::fabsf32(self) } /// Returns a number that represents the sign of `self`. @@ -1508,8 +1507,7 @@ impl f32 { #[stable(feature = "copysign", since = "1.35.0")] #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] pub const fn copysign(self, sign: f32) -> f32 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf32(self, sign) } + intrinsics::copysignf32(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 91e3949fc390..3abdc7c108ab 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1447,8 +1447,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn abs(self) -> f64 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::fabsf64(self) } + intrinsics::fabsf64(self) } /// Returns a number that represents the sign of `self`. @@ -1506,8 +1505,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn copysign(self, sign: f64) -> f64 { - // SAFETY: this is actually a safe intrinsic - unsafe { intrinsics::copysignf64(self, sign) } + intrinsics::copysignf64(self, sign) } /// Float addition that allows optimizations based on algebraic rules. From aa537824c40437d11d32c66fe16d4764b072c094 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 24 Sep 2025 00:50:36 +0200 Subject: [PATCH 197/537] core: simplify `CStr::default()` Just use a `CStr`-literal... --- library/core/src/ffi/c_str.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d0b53e3a237f..09d9b160700c 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -179,9 +179,7 @@ impl fmt::Debug for CStr { impl Default for &CStr { #[inline] fn default() -> Self { - const SLICE: &[c_char] = &[0]; - // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string. - unsafe { CStr::from_ptr(SLICE.as_ptr()) } + c"" } } From 95ddfa102af7f841c36ab8b207eb42571716b1cd Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 24 Sep 2025 07:34:22 +0800 Subject: [PATCH 198/537] Update LLVM to 21.1.2 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 333793696b0a..8c30b9c5098b 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 333793696b0a08002acac6af983adc7a5233fc56 +Subproject commit 8c30b9c5098bdff1d3d9a2d460ee091cd1171e60 From ce677c7db80a245e1eee5b948dd6b20b4bba0423 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 23 Sep 2025 20:38:38 -0300 Subject: [PATCH 199/537] Update compiler/rustc_mir_transform/src/patch.rs Co-authored-by: lcnr --- compiler/rustc_mir_transform/src/patch.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index 8f2124405650..d831ab50b1ac 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -23,6 +23,8 @@ pub(crate) struct MirPatch<'tcx> { terminate_block: Option<(BasicBlock, UnwindTerminateReason)>, body_span: Span, next_local: usize, + /// The number of blocks at the start of the transformation. New blocks + /// get appended at the end. next_block: usize, } From f5c6c9542ecfab74e654f9b7f1150d486560ae43 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Tue, 16 Sep 2025 02:23:24 -0400 Subject: [PATCH 200/537] Add an attribute to check the number of lanes in a SIMD vector after monomorphization Unify zero-length and oversized SIMD errors --- .../src/attributes/crate_level.rs | 36 ------------------ .../src/attributes/rustc_internal.rs | 18 +++++++++ .../rustc_attr_parsing/src/attributes/util.rs | 37 ++++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 3 +- .../rustc_codegen_cranelift/src/common.rs | 9 ++++- .../rustc_codegen_cranelift/src/global_asm.rs | 5 ++- compiler/rustc_codegen_gcc/src/context.rs | 9 ++++- compiler/rustc_codegen_llvm/src/context.rs | 11 +++++- compiler/rustc_feature/src/builtin_attrs.rs | 6 +++ .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/hir_ty_lowering/cmse.rs | 1 + compiler/rustc_middle/messages.ftl | 6 +++ compiler/rustc_middle/src/error.rs | 6 +++ compiler/rustc_middle/src/ty/layout.rs | 26 +++++++++++++ compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_transmute/src/layout/tree.rs | 1 + compiler/rustc_ty_utils/src/errors.rs | 13 ------- compiler/rustc_ty_utils/src/layout.rs | 26 +++++++++++-- .../html/templates/type_layout.html | 5 +++ tests/ui/simd/auxiliary/simd-lane-limit.rs | 5 +++ tests/ui/simd/monomorphize-too-long.rs | 4 +- tests/ui/simd/monomorphize-too-long.stderr | 6 ++- tests/ui/simd/monomorphize-zero-length.rs | 4 +- tests/ui/simd/monomorphize-zero-length.stderr | 6 ++- tests/ui/simd/simd-lane-limit-err-npow2.rs | 12 ++++++ .../ui/simd/simd-lane-limit-err-npow2.stderr | 8 ++++ tests/ui/simd/simd-lane-limit-err.rs | 11 ++++++ tests/ui/simd/simd-lane-limit-err.stderr | 8 ++++ tests/ui/simd/simd-lane-limit-ok.rs | 14 +++++++ .../type-generic-monomorphisation-empty.rs | 4 +- ...type-generic-monomorphisation-empty.stderr | 6 ++- ...type-generic-monomorphisation-oversized.rs | 5 +-- ...-generic-monomorphisation-oversized.stderr | 6 ++- 35 files changed, 245 insertions(+), 78 deletions(-) create mode 100644 tests/ui/simd/auxiliary/simd-lane-limit.rs create mode 100644 tests/ui/simd/simd-lane-limit-err-npow2.rs create mode 100644 tests/ui/simd/simd-lane-limit-err-npow2.stderr create mode 100644 tests/ui/simd/simd-lane-limit-err.rs create mode 100644 tests/ui/simd/simd-lane-limit-err.stderr create mode 100644 tests/ui/simd/simd-lane-limit-ok.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 4611de444599..00edafecd9a8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,40 +1,4 @@ -use std::num::IntErrorKind; - -use rustc_hir::limit::Limit; - use super::prelude::*; -use crate::session_diagnostics::LimitInvalid; - -impl AcceptContext<'_, '_, S> { - fn parse_limit_int(&self, nv: &NameValueParser) -> Option { - let Some(limit) = nv.value_as_str() else { - self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; - - let error_str = match limit.as_str().parse() { - Ok(i) => return Some(Limit::new(i)), - Err(e) => match e.kind() { - IntErrorKind::PosOverflow => "`limit` is too large", - IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::NegOverflow => { - panic!( - "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" - ) - } - IntErrorKind::Zero => { - panic!("zero is a valid `limit` so should have returned Ok() when parsing") - } - kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), - }, - }; - - self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); - - None - } -} pub(crate) struct CrateNameParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index a995549fc7c8..cf2f5c6c7902 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -49,3 +49,21 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser { Some(AttributeKind::RustcObjectLifetimeDefault) } } + +pub(crate) struct RustcSimdMonomorphizeLaneLimitParser; + +impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser { + const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 77e8c32e59d7..62b72798e969 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,11 +1,15 @@ +use std::num::IntErrorKind; + use rustc_ast::LitKind; use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; +use rustc_hir::limit::Limit; use rustc_span::{Symbol, sym}; use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::parser::{ArgParser, NameValueParser}; +use crate::session_diagnostics::LimitInvalid; /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are @@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer( }; Some(num.0) } + +impl AcceptContext<'_, '_, S> { + pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option { + let Some(limit) = nv.value_as_str() else { + self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let error_str = match limit.as_str().parse() { + Ok(i) => return Some(Limit::new(i)), + Err(e) => match e.kind() { + IntErrorKind::PosOverflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::NegOverflow => { + panic!( + "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" + ) + } + IntErrorKind::Zero => { + panic!("zero is a valid `limit` so should have returned Ok() when parsing") + } + kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), + }, + }; + + self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); + + None + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7998048be5a..72fe269b135a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -53,7 +53,7 @@ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, - RustcObjectLifetimeDefaultParser, + RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -195,6 +195,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 2fbe5c02802a..81b1814605a1 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.0.sess.dcx().span_fatal(span, err.to_string()) } else { self.0 @@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) = + err + { self.0.sess.dcx().emit_fatal(Spanned { span, node: err }) } else { match fn_abi_request { diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 203b443269fa..1306c6aa5179 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.tcx.sess.dcx().span_fatal(span, err.to_string()) } else { self.tcx diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 665cf22ddbae..9815fb07eaae 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic())) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) @@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) = + err + { self.tcx.dcx().emit_fatal(respan(span, err)) } else { match fn_abi_request { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index a69fa54a54a4..e4528efaa37b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -991,7 +991,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> { impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::ReferencesError(_) + | LayoutError::InvalidSimd { .. } = err + { self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() }) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) @@ -1008,7 +1011,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { match err { - FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => { + FnAbiError::Layout( + LayoutError::SizeOverflow(_) + | LayoutError::Cycle(_) + | LayoutError::InvalidSimd { .. }, + ) => { self.tcx.dcx().emit_fatal(Spanned { span, node: err }); } _ => match fn_abi_request { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 129ab7eccb57..0d890b57de0d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1203,6 +1203,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ niche optimizations in the standard library", ), + rustc_attr!( + rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing, + EncodeCrossCrate::Yes, + "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \ + for better error messages", + ), rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index ea11a99efbc3..80cb64176847 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -642,6 +642,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`. + RustcSimdMonomorphizeLaneLimit(Limit), + /// Represents `#[sanitize]` /// /// the on set and off set are distjoint since there's a third option: unset. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 55521c158540..968ea668efea 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -85,6 +85,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, + RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, ShouldPanic { .. } => No, SkipDuringMethodDispatch { .. } => No, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 5088c63702e6..76b0ce985f0c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -213,6 +213,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError } Unknown(..) | SizeOverflow(..) + | InvalidSimd { .. } | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => { diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 279ab9a9d8fb..82f3df8da3b1 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -98,6 +98,12 @@ middle_layout_references_error = middle_layout_size_overflow = values of the type `{$ty}` are too big for the target architecture +middle_layout_simd_too_many = + the SIMD type `{$ty}` has more elements than the limit {$max_lanes} + +middle_layout_simd_zero_length = + the SIMD type `{$ty}` has zero elements + middle_layout_too_generic = the type `{$ty}` does not have a fixed layout middle_layout_unknown = diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index dad402ec6961..e15da827bda9 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -141,6 +141,12 @@ pub enum LayoutError<'tcx> { #[diag(middle_layout_size_overflow)] Overflow { ty: Ty<'tcx> }, + #[diag(middle_layout_simd_too_many)] + SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 }, + + #[diag(middle_layout_simd_zero_length)] + SimdZeroLength { ty: Ty<'tcx> }, + #[diag(middle_layout_normalization_failure)] NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2114d080dfa4..47e561d9d3ce 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -217,6 +217,15 @@ impl fmt::Display for ValidityRequirement { } } +#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] +pub enum SimdLayoutError { + /// The vector has 0 lanes. + ZeroLength, + /// The vector has more lanes than supported or permitted by + /// #\[rustc_simd_monomorphize_lane_limit\]. + TooManyLanes(u64), +} + #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub enum LayoutError<'tcx> { /// A type doesn't have a sensible layout. @@ -229,6 +238,8 @@ pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`]. SizeOverflow(Ty<'tcx>), + /// A SIMD vector has invalid layout, such as zero-length or too many lanes. + InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError }, /// The layout can vary due to a generic parameter. /// /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout @@ -256,6 +267,10 @@ impl<'tcx> LayoutError<'tcx> { match self { Unknown(_) => middle_layout_unknown, SizeOverflow(_) => middle_layout_size_overflow, + InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => { + middle_layout_simd_too_many + } + InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length, TooGeneric(_) => middle_layout_too_generic, NormalizationFailure(_, _) => middle_layout_normalization_failure, Cycle(_) => middle_layout_cycle, @@ -270,6 +285,10 @@ impl<'tcx> LayoutError<'tcx> { match self { Unknown(ty) => E::Unknown { ty }, SizeOverflow(ty) => E::Overflow { ty }, + InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => { + E::SimdTooManyLanes { ty, max_lanes } + } + InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty }, TooGeneric(ty) => E::TooGeneric { ty }, NormalizationFailure(ty, e) => { E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } @@ -292,6 +311,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { LayoutError::SizeOverflow(ty) => { write!(f, "values of the type `{ty}` are too big for the target architecture") } + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => { + write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}") + } + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => { + write!(f, "the SIMD type `{ty}` has zero elements") + } LayoutError::NormalizationFailure(t, e) => write!( f, "unable to determine layout for `{}` because `{}` cannot be normalized", @@ -373,6 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> { e @ LayoutError::Cycle(_) | e @ LayoutError::Unknown(_) | e @ LayoutError::SizeOverflow(_) + | e @ LayoutError::InvalidSimd { .. } | e @ LayoutError::NormalizationFailure(..) | e @ LayoutError::ReferencesError(_), ) => return Err(e), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2562d2e0b83c..cabf28197413 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -254,6 +254,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroEscape( .. ) | AttributeKind::RustcLayoutScalarValidRangeStart(..) | AttributeKind::RustcLayoutScalarValidRangeEnd(..) + | AttributeKind::RustcSimdMonomorphizeLaneLimit(..) | AttributeKind::ExportStable | AttributeKind::FfiConst(..) | AttributeKind::UnstableFeatureBound(..) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cdb0b5b58da6..92a1fad47552 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1937,6 +1937,7 @@ symbols! { rustc_regions, rustc_reservation_impl, rustc_serialize, + rustc_simd_monomorphize_lane_limit, rustc_skip_during_method_dispatch, rustc_specialization_trait, rustc_std_internal_symbol, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index d7ea26a2ab1d..a02e8ecf613f 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -279,6 +279,7 @@ pub(crate) mod rustc { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) | LayoutError::TooGeneric(..) + | LayoutError::InvalidSimd { .. } | LayoutError::NormalizationFailure(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, LayoutError::Cycle(err) => Self::TypeError(*err), diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 0298e7e0e951..f92c405242ce 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -78,19 +78,6 @@ pub(crate) struct UnexpectedFnPtrAssociatedItem { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ty_utils_zero_length_simd_type)] -pub(crate) struct ZeroLengthSimdType<'tcx> { - pub ty: Ty<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(ty_utils_oversized_simd_type)] -pub(crate) struct OversizedSimdType<'tcx> { - pub ty: Ty<'tcx>, - pub max_lanes: u64, -} - #[derive(Diagnostic)] #[diag(ty_utils_non_primitive_simd_type)] pub(crate) struct NonPrimitiveSimdType<'tcx> { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 79f7e228e2ad..5c4451ce264f 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -7,11 +7,13 @@ use rustc_abi::{ VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ - FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, + FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ @@ -22,7 +24,7 @@ use rustc_span::{Symbol, sym}; use tracing::{debug, instrument}; use {rustc_abi as abi, rustc_hir as hir}; -use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType}; +use crate::errors::NonPrimitiveSimdType; mod invariant; @@ -120,11 +122,11 @@ fn map_error<'tcx>( } LayoutCalculatorError::ZeroLengthSimdType => { // Can't be caught in typeck if the array length is generic. - cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty }) + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } } LayoutCalculatorError::OversizedSimdType { max_lanes } => { // Can't be caught in typeck if the array length is generic. - cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes }) + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } } LayoutCalculatorError::NonPrimitiveSimdType(field) => { // This error isn't caught in typeck, e.g., if @@ -561,6 +563,22 @@ fn layout_of_uncached<'tcx>( let e_ly = cx.layout_of(e_ty)?; + // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit + if let Some(limit) = find_attr!( + tcx.get_all_attrs(def.did()), + AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit + ) { + if !limit.value_within_limit(e_len as usize) { + return Err(map_error( + &cx, + ty, + rustc_abi::LayoutCalculatorError::OversizedSimdType { + max_lanes: limit.0 as u64, + }, + )); + } + } + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? } diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html index 0034552bdd3b..49153d58fe98 100644 --- a/src/librustdoc/html/templates/type_layout.html +++ b/src/librustdoc/html/templates/type_layout.html @@ -65,5 +65,10 @@ Note: Encountered an error during type layout; {#+ #} the type's layout depended on the type's layout itself. {# #}

+ {% when Err(LayoutError::InvalidSimd {..}) %} +

{# #} + Note: Encountered an error during type layout; {#+ #} + the vector type had zero elements or too many elements. {# #} +

{% endmatch %}
{# #} diff --git a/tests/ui/simd/auxiliary/simd-lane-limit.rs b/tests/ui/simd/auxiliary/simd-lane-limit.rs new file mode 100644 index 000000000000..dde6b880c62e --- /dev/null +++ b/tests/ui/simd/auxiliary/simd-lane-limit.rs @@ -0,0 +1,5 @@ +#![feature(rustc_attrs, repr_simd)] + +#[repr(simd, packed)] +#[rustc_simd_monomorphize_lane_limit = "8"] +pub struct Simd(pub [T; N]); diff --git a/tests/ui/simd/monomorphize-too-long.rs b/tests/ui/simd/monomorphize-too-long.rs index 4fac987b0b5a..9c8374151917 100644 --- a/tests/ui/simd/monomorphize-too-long.rs +++ b/tests/ui/simd/monomorphize-too-long.rs @@ -6,7 +6,5 @@ struct Simd([T; N]); fn main() { - let _too_big = Simd([1_u16; 54321]); + let _too_big = Simd([1_u16; 54321]); //~ ERROR the SIMD type `Simd` has more elements than the limit 32768 } - -//~? ERROR monomorphising SIMD type `Simd` of length greater than 32768 diff --git a/tests/ui/simd/monomorphize-too-long.stderr b/tests/ui/simd/monomorphize-too-long.stderr index 978eef307abd..71bc78ef5c95 100644 --- a/tests/ui/simd/monomorphize-too-long.stderr +++ b/tests/ui/simd/monomorphize-too-long.stderr @@ -1,4 +1,8 @@ -error: monomorphising SIMD type `Simd` of length greater than 32768 +error: the SIMD type `Simd` has more elements than the limit 32768 + --> $DIR/monomorphize-too-long.rs:9:9 + | +LL | let _too_big = Simd([1_u16; 54321]); + | ^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/simd/monomorphize-zero-length.rs b/tests/ui/simd/monomorphize-zero-length.rs index d38870c572d9..f956197a61cf 100644 --- a/tests/ui/simd/monomorphize-zero-length.rs +++ b/tests/ui/simd/monomorphize-zero-length.rs @@ -6,7 +6,5 @@ struct Simd([T; N]); fn main() { - let _empty = Simd([1.0; 0]); + let _empty = Simd([1.0; 0]); //~ ERROR the SIMD type `Simd` has zero elements } - -//~? ERROR monomorphising SIMD type `Simd` of zero length diff --git a/tests/ui/simd/monomorphize-zero-length.stderr b/tests/ui/simd/monomorphize-zero-length.stderr index 738c20fe51a4..66f26d95c9d9 100644 --- a/tests/ui/simd/monomorphize-zero-length.stderr +++ b/tests/ui/simd/monomorphize-zero-length.stderr @@ -1,4 +1,8 @@ -error: monomorphising SIMD type `Simd` of zero length +error: the SIMD type `Simd` has zero elements + --> $DIR/monomorphize-zero-length.rs:9:9 + | +LL | let _empty = Simd([1.0; 0]); + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.rs b/tests/ui/simd/simd-lane-limit-err-npow2.rs new file mode 100644 index 000000000000..d5c5c92e953d --- /dev/null +++ b/tests/ui/simd/simd-lane-limit-err-npow2.rs @@ -0,0 +1,12 @@ +//@ build-fail +//@ aux-crate:simd=simd-lane-limit.rs + +extern crate simd; + +use simd::Simd; + +fn main() { + // test non-power-of-two, since #[repr(simd, packed)] has unusual layout + let _x: Simd = Simd([0; 24]); + //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8 +} diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.stderr b/tests/ui/simd/simd-lane-limit-err-npow2.stderr new file mode 100644 index 000000000000..fff26c4c1c1b --- /dev/null +++ b/tests/ui/simd/simd-lane-limit-err-npow2.stderr @@ -0,0 +1,8 @@ +error: the SIMD type `simd::Simd` has more elements than the limit 8 + --> $DIR/simd-lane-limit-err-npow2.rs:10:9 + | +LL | let _x: Simd = Simd([0; 24]); + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/simd-lane-limit-err.rs b/tests/ui/simd/simd-lane-limit-err.rs new file mode 100644 index 000000000000..00390bdbdafa --- /dev/null +++ b/tests/ui/simd/simd-lane-limit-err.rs @@ -0,0 +1,11 @@ +//@ build-fail +//@ aux-crate:simd=simd-lane-limit.rs + +extern crate simd; + +use simd::Simd; + +fn main() { + let _x: Simd = Simd([0; 16]); + //~^ ERROR the SIMD type `simd::Simd` has more elements than the limit 8 +} diff --git a/tests/ui/simd/simd-lane-limit-err.stderr b/tests/ui/simd/simd-lane-limit-err.stderr new file mode 100644 index 000000000000..3f2eaeda2d41 --- /dev/null +++ b/tests/ui/simd/simd-lane-limit-err.stderr @@ -0,0 +1,8 @@ +error: the SIMD type `simd::Simd` has more elements than the limit 8 + --> $DIR/simd-lane-limit-err.rs:9:9 + | +LL | let _x: Simd = Simd([0; 16]); + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/simd-lane-limit-ok.rs b/tests/ui/simd/simd-lane-limit-ok.rs new file mode 100644 index 000000000000..52fd3158440a --- /dev/null +++ b/tests/ui/simd/simd-lane-limit-ok.rs @@ -0,0 +1,14 @@ +//@ build-pass +//@ aux-crate:simd=simd-lane-limit.rs + +extern crate simd; + +use simd::Simd; + +fn main() { + let _x: Simd = Simd([0; 4]); + let _y: Simd = Simd([0; 8]); + + // test non-power-of-two, since #[repr(simd, packed)] has unusual layout + let _z: Simd = Simd([0; 6]); +} diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.rs b/tests/ui/simd/type-generic-monomorphisation-empty.rs index c08dc9fe3df2..7c43b8914da6 100644 --- a/tests/ui/simd/type-generic-monomorphisation-empty.rs +++ b/tests/ui/simd/type-generic-monomorphisation-empty.rs @@ -6,7 +6,5 @@ struct Simd([f32; N]); fn main() { - let _ = Simd::<0>([]); + let _empty = Simd::<0>([]); //~ ERROR the SIMD type `Simd<0>` has zero elements } - -//~? ERROR monomorphising SIMD type `Simd<0>` of zero length diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.stderr b/tests/ui/simd/type-generic-monomorphisation-empty.stderr index fc294607ae31..450db7e47db0 100644 --- a/tests/ui/simd/type-generic-monomorphisation-empty.stderr +++ b/tests/ui/simd/type-generic-monomorphisation-empty.stderr @@ -1,4 +1,8 @@ -error: monomorphising SIMD type `Simd<0>` of zero length +error: the SIMD type `Simd<0>` has zero elements + --> $DIR/type-generic-monomorphisation-empty.rs:9:9 + | +LL | let _empty = Simd::<0>([]); + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.rs b/tests/ui/simd/type-generic-monomorphisation-oversized.rs index efe3480317c9..73a1f00e8c7f 100644 --- a/tests/ui/simd/type-generic-monomorphisation-oversized.rs +++ b/tests/ui/simd/type-generic-monomorphisation-oversized.rs @@ -6,7 +6,6 @@ struct Simd([f32; N]); fn main() { - let _ = Simd::<65536>([0.; 65536]); + let _x = Simd::<65536>([0.; 65536]); + //~^ ERROR the SIMD type `Simd<65536>` has more elements than the limit 32768 } - -//~? ERROR monomorphising SIMD type `Simd<65536>` of length greater than 32768 diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr index 39ff36799cc9..0065049abd68 100644 --- a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr +++ b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr @@ -1,4 +1,8 @@ -error: monomorphising SIMD type `Simd<65536>` of length greater than 32768 +error: the SIMD type `Simd<65536>` has more elements than the limit 32768 + --> $DIR/type-generic-monomorphisation-oversized.rs:9:9 + | +LL | let _x = Simd::<65536>([0.; 65536]); + | ^^ error: aborting due to 1 previous error From 60548ffaa3dafec019e52f39ab7a075d3f11e24e Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Tue, 23 Sep 2025 22:14:25 -0400 Subject: [PATCH 201/537] Including spans in layout errors for all ADTs --- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index dc3a84b6a151..7ecba13d7274 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -469,8 +469,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id), ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id), ty::Adt(def, ..) => match def.adt_kind() { - AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), - AdtKind::Union => build_union_type_di_node(cx, unique_type_id), + AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span), + AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span), AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span), }, ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), @@ -1066,6 +1066,7 @@ fn visibility_di_flags<'ll, 'tcx>( fn build_struct_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let struct_type = unique_type_id.expect_ty(); let ty::Adt(adt_def, _) = struct_type.kind() else { @@ -1073,7 +1074,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( }; assert!(adt_def.is_struct()); let containing_scope = get_namespace_for_item(cx, adt_def.did()); - let struct_type_and_layout = cx.layout_of(struct_type); + let struct_type_and_layout = cx.spanned_layout_of(struct_type, span); let variant_def = adt_def.non_enum_variant(); let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers { Some(file_metadata_from_def_id(cx, Some(adt_def.did()))) @@ -1266,6 +1267,7 @@ fn build_closure_env_di_node<'ll, 'tcx>( fn build_union_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let union_type = unique_type_id.expect_ty(); let (union_def_id, variant_def) = match union_type.kind() { @@ -1273,7 +1275,7 @@ fn build_union_type_di_node<'ll, 'tcx>( _ => bug!("build_union_type_di_node on a non-ADT"), }; let containing_scope = get_namespace_for_item(cx, union_def_id); - let union_ty_and_layout = cx.layout_of(union_type); + let union_ty_and_layout = cx.spanned_layout_of(union_type, span); let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false); let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers { Some(file_metadata_from_def_id(cx, Some(union_def_id))) From c9dc0e307ac643518ecf98373f86be5f68a197a0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 24 Sep 2025 07:01:24 +0200 Subject: [PATCH 202/537] temporary-lifetime-extension-tuple-ctor.rs: make usable on all editions Also - add Reference id - fix typo --- .../ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs index bb537f855a4a..7de786dff3b7 100644 --- a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs +++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs @@ -1,4 +1,4 @@ -//@ edition:2024 +//@ reference: destructors.scope.lifetime-extension.exprs fn temp() -> String { String::from("Hello") @@ -22,7 +22,7 @@ fn main() { let a = &temp(); let b = Some(&temp()); let c = Option::Some::<&String>(&temp()); - use Option::Some as S; + use std::option::Option::Some as S; let d = S(&temp()); let e = X(&temp()); let f = Some(Ok::<_, ()>(std::borrow::Cow::Borrowed(if true { @@ -31,6 +31,6 @@ fn main() { panic!() }))); let some = Some; // Turn the ctor into a regular function. - let g = some(&temp()); //~ERROR temporary value dropped while borrowe + let g = some(&temp()); //~ERROR temporary value dropped while borrowed println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}"); } From 763ef13d3c0ddda792617987b2f13dd40f67c266 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 24 Sep 2025 05:45:12 +0000 Subject: [PATCH 203/537] Remove non-ns version of impl_self_ty and impl_trait --- .../crates/hir-ty/src/builder.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 32 +++----- .../rust-analyzer/crates/hir-ty/src/infer.rs | 4 +- .../crates/hir-ty/src/infer/path.rs | 10 ++- .../rust-analyzer/crates/hir-ty/src/lower.rs | 77 +++---------------- .../crates/hir-ty/src/lower/path.rs | 9 ++- .../crates/hir-ty/src/lower_nextsolver.rs | 4 +- .../hir-ty/src/lower_nextsolver/path.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 22 ++++-- .../crates/hir-ty/src/mir/eval.rs | 5 +- .../crates/hir-ty/src/next_solver/interner.rs | 8 +- .../crates/hir-ty/src/next_solver/solver.rs | 6 +- .../crates/hir-ty/src/tests/incremental.rs | 2 + .../hir-ty/src/tests/method_resolution.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 19 +++-- .../ide-completion/src/tests/type_pos.rs | 18 ++--- .../ide/src/inlay_hints/closing_brace.rs | 2 +- 17 files changed, 97 insertions(+), 127 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 4957c69ae165..5511587c71a4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -378,6 +378,6 @@ impl<'db> TyBuilder>> { db: &'db dyn HirDatabase, def: hir_def::ImplId, ) -> TyBuilder>> { - TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty_ns(def)) + TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def)) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 42f7ec6b59fd..71fb3d44fb70 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -16,8 +16,8 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, - TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db, + Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty, + TyDefId, ValueTyDefId, chalk_db, consteval::ConstEvalError, drop::DropGlue, dyn_compatibility::DynCompatibilityViolation, @@ -143,9 +143,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: ImplId, ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); - #[salsa::invoke(crate::lower::impl_self_ty_query)] + #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)] #[salsa::transparent] - fn impl_self_ty(&self, def: ImplId) -> Binders; + fn impl_self_ty<'db>( + &'db self, + def: ImplId, + ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; // FIXME: Make this a non-interned query. #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)] @@ -169,9 +172,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { Diagnostics, )>; - #[salsa::invoke(crate::lower::impl_trait_query)] + #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)] #[salsa::transparent] - fn impl_trait(&self, def: ImplId) -> Option>; + fn impl_trait<'db>( + &'db self, + def: ImplId, + ) -> Option>>; #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)] fn field_types_with_diagnostics<'db>( @@ -325,24 +331,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // next trait solver - #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)] - #[salsa::transparent] - fn impl_self_ty_ns<'db>( - &'db self, - def: ImplId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; - #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)] #[salsa::transparent] fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>; - #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)] - #[salsa::transparent] - fn impl_trait_ns<'db>( - &'db self, - def: ImplId, - ) -> Option>>; - #[salsa::invoke(crate::lower_nextsolver::field_types_query)] #[salsa::transparent] fn field_types_ns<'db>( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 0a095ea64458..2c57a5e83d04 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1787,7 +1787,9 @@ impl<'db> InferenceContext<'db> { TypeNs::SelfType(impl_id) => { let generics = crate::generics::generics(self.db, impl_id.into()); let substs = generics.placeholder_subst(self.db); - let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let mut ty = + self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); let Some(remaining_idx) = unresolved else { drop(ctx); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 3a50b832cf19..733f3c278806 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -74,8 +74,11 @@ impl<'db> InferenceContext<'db> { } ValueNs::ImplSelf(impl_id) => { let generics = crate::generics::generics(self.db, impl_id.into()); + let interner = DbInterner::new_with(self.db, None, None); let substs = generics.placeholder_subst(self.db); - let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = + self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { Some(ValuePathResolution::GenericDef( struct_id.into(), @@ -359,10 +362,13 @@ impl<'db> InferenceContext<'db> { }; let substs = match container { ItemContainerId::ImplId(impl_id) => { + let interner = DbInterner::new_with(self.db, None, None); let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None) .fill_with_inference_vars(&mut self.table) .build(); - let impl_self_ty = self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs); + let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner); + let impl_self_ty = + self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner); self.unify(&impl_self_ty, &ty); impl_substs } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b55f9cd145e2..0c197b27034b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -25,7 +25,7 @@ use chalk_ir::{ use either::Either; use hir_def::{ AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, + GenericParamId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, @@ -34,8 +34,8 @@ use hir_def::{ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, signatures::{FunctionSignature, TraitFlags}, type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, - TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, + ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef, + TypeRefId, }, }; use hir_expand::name::Name; @@ -59,6 +59,10 @@ use crate::{ }, make_binders, mapping::{from_chalk_trait_id, lt_to_placeholder_idx}, + next_solver::{ + DbInterner, + mapping::{ChalkToNextSolver, NextSolverToChalk}, + }, static_lifetime, to_chalk_trait_id, to_placeholder_idx, utils::all_super_trait_refs, variable_kinds_from_iter, @@ -565,14 +569,6 @@ impl<'a> TyLoweringContext<'a> { Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx)) } - fn lower_trait_ref( - &mut self, - trait_ref: &HirTraitRef, - explicit_self_ty: Ty, - ) -> Option { - self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0) - } - /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the /// **parent**. This is important so we generate the correct bound var/placeholder. @@ -851,21 +847,21 @@ fn named_associated_type_shorthand_candidates( }) }; + let interner = DbInterner::new_with(db, None, None); match res { TypeNs::SelfType(impl_id) => { - // we're _in_ the impl -- the binders get added back later. Correct, - // but it would be nice to make this more explicit - let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0; + let trait_ref = db.impl_trait(impl_id)?; let impl_id_as_generic_def: GenericDefId = impl_id.into(); if impl_id_as_generic_def != def { let subst = TyBuilder::subst_for_def(db, impl_id, None) .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) .build(); - let trait_ref = subst.apply(trait_ref, Interner); + let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); + let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner); search(trait_ref) } else { - search(trait_ref) + search(trait_ref.skip_binder().to_chalk(interner)) } } TypeNs::GenericParam(param_id) => { @@ -1335,31 +1331,6 @@ impl ValueTyDefId { } } -pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { - impl_self_ty_with_diagnostics_query(db, impl_id).0 -} - -pub(crate) fn impl_self_ty_with_diagnostics_query( - db: &dyn HirDatabase, - impl_id: ImplId, -) -> (Binders, Diagnostics) { - let impl_data = db.impl_signature(impl_id); - let resolver = impl_id.resolver(db); - let generics = generics(db, impl_id.into()); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ) - .with_type_param_mode(ParamLoweringMode::Variable); - ( - make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)), - create_diagnostics(ctx.diagnostics), - ) -} - pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { const_param_ty_with_diagnostics_query(db, def).0 } @@ -1397,30 +1368,6 @@ pub(crate) fn const_param_ty_cycle_result( TyKind::Error.intern(Interner) } -pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { - impl_trait_with_diagnostics_query(db, impl_id).map(|it| it.0) -} - -pub(crate) fn impl_trait_with_diagnostics_query( - db: &dyn HirDatabase, - impl_id: ImplId, -) -> Option<(Binders, Diagnostics)> { - let impl_data = db.impl_signature(impl_id); - let resolver = impl_id.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ) - .with_type_param_mode(ParamLoweringMode::Variable); - let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); - let target_trait = impl_data.target_trait.as_ref()?; - let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?); - Some((trait_ref, create_diagnostics(ctx.diagnostics))) -} - pub(crate) fn return_type_impl_traits( db: &dyn HirDatabase, def: hir_def::FunctionId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 279bbff7c0d9..da9dd21183e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -255,8 +255,15 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // `def` can be either impl itself or item within, and we need impl itself // now. let generics = generics.parent_or_self(); + let interner = DbInterner::new_with(self.ctx.db, None, None); let subst = generics.placeholder_subst(self.ctx.db); - self.ctx.db.impl_self_ty(impl_id).substitute(Interner, &subst) + let args: crate::next_solver::GenericArgs<'_> = + subst.to_nextsolver(interner); + self.ctx + .db + .impl_self_ty(impl_id) + .instantiate(interner, args) + .to_chalk(interner) } ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id) .fill_with_bound_vars(self.ctx.in_binders, 0) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs index 02774a63df42..84cd216b8121 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs @@ -920,7 +920,7 @@ pub(crate) fn impl_trait_with_diagnostics_query<'db>( impl_id.into(), LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, ); - let self_ty = db.impl_self_ty_ns(impl_id).skip_binder(); + let self_ty = db.impl_self_ty(impl_id).skip_binder(); let target_trait = impl_data.target_trait.as_ref()?; let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?); Some((trait_ref, create_diagnostics(ctx.diagnostics))) @@ -2024,7 +2024,7 @@ fn named_associated_type_shorthand_candidates<'db, R>( match res { TypeNs::SelfType(impl_id) => { - let trait_ref = db.impl_trait_ns(impl_id)?; + let trait_ref = db.impl_trait(impl_id)?; // FIXME(next-solver): same method in `lower` checks for impl or not // Is that needed here? diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs index 46dc66a8c8ba..0a9f34c9dabd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs @@ -287,7 +287,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { } } } - TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty_ns(impl_id).skip_binder(), + TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(), TypeNs::AdtSelfType(adt) => { let args = crate::next_solver::GenericArgs::identity_for_item( self.ctx.interner, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 93ef64272d14..61d3091a0c1d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -297,11 +297,12 @@ impl TraitImpls { continue; } let target_trait = match db.impl_trait(impl_id) { - Some(tr) => tr.skip_binders().hir_trait_id(), + Some(tr) => tr.skip_binder().def_id.0, None => continue, }; - let self_ty = db.impl_self_ty(impl_id); - let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders()); + let interner = DbInterner::new_with(db, None, None); + let self_ty = db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner); + let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty); map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id); } @@ -414,8 +415,8 @@ impl InherentImpls { continue; } - let self_ty = db.impl_self_ty(impl_id); - let self_ty = self_ty.skip_binders(); + let interner = DbInterner::new_with(db, None, None); + let self_ty = &db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner); match is_inherent_impl_coherent(db, def_map, impl_id, self_ty) { true => { @@ -897,10 +898,13 @@ fn find_matching_impl( table.run_in_snapshot(|table| { let impl_substs = TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build(); + let args: crate::next_solver::GenericArgs<'_> = + impl_substs.to_nextsolver(table.interner); let trait_ref = db .impl_trait(impl_) .expect("non-trait method in find_matching_impl") - .substitute(Interner, &impl_substs); + .instantiate(table.interner, args) + .to_chalk(table.interner); if !table.unify(&trait_ref, &actual_trait_ref) { return None; @@ -1018,7 +1022,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool { let local_crate = impl_.lookup(db).container.krate(); let is_local = |tgt_crate| tgt_crate == local_crate; - let trait_ref = impl_trait.substitute(Interner, &substs); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let trait_ref = impl_trait.instantiate(interner, args).to_chalk(interner); let trait_id = from_chalk_trait_id(trait_ref.trait_id); if is_local(trait_id.module(db).krate()) { // trait to be implemented is local @@ -1824,7 +1830,7 @@ fn is_valid_impl_fn_candidate( let _p = tracing::info_span!("subst_for_def").entered(); let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into()); let expect_self_ty = db - .impl_self_ty_ns(impl_id) + .impl_self_ty(impl_id) .instantiate(table.interner, &impl_subst) .to_chalk(table.interner); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 3d7ad8d3b069..fa63baa5d2ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -432,9 +432,12 @@ impl MirEvalError { let self_ = match func.lookup(db).container { ItemContainerId::ImplId(impl_id) => Some({ let generics = crate::generics::generics(db, impl_id.into()); + let interner = DbInterner::new_with(db, None, None); let substs = generics.placeholder_subst(db); + let args: crate::next_solver::GenericArgs<'_> = + substs.to_nextsolver(interner); db.impl_self_ty(impl_id) - .substitute(Interner, &substs) + .instantiate(interner, args) .display(db, display_target) .to_string() }), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 3ff9fde9768b..b72504a19cf0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1394,7 +1394,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, impl_id: Self::ImplId, ) -> EarlyBinder> { - let trait_ref = self.db().impl_trait_ns(impl_id.0).expect("expected an impl of trait"); + let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait"); trait_ref.map_bound(|trait_ref| { let clause: Clause<'_> = trait_ref.upcast(self); Clauses::new_from_iter( @@ -1633,7 +1633,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { |impls| { for i in impls.for_trait(trait_) { use rustc_type_ir::TypeVisitable; - let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| { + let contains_errors = self.db().impl_trait(i).map_or(false, |b| { b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() }); if contains_errors { @@ -1656,7 +1656,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { for fp in fps { for i in impls.for_trait_and_self_ty(trait_, *fp) { use rustc_type_ir::TypeVisitable; - let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| { + let contains_errors = self.db().impl_trait(i).map_or(false, |b| { b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() }); if contains_errors { @@ -1702,7 +1702,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { impl_id: Self::ImplId, ) -> EarlyBinder> { let db = self.db(); - db.impl_trait_ns(impl_id.0) + db.impl_trait(impl_id.0) // ImplIds for impls where the trait ref can't be resolved should never reach trait solving .expect("invalid impl passed to trait solver") } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 946e57e6cb74..a161423da4d7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -156,16 +156,16 @@ impl<'db> SolverDelegate for SolverContext<'db> { SolverDefId::TypeAliasId(id) => id, _ => panic!("Unexpected SolverDefId"), }; - let trait_ref = self + let trait_ = self .0 .interner .db() .impl_trait(impl_id.0) // ImplIds for impls where the trait ref can't be resolved should never reach solver .expect("invalid impl passed to next-solver") - .into_value_and_skipped_binders() + .skip_binder() + .def_id .0; - let trait_ = trait_ref.hir_trait_id(); let trait_data = trait_.trait_items(self.0.interner.db()); let id = impl_id.0.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index cc5ad2045ed4..8587c13e87f7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -504,8 +504,10 @@ impl SomeStruct { "crate_local_def_map", "trait_impls_in_crate_shim", "attrs_shim", + "impl_trait_with_diagnostics_shim", "impl_signature_shim", "impl_signature_with_source_map_shim", + "impl_self_ty_with_diagnostics_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", "attrs_shim", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 5ada14bc5342..2f8f66647566 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -2050,7 +2050,7 @@ impl dyn Error + Send { /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; - // ^^^^ expected Box, got Box + // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 5592ca285fb0..c8ce46c4732c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -869,10 +869,13 @@ impl Module { .collect(); if !missing.is_empty() { - let self_ty = db.impl_self_ty(impl_def.id).substitute( - Interner, - &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db), - ); + let interner = DbInterner::new_with(db, None, None); + let args: crate::next_solver::GenericArgs<'_> = + hir_ty::generics::generics(db, impl_def.id.into()) + .placeholder_subst(db) + .to_nextsolver(interner); + let self_ty = + db.impl_self_ty(impl_def.id).instantiate(interner, args).to_chalk(interner); let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) = self_ty.kind(Interner) { @@ -4546,21 +4549,23 @@ impl Impl { } pub fn trait_(self, db: &dyn HirDatabase) -> Option { - let trait_ref = db.impl_trait_ns(self.id)?; + let trait_ref = db.impl_trait(self.id)?; let id = trait_ref.skip_binder().def_id; Some(Trait { id: id.0 }) } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { - let trait_ref = db.impl_trait_ns(self.id)?.instantiate_identity(); + let trait_ref = db.impl_trait(self.id)?.instantiate_identity(); let resolver = self.id.resolver(db); Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) } pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); let substs = TyBuilder::placeholder_subst(db, self.id); - let ty = db.impl_self_ty(self.id).substitute(Interner, &substs); + let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); + let ty = db.impl_self_ty(self.id).instantiate(interner, args).to_chalk(interner); Type::new_with_resolver_inner(db, &resolver, ty) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index c7e2d058257e..125e11e9e358 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -429,18 +429,18 @@ trait Tr { impl Tr<$0 "#, expect![[r#" - en Enum Enum - ma makro!(…) macro_rules! makro + en Enum Enum + ma makro!(…) macro_rules! makro md module - sp Self dyn Tr<{unknown}> - st Record Record - st S S - st Tuple Tuple - st Unit Unit + sp Self dyn Tr<{unknown}> + 'static + st Record Record + st S S + st Tuple Tuple + st Unit Unit tt Tr tt Trait - un Union Union - bt u32 u32 + un Union Union + bt u32 u32 kw crate:: kw self:: "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index e80c9dc9d473..9d246eda57e0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -191,7 +191,7 @@ impl Tr for () { //^ impl Tr for () impl dyn Tr { } -//^ impl dyn Tr +//^ impl dyn Tr + 'static static S0: () = 0; static S1: () = {}; From 6e897949a5a1fb3bb70c5166cced9b24af879882 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 24 Sep 2025 14:36:09 +0800 Subject: [PATCH 204/537] Fix applicable on if-let-chain for invert_if Example --- ```rust fn f() { i$0f x && let Some(_) = Some(1) { 1 } else { 0 } } ``` **Before this PR**: ```rust fn f() { if !(x && let Some(_) = Some(1)) { 0 } else { 1 } } ``` **After this PR**: Assist not applicable --- .../crates/ide-assists/src/handlers/invert_if.rs | 12 ++++++++++++ .../crates/ide-db/src/syntax_helpers/node_ext.rs | 5 +---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs index d198870b023e..7576d2fab976 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs @@ -124,6 +124,18 @@ mod tests { ) } + #[test] + fn invert_if_doesnt_apply_with_if_let_chain() { + check_assist_not_applicable( + invert_if, + "fn f() { i$0f x && let Some(_) = Some(1) { 1 } else { 0 } }", + ); + check_assist_not_applicable( + invert_if, + "fn f() { i$0f let Some(_) = Some(1) && x { 1 } else { 0 } }", + ); + } + #[test] fn invert_if_option_case() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs index cefd8fd49676..e1d140730edc 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -265,10 +265,7 @@ pub fn is_pattern_cond(expr: ast::Expr) -> bool { ast::Expr::BinExpr(expr) if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) => { - expr.lhs() - .map(is_pattern_cond) - .or_else(|| expr.rhs().map(is_pattern_cond)) - .unwrap_or(false) + expr.lhs().map_or(false, is_pattern_cond) || expr.rhs().map_or(false, is_pattern_cond) } ast::Expr::ParenExpr(expr) => expr.expr().is_some_and(is_pattern_cond), ast::Expr::LetExpr(_) => true, From 03fd823dbf39ebbd69f6e20e9d44c0cb893140c3 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 24 Sep 2025 13:26:03 +0530 Subject: [PATCH 205/537] library: std: sys: pal: uefi: Add some comments I seemed to have forgotten that since I am using GET_PROTOCOL attribute for the std usecases, I did not need to close the protocols explicitly. So adding these comments as a note to future self not to waste time on the same thing again. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index b50574de937a..c0d69c3e0029 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -92,6 +92,9 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result( handle: NonNull, mut protocol_guid: Guid, @@ -473,6 +476,7 @@ impl<'a> crate::fmt::Debug for DevicePathNode<'a> { } } +/// Protocols installed by Rust side on a handle. pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, From 8e37f0f120ba8b77889bea3fc607004c89afffb4 Mon Sep 17 00:00:00 2001 From: sysrex <769991+sysrex@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:13:08 +0100 Subject: [PATCH 206/537] chore: remove discord references from the std library as well --- library/std/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 33e3bf0c085d..9266a0af2c83 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -94,7 +94,7 @@ //! pull-requests for your suggested changes. //! //! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on [Discord][rust-discord] +//! improved, submit a PR, or chat with us first on [Zulip][rust-zulip] //! #docs. //! //! # A Tour of The Rust Standard Library @@ -212,7 +212,7 @@ //! [multithreading]: thread //! [other]: #what-is-in-the-standard-library-documentation //! [primitive types]: ../book/ch03-02-data-types.html -//! [rust-discord]: https://discord.gg/rust-lang +//! [rust-zulip]: https://rust-lang.zulipchat.com/ //! [array]: prim@array //! [slice]: prim@slice From 3378997867a9501beb3137f1ae508aadf1b9fc4b Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 12:50:50 +0200 Subject: [PATCH 207/537] fix wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémy Rakic --- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e05c5b224858..be44dc955c21 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -540,7 +540,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // If there are nested bodies in promoteds, we also need to update their - // location to something in the actually body, not the promoted. + // location to something in the actual body, not the promoted. // // We don't update the constraint categories of the resulting constraints // as returns in nested bodies are a proper return, even if that nested body From 32d24f9efa81a1c467da21c3ae2d93a6b00a9f5b Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 13:02:27 +0200 Subject: [PATCH 208/537] allow bound regions in writeback --- compiler/rustc_hir_typeck/src/writeback.rs | 6 +++-- tests/crashes/117808.rs | 27 ------------------- .../writeback-predicate-bound-region.rs | 14 ++++++++++ 3 files changed, 18 insertions(+), 29 deletions(-) delete mode 100644 tests/crashes/117808.rs create mode 100644 tests/ui/traits/next-solver/writeback-predicate-bound-region.rs diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6192420898f6..d01eeb9a4b69 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -1003,8 +1003,10 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - debug_assert!(!r.is_bound(), "Should not be resolving bound region."); - self.fcx.tcx.lifetimes.re_erased + match r.kind() { + ty::ReBound(..) => r, + _ => self.fcx.tcx.lifetimes.re_erased, + } } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/tests/crashes/117808.rs b/tests/crashes/117808.rs deleted file mode 100644 index 2c727986dd07..000000000000 --- a/tests/crashes/117808.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ known-bug: #117808 -//@ edition:2021 -//@ needs-rustc-debug-assertions - -use std::future::Future; - -fn hrc AsyncClosure<'a, (), R>>(f: F) -> F { - f -} - -fn main() { - hrc(|x| async {}); -} - -trait AsyncClosure<'a, I, R> -where - I: 'a, -{ -} - -impl<'a, I, R, Fut, F> AsyncClosure<'a, I, R> for F -where - I: 'a, - F: Fn(&'a I) -> Fut, - Fut: Future + Send + 'a, -{ -} diff --git a/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs b/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs new file mode 100644 index 000000000000..a7ed5dbcf086 --- /dev/null +++ b/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs @@ -0,0 +1,14 @@ +//@ edition: 2024 +//@ check-pass +//@ compile-flags: -Znext-solver + +// This previously ICE'd during writeback when resolving +// the stalled coroutine predicate due to its bound lifetime. + +trait Trait<'a> {} +impl<'a, T: Send> Trait<'a> for T {} + +fn is_trait Trait<'a>>(_: T) {} +fn main() { + is_trait(async {}) +} From 2886ca496a8adff7424da8b19eeaffa9d392210c Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 13:04:36 +0200 Subject: [PATCH 209/537] imrpove type_op failure ICE --- .../src/traits/query/type_op/custom.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 6ce68507d652..a96cb738b81f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -100,9 +100,9 @@ where } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) { Err(guar) } else { - Err(infcx - .dcx() - .delayed_bug(format!("errors selecting obligation during MIR typeck: {errors:?}"))) + Err(infcx.dcx().delayed_bug(format!( + "errors selecting obligation during MIR typeck: {name} {root_def_id:?} {errors:?}" + ))) } })?; From 0a41add6293d76b165968d70f95e7edbbe65fe11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Sep 2025 19:46:30 +0200 Subject: [PATCH 210/537] const-eval: improve and actually test the errors when pointers might be outside the range of a scalar --- compiler/rustc_const_eval/messages.ftl | 4 ++-- compiler/rustc_const_eval/src/errors.rs | 7 +++---- .../rustc_const_eval/src/interpret/validity.rs | 5 +---- .../rustc_middle/src/mir/interpret/error.rs | 5 +---- tests/ui/consts/const-eval/ub-nonnull.rs | 4 ++++ tests/ui/consts/const-eval/ub-nonnull.stderr | 17 ++++++++++++++--- tests/ui/consts/const-eval/ub-ref-ptr.rs | 11 ++++++++++- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 17 ++++++++++++++--- 8 files changed, 49 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 700d7c26752b..97674aea540c 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -479,11 +479,11 @@ const_eval_validation_never_val = {$front_matter}: encountered a value of the ne const_eval_validation_null_box = {$front_matter}: encountered a null box const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer const_eval_validation_null_ref = {$front_matter}: encountered a null reference -const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} -const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range} const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 2d412ee5ec26..29bddd59ffd5 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -668,7 +668,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { MutableRefInConst => const_eval_validation_mutable_ref_in_const, NullFnPtr => const_eval_validation_null_fn_ptr, NeverVal => const_eval_validation_never_val, - NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, + NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range, PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, OutOfRange { .. } => const_eval_validation_out_of_range, UnsafeCellInImmutable => const_eval_validation_unsafe_cell, @@ -804,9 +804,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { | InvalidFnPtr { value } => { err.arg("value", value); } - NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { - add_range_arg(range, max_value, err) - } + PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err), OutOfRange { range, max_value, value } => { err.arg("value", value); add_range_arg(range, max_value, err); @@ -826,6 +824,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { | MutableRefToImmutable | MutableRefInConst | NullFnPtr + | NonnullPtrMaybeNull | NeverVal | UnsafeCellInImmutable | InvalidMetaSliceTooLarge { .. } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9adc3fa46318..8648b83b8dcd 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -819,10 +819,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if start == 1 && end == max_value { // Only null is the niche. So make sure the ptr is NOT null. if self.ecx.scalar_may_be_null(scalar)? { - throw_validation_failure!( - self.path, - NullablePtrOutOfRange { range: valid_range, max_value } - ) + throw_validation_failure!(self.path, NonnullPtrMaybeNull) } else { return interp_ok(()); } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7c72a8ec243a..1a9ae4bbceb4 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> { MutableRefInConst, NullFnPtr, NeverVal, - NullablePtrOutOfRange { - range: WrappingRange, - max_value: u128, - }, + NonnullPtrMaybeNull, PtrOutOfRange { range: WrappingRange, max_value: u128, diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index 916468426248..851f3996cd10 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -57,4 +57,8 @@ const NULL_FAT_PTR: NonNull = unsafe { mem::transmute((0_usize, meta)) }; +static S: u32 = 0; // just a static to construct a maybe-null pointer off of +const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) }; +//~^ ERROR invalid value + fn main() {} diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 91c82efbc5ed..e4486e3c500b 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -9,7 +9,7 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC2 which is only 1 byte from the end of the allocation --> $DIR/ub-nonnull.rs:22:29 | LL | let out_of_bounds_ptr = &ptr[255]; @@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; @@ -80,6 +80,17 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { HEX_DUMP } -error: aborting due to 8 previous errors +error[E0080]: constructing invalid value: encountered a maybe-null pointer, but expected something that is definitely non-zero + --> $DIR/ub-nonnull.rs:61:1 + | +LL | const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index d8e5102fcbe7..5ff9748af0c1 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -4,7 +4,7 @@ //@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" //@ dont-require-annotations: NOTE //@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1" - +#![feature(rustc_attrs)] #![allow(invalid_value)] use std::mem; @@ -65,5 +65,14 @@ const UNALIGNED_READ: () = unsafe { ptr.read(); //~ ERROR accessing memory }; +// Check the general case of a pointer value not falling into the scalar valid range. +#[rustc_layout_scalar_valid_range_start(1000)] +pub struct High { + pointer: *const (), +} +static S: u32 = 0; // just a static to construct a pointer with unknown absolute address +const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) }; +//~^ ERROR invalid value + fn main() {} diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index c45f66c29259..9170cde94e2a 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -103,7 +103,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC3[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:49:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; @@ -124,7 +124,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC5[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:54:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; @@ -162,6 +162,17 @@ error[E0080]: accessing memory based on pointer with alignment 1, but alignment LL | ptr.read(); | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here -error: aborting due to 15 previous errors +error[E0080]: constructing invalid value: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000 + --> $DIR/ub-ref-ptr.rs:74:1 + | +LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0080`. From 8328c3dada0c888b1c570f97314b3f697d4b2a96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Sep 2025 12:12:41 +0200 Subject: [PATCH 211/537] const validation: better error for maybe-null references --- compiler/rustc_const_eval/messages.ftl | 10 +++- compiler/rustc_const_eval/src/errors.rs | 10 ++-- .../src/interpret/validity.rs | 13 ++++- .../rustc_middle/src/mir/interpret/error.rs | 2 + src/tools/compiletest/src/runtest.rs | 2 +- tests/ui/consts/const-eval/ub-ref-ptr.rs | 12 +++- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 58 +++++++++++++------ tests/ui/consts/const_transmute_type_id7.rs | 16 +++++ .../ui/consts/const_transmute_type_id7.stderr | 14 +++++ 9 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id7.rs create mode 100644 tests/ui/consts/const_transmute_type_id7.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 97674aea540c..010ffa60c7a5 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -476,9 +476,15 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` -const_eval_validation_null_box = {$front_matter}: encountered a null box +const_eval_validation_null_box = {$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null + } box const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer -const_eval_validation_null_ref = {$front_matter}: encountered a null reference +const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null + } reference const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 29bddd59ffd5..d352a6384245 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -696,8 +696,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, - NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box, - NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref, + NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box, + NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref, DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { const_eval_validation_dangling_box_no_provenance } @@ -820,8 +820,10 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { err.arg("vtable_dyn_type", vtable_dyn_type.to_string()); err.arg("expected_dyn_type", expected_dyn_type.to_string()); } - NullPtr { .. } - | MutableRefToImmutable + NullPtr { maybe, .. } => { + err.arg("maybe", maybe); + } + MutableRefToImmutable | MutableRefInConst | NullFnPtr | NonnullPtrMaybeNull diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 8648b83b8dcd..5f088fe37e80 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -511,7 +511,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message ), self.path, - Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind }, + Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false }, Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate @@ -538,8 +538,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ); // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero // that does not imply non-null. - if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? { - throw_validation_failure!(self.path, NullPtr { ptr_kind }) + let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx); + if self.ecx.scalar_may_be_null(scalar)? { + let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); + throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe }) } // Do not allow references to uninhabited types. if place.layout.is_uninhabited() { @@ -757,6 +759,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } else { // Otherwise (for standalone Miri), we have to still check it to be non-null. if self.ecx.scalar_may_be_null(scalar)? { + let maybe = + !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); + // This can't be a "maybe-null" pointer since the check for this being + // a fn ptr at all already ensures that the pointer is inbounds. + assert!(!maybe); throw_validation_failure!(self.path, NullFnPtr); } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 1a9ae4bbceb4..951aac503fee 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -541,6 +541,8 @@ pub enum ValidationErrorKind<'tcx> { }, NullPtr { ptr_kind: PointerKind, + /// Records whether this pointer is definitely null or just may be null. + maybe: bool, }, DanglingPtrNoProvenance { ptr_kind: PointerKind, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 89fb8eb4357b..59bd3111ecf3 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2655,7 +2655,7 @@ impl<'test> TestCx<'test> { // The alloc-id appears in pretty-printed allocations. normalized = static_regex!( - r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?()?( \([0-9]+ ptr bytes\))?─*╼" + r"╾─*a(lloc)?([0-9]+)(\+0x[0-9a-f]+)?()?( \([0-9]+ ptr bytes\))?─*╼" ) .replace_all(&normalized, |caps: &Captures<'_>| { // Renumber the captured index. diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index 5ff9748af0c1..a5fdde1f9a4e 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -27,6 +27,11 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) }; const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; //~^ ERROR invalid value +const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({ +//~^ ERROR maybe-null + let ref_ = &0u8; + (ref_ as *const u8).wrapping_add(10) +}) }; // It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, // but that would fail to compile; so we ended up breaking user code that would @@ -57,7 +62,12 @@ const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; //~^ ERROR invalid value const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; //~^ ERROR invalid value - +const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({ +//~^ ERROR invalid value + fn fun() {} + let ptr = fun as fn(); + (ptr as *const u8).wrapping_add(10) +}) }; const UNALIGNED_READ: () = unsafe { let x = &[0u8; 4]; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 9170cde94e2a..349a98f11be4 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -42,8 +42,19 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; HEX_DUMP } +error[E0080]: constructing invalid value: encountered a maybe-null box + --> $DIR/ub-ref-ptr.rs:30:1 + | +LL | const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:34:1 + --> $DIR/ub-ref-ptr.rs:39:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here @@ -52,7 +63,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:37:39 + --> $DIR/ub-ref-ptr.rs:42:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here @@ -61,13 +72,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:37:38 + --> $DIR/ub-ref-ptr.rs:42:38 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: unable to turn pointer into integer - --> $DIR/ub-ref-ptr.rs:40:86 + --> $DIR/ub-ref-ptr.rs:45:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here @@ -76,13 +87,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: erroneous constant encountered - --> $DIR/ub-ref-ptr.rs:40:85 + --> $DIR/ub-ref-ptr.rs:45:85 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; | ^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) - --> $DIR/ub-ref-ptr.rs:43:1 + --> $DIR/ub-ref-ptr.rs:48:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -93,7 +104,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) - --> $DIR/ub-ref-ptr.rs:46:1 + --> $DIR/ub-ref-ptr.rs:51:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -103,8 +114,8 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory - --> $DIR/ub-ref-ptr.rs:49:41 +error[E0080]: reading memory at ALLOC6[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:54:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here @@ -114,7 +125,7 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; } error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer - --> $DIR/ub-ref-ptr.rs:52:1 + --> $DIR/ub-ref-ptr.rs:57:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -124,8 +135,8 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: reading memory at ALLOC5[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory - --> $DIR/ub-ref-ptr.rs:54:38 +error[E0080]: reading memory at ALLOC7[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory + --> $DIR/ub-ref-ptr.rs:59:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here @@ -135,7 +146,7 @@ LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; } error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer - --> $DIR/ub-ref-ptr.rs:56:1 + --> $DIR/ub-ref-ptr.rs:61:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -145,8 +156,8 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; HEX_DUMP } -error[E0080]: constructing invalid value: encountered ALLOC2, but expected a function pointer - --> $DIR/ub-ref-ptr.rs:58:1 +error[E0080]: constructing invalid value: encountered ALLOC3, but expected a function pointer + --> $DIR/ub-ref-ptr.rs:63:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -156,14 +167,25 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; HEX_DUMP } +error[E0080]: constructing invalid value: encountered ALLOC4+0xa, but expected a function pointer + --> $DIR/ub-ref-ptr.rs:65:1 + | +LL | const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required - --> $DIR/ub-ref-ptr.rs:65:5 + --> $DIR/ub-ref-ptr.rs:75:5 | LL | ptr.read(); | ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here error[E0080]: constructing invalid value: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000 - --> $DIR/ub-ref-ptr.rs:74:1 + --> $DIR/ub-ref-ptr.rs:84:1 | LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value @@ -173,6 +195,6 @@ LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) }; HEX_DUMP } -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_transmute_type_id7.rs b/tests/ui/consts/const_transmute_type_id7.rs new file mode 100644 index 000000000000..73b8187a8007 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id7.rs @@ -0,0 +1,16 @@ +//! Ensure a decent error message for maybe-null references. +//! (see ) + +// Strip out raw byte dumps to make comparison platform-independent: +//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" + +#![feature(const_trait_impl, const_cmp)] + +use std::any::TypeId; +use std::mem::transmute; + +const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::()) }; +//~^ERROR: maybe-null + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id7.stderr b/tests/ui/consts/const_transmute_type_id7.stderr new file mode 100644 index 000000000000..664975831f40 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id7.stderr @@ -0,0 +1,14 @@ +error[E0080]: constructing invalid value at [0]: encountered a maybe-null reference + --> $DIR/const_transmute_type_id7.rs:13:1 + | +LL | const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value + | + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From a875f7779e3c3b9023bff24b6beca08e7be0e0e8 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 24 Sep 2025 14:13:34 +0200 Subject: [PATCH 212/537] alloc: simplify `Default` for `Box` and `Rc` --- library/alloc/src/ffi/c_str.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index b0c8c4b1ca4a..3e78d680ea68 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -970,17 +970,14 @@ impl Default for Rc { /// This may or may not share an allocation with other Rcs on the same thread. #[inline] fn default() -> Self { - let rc = Rc::<[u8]>::from(*b"\0"); - // `[u8]` has the same layout as `CStr`, and it is `NUL` terminated. - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } + Rc::from(c"") } } #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { - let boxed: Box<[u8]> = Box::from([0]); - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } + Box::from(c"") } } From 0e7cc32633ea7c7978529d3d4478b17474383a18 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 24 Sep 2025 21:28:50 +0900 Subject: [PATCH 213/537] Switch next-solver related rustc dependencies of r-a to crates.io ones --- .../rust-analyzer/crates/hir-def/src/lib.rs | 4 --- .../rust-analyzer/crates/hir-ty/src/lib.rs | 31 +++---------------- .../crates/hir-ty/src/next_solver/consts.rs | 2 -- .../hir-ty/src/next_solver/predicate.rs | 2 -- .../crates/hir-ty/src/next_solver/ty.rs | 2 -- src/tools/rust-analyzer/crates/hir/src/lib.rs | 4 --- 6 files changed, 5 insertions(+), 40 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 301d4cca0666..e5c213ca937c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -15,10 +15,6 @@ extern crate rustc_parse_format; #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_parse_format as rustc_parse_format; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_abi; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_abi as rustc_abi; pub mod db; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 451622ef7472..2e59a488e673 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -3,45 +3,24 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#[cfg(feature = "in-rust-tree")] -extern crate rustc_index; +// FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but +// temporarily switched to crates.io versions due to hardships that working on them from rustc +// demands corresponding changes on rust-analyzer at the same time. +// For details, see the zulip discussion below: +// https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/relying.20on.20in-tree.20.60rustc_type_ir.60.2F.60rustc_next_trait_solver.60/with/541055689 -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_index as rustc_index; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_abi; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_abi as rustc_abi; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_pattern_analysis; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_ast_ir; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_ast_ir as rustc_ast_ir; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_type_ir; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_type_ir as rustc_type_ir; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_next_trait_solver; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_data_structures as ena; - mod builder; mod chalk_db; mod chalk_ext; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 7ebefa76ed02..0b3582051bc0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -36,8 +36,6 @@ impl<'db> Const<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - #[cfg(feature = "in-rust-tree")] - stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Const::new_(interner.db(), InternedWrapperNoDebug(cached)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index 86545415009a..99b1354b6335 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -227,8 +227,6 @@ impl<'db> Predicate<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - #[cfg(feature = "in-rust-tree")] - stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Predicate::new_(interner.db(), InternedWrapperNoDebug(cached)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index c7a747ade3e7..70139e866694 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -60,8 +60,6 @@ impl<'db> Ty<'db> { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - #[cfg(feature = "in-rust-tree")] - stable_hash: ena::fingerprint::Fingerprint::ZERO, }; Ty::new_(interner.db(), InternedWrapperNoDebug(cached)) } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f8dacf0fb863..027a386abe8c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -20,10 +20,6 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] -#[cfg(feature = "in-rust-tree")] -extern crate rustc_type_ir; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_type_ir as rustc_type_ir; mod attrs; From 7a0adc08786df857e810c9f6a5a0cb6cae32659b Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 15:02:41 +0200 Subject: [PATCH 214/537] add test --- .../coroutine/copy-fast-path-query-cycle.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/ui/coroutine/copy-fast-path-query-cycle.rs diff --git a/tests/ui/coroutine/copy-fast-path-query-cycle.rs b/tests/ui/coroutine/copy-fast-path-query-cycle.rs new file mode 100644 index 000000000000..644cba0d47af --- /dev/null +++ b/tests/ui/coroutine/copy-fast-path-query-cycle.rs @@ -0,0 +1,40 @@ +//@ edition: 2024 +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for #146813. We previously used a pseudo-canonical +// query during HIR typeck which caused a query cycle when looking at the +// witness of a coroutine. + +use std::future::Future; + +trait ConnectMiddleware {} + +trait ConnectHandler: Sized { + fn with(self, _: M) -> impl ConnectHandler + where + M: ConnectMiddleware, + { + LayeredConnectHandler + } +} + +struct LayeredConnectHandler; +impl ConnectHandler for LayeredConnectHandler {} +impl ConnectHandler for F where F: FnOnce() {} + +impl ConnectMiddleware for F +where + F: FnOnce() -> Fut, + Fut: Future + Send, +{ +} + +pub async fn fails() { + { || {} } + .with(async || ()) + .with(async || ()) + .with(async || ()); +} +fn main() {} From d91025316554f9cff948639ee34bf217ef724947 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Sat, 13 Sep 2025 08:51:28 -0400 Subject: [PATCH 215/537] constify Default on Nanoseconds --- library/core/src/num/niche_types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs index 610d9d8cf92e..9ac0eb72bdcb 100644 --- a/library/core/src/num/niche_types.rs +++ b/library/core/src/num/niche_types.rs @@ -112,7 +112,8 @@ impl Nanoseconds { pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) }; } -impl Default for Nanoseconds { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for Nanoseconds { #[inline] fn default() -> Self { Self::ZERO From 4acea466e42758468e6cd1de7c6173eabcd5f1b3 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 24 Sep 2025 13:26:53 +0000 Subject: [PATCH 216/537] simplify setup_constraining_predicates, and note it is potentially cubic --- .../src/constrained_generic_params.rs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 366b3943a058..44d7f3a5e8bc 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>( // which is `O(nt)` where `t` is the depth of type-parameter constraints, // remembering that `t` should be less than 7 in practice. // + // FIXME(hkBst): the big-O bound above would be accurate for the number + // of calls to `parameters_for`, which itself is some O(complexity of type). + // That would make this potentially cubic instead of merely quadratic... + // ...unless we cache those `parameters_for` calls. + // // Basically, I iterate over all projections and swap every // "ready" projection to the start of the list, such that // all of the projections before `i` are topologically sorted // and constrain all the parameters in `input_parameters`. // - // In the example, `input_parameters` starts by containing `U` - which - // is constrained by the trait-ref - and so on the first pass we + // In the first example, `input_parameters` starts by containing `U`, + // which is constrained by the self type `U`. Then, on the first pass we // observe that `::Item = T` is a "ready" projection that - // constrains `T` and swap it to front. As it is the sole projection, + // constrains `T` and swap it to the front. As it is the sole projection, // no more swaps can take place afterwards, with the result being // * ::Item = T // * T: Debug @@ -193,33 +198,28 @@ pub(crate) fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() { - // Special case: watch out for some kind of sneaky attempt - // to project out an associated type defined by this very - // trait. - let unbound_trait_ref = projection.projection_term.trait_ref(tcx); - if Some(unbound_trait_ref) == impl_trait_ref { - continue; - } + if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() && - // A projection depends on its input types and determines its output - // type. For example, if we have - // `<::Baz as Iterator>::Output = ::Output` - // Then the projection only applies if `T` is known, but it still - // does not determine `U`. + // Special case: watch out for some kind of sneaky attempt to + // project out an associated type defined by this very trait. + !impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) && + + // A projection depends on its input types and determines its output + // type. For example, if we have + // `<::Baz as Iterator>::Output = ::Output` + // then the projection only applies if `T` is known, but it still + // does not determine `U`. + { let inputs = parameters_for(tcx, projection.projection_term, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); - if !relies_only_on_inputs { - continue; - } + relies_only_on_inputs + } { input_parameters.extend(parameters_for(tcx, projection.term, false)); - } else { - continue; + + predicates.swap(i, j); + i += 1; + changed = true; } - // fancy control flow to bypass borrow checker - predicates.swap(i, j); - i += 1; - changed = true; } debug!( "setup_constraining_predicates: predicates={:?} \ From 56734495e2fd485a7be1ba77da1bf18a0eca4636 Mon Sep 17 00:00:00 2001 From: BenjaminBrienen Date: Wed, 24 Sep 2025 14:25:10 +0200 Subject: [PATCH 217/537] feature: Implement vec_try_remove Vec::try_remove is a non-panicking version of Vec::remove --- library/alloc/src/vec/mod.rs | 32 ++++++++++++++++++++++++++++++-- library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/vec.rs | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ebdb86f98a85..694b7b2df08f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2173,9 +2173,37 @@ impl Vec { panic!("removal index (is {index}) should be < len (is {len})"); } + match self.try_remove(index) { + Some(elem) => elem, + None => assert_failed(index, self.len()), + } + } + + /// Remove and return the element at position `index` within the vector, + /// shifting all elements after it to the left, or [`None`] if it does not + /// exist. + /// + /// Note: Because this shifts over the remaining elements, it has a + /// worst-case performance of *O*(*n*). If you'd like to remove + /// elements from the beginning of the `Vec`, consider using + /// [`VecDeque::pop_front`] instead. + /// + /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_try_remove)] + /// let mut v = vec![1, 2, 3]; + /// assert_eq!(v.try_remove(0), Some(1)); + /// assert_eq!(v.try_remove(2), None); + /// ``` + #[unstable(feature = "vec_try_remove", issue = "146954")] + #[rustc_confusables("delete", "take", "remove")] + pub fn try_remove(&mut self, index: usize) -> Option { let len = self.len(); if index >= len { - assert_failed(index, len); + return None; } unsafe { // infallible @@ -2191,7 +2219,7 @@ impl Vec { ptr::copy(ptr.add(1), ptr, len - index - 1); } self.set_len(len - 1); - ret + Some(ret) } } diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 8c3ce156f3c1..cba9883e148e 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] +#![feature(vec_try_remove)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 33a34daccbfd..ea334ab0f143 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -630,6 +630,21 @@ fn test_swap_remove_empty() { vec.swap_remove(0); } +#[test] +fn test_try_remove() { + let mut vec = vec![1, 2, 3]; + // We are attempting to remove vec[0] which contains 1 + assert_eq!(vec.try_remove(0), Some(1)); + // Now `vec` looks like: [2, 3] + // We will now try to remove vec[2] which does not exist + // This should return `None` + assert_eq!(vec.try_remove(2), None); + + // We will try the same thing with an empty vector + let mut v: Vec = vec![]; + assert!(v.try_remove(0).is_none()); +} + #[test] fn test_move_items() { let vec = vec![1, 2, 3]; From 30289353e8e04eff33a0e533b6b398c308b24025 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 22 Sep 2025 15:50:22 +0000 Subject: [PATCH 218/537] Improve derive suggestion of const param Make the suggestion not to remove the adt and use the name of the adt variant --- .../src/error_reporting/traits/fulfillment_errors.rs | 11 +++++++---- .../forbid-non-structural_match-types.stderr | 2 +- tests/ui/const-generics/issue-80471.stderr | 4 ++-- tests/ui/const-generics/issues/issue-97278.stderr | 4 ++-- .../ui/consts/refs_check_const_eq-issue-88384.stderr | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 149f5e638b1a..d485eb7266b2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1305,8 +1305,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if ty.is_structural_eq_shallow(self.tcx) { diag.span_suggestion( - span, - "add `#[derive(ConstParamTy)]` to the struct", + span.shrink_to_lo(), + format!("add `#[derive(ConstParamTy)]` to the {}", def.descr()), "#[derive(ConstParamTy)]\n", Applicability::MachineApplicable, ); @@ -1314,8 +1314,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // FIXME(adt_const_params): We should check there's not already an // overlapping `Eq`/`PartialEq` impl. diag.span_suggestion( - span, - "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct", + span.shrink_to_lo(), + format!( + "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the {}", + def.descr() + ), "#[derive(ConstParamTy, PartialEq, Eq)]\n", Applicability::MachineApplicable, ); diff --git a/tests/ui/const-generics/forbid-non-structural_match-types.stderr b/tests/ui/const-generics/forbid-non-structural_match-types.stderr index 8ef629329f10..94afded9469e 100644 --- a/tests/ui/const-generics/forbid-non-structural_match-types.stderr +++ b/tests/ui/const-generics/forbid-non-structural_match-types.stderr @@ -6,8 +6,8 @@ LL | struct D; | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct | -LL - struct C; LL + #[derive(ConstParamTy, PartialEq, Eq)] +LL | struct C; | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issue-80471.stderr b/tests/ui/const-generics/issue-80471.stderr index 8cf3d68e5d69..fff2eb53cf12 100644 --- a/tests/ui/const-generics/issue-80471.stderr +++ b/tests/ui/const-generics/issue-80471.stderr @@ -4,10 +4,10 @@ error[E0741]: `Nat` must implement `ConstParamTy` to be used as the type of a co LL | fn foo() {} | ^^^ | -help: add `#[derive(ConstParamTy)]` to the struct +help: add `#[derive(ConstParamTy)]` to the enum | -LL - enum Nat { LL + #[derive(ConstParamTy)] +LL | enum Nat { | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-97278.stderr b/tests/ui/const-generics/issues/issue-97278.stderr index 4894ddb7b8db..21a5fc94032c 100644 --- a/tests/ui/const-generics/issues/issue-97278.stderr +++ b/tests/ui/const-generics/issues/issue-97278.stderr @@ -4,10 +4,10 @@ error[E0741]: `Bar` must implement `ConstParamTy` to be used as the type of a co LL | fn test() {} | ^^^ | -help: add `#[derive(ConstParamTy)]` to the struct +help: add `#[derive(ConstParamTy)]` to the enum | -LL - enum Bar { LL + #[derive(ConstParamTy)] +LL | enum Bar { | error: aborting due to 1 previous error diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr index 65e4dc22c288..62c5c5276411 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -15,8 +15,8 @@ LL | struct Foo; | help: add `#[derive(ConstParamTy)]` to the struct | -LL - struct CompileTimeSettings { LL + #[derive(ConstParamTy)] +LL | struct CompileTimeSettings { | error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter @@ -27,8 +27,8 @@ LL | impl Foo { | help: add `#[derive(ConstParamTy)]` to the struct | -LL - struct CompileTimeSettings { LL + #[derive(ConstParamTy)] +LL | struct CompileTimeSettings { | error: aborting due to 2 previous errors; 1 warning emitted From 5a4e53603631475335bab3e1416f4aca61172094 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Wed, 24 Sep 2025 12:55:38 +0800 Subject: [PATCH 219/537] Fix infinite recursion in Path::eq with String --- library/std/src/path.rs | 12 ++++++------ library/std/tests/path.rs | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 70ba502d6842..88d8a4f21cac 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2107,7 +2107,7 @@ impl PartialEq for PathBuf { impl cmp::PartialEq for PathBuf { #[inline] fn eq(&self, other: &str) -> bool { - Path::eq(self, other) + self.as_path() == other } } @@ -2115,7 +2115,7 @@ impl cmp::PartialEq for PathBuf { impl cmp::PartialEq for str { #[inline] fn eq(&self, other: &PathBuf) -> bool { - other == self + self == other.as_path() } } @@ -2123,7 +2123,7 @@ impl cmp::PartialEq for str { impl cmp::PartialEq for PathBuf { #[inline] fn eq(&self, other: &String) -> bool { - **self == **other + self.as_path() == other.as_str() } } @@ -2131,7 +2131,7 @@ impl cmp::PartialEq for PathBuf { impl cmp::PartialEq for String { #[inline] fn eq(&self, other: &PathBuf) -> bool { - other == self + self.as_str() == other.as_path() } } @@ -3426,7 +3426,7 @@ impl cmp::PartialEq for str { impl cmp::PartialEq for Path { #[inline] fn eq(&self, other: &String) -> bool { - self == &*other + self == other.as_str() } } @@ -3434,7 +3434,7 @@ impl cmp::PartialEq for Path { impl cmp::PartialEq for String { #[inline] fn eq(&self, other: &Path) -> bool { - other == self + self.as_str() == other } } diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index fa76c50597b0..837a14b808ff 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -2528,7 +2528,17 @@ fn normalize_lexically() { } #[test] -/// See issue#146183 -fn compare_path_to_str() { - assert!(&PathBuf::from("x") == "x"); +/// See issue#146183 and issue#146940 +fn compare_path_like_to_str_like() { + let path_buf = PathBuf::from("x"); + let path = Path::new("x"); + let s = String::from("x"); + assert!(path == "x"); + assert!("x" == path); + assert!(path == &s); + assert!(&s == path); + assert!(&path_buf == "x"); + assert!("x" == &path_buf); + assert!(path_buf == s); + assert!(s == path_buf); } From 6dafcaf6c85e235b259f1d2f1da3268bda74ab65 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Wed, 24 Sep 2025 09:33:43 -0400 Subject: [PATCH 220/537] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 966f94733bbc..f2932725b045 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 966f94733bbc94ca51ff9f1e4c49ad250ebbdc50 +Subproject commit f2932725b045d361ff5f18ba02b1409dd1f44e71 From f509dff56d82de64c37080731cbada0ac4dde2b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Sep 2025 21:55:05 +0200 Subject: [PATCH 221/537] f16_f128: enable some more tests in Miri --- library/coretests/tests/floats/mod.rs | 32 +++++++++++++-------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index d2b572230944..d8a831af78d3 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1180,15 +1180,12 @@ float_test! { } } -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - float_test! { name: sqrt_domain, attrs: { const: #[cfg(false)], - f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { assert!(Float::NAN.sqrt().is_nan()); @@ -1246,8 +1243,8 @@ float_test! { float_test! { name: total_cmp, attrs: { - f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { use core::cmp::Ordering; @@ -1355,8 +1352,8 @@ float_test! { name: total_cmp_s_nan, attrs: { const: #[cfg(false)], - f16: #[cfg(false)], - f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + f16: #[cfg(miri)], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { use core::cmp::Ordering; @@ -1432,6 +1429,7 @@ float_test! { name: powi, attrs: { const: #[cfg(false)], + // FIXME(f16_f128): `powi` does not work in Miri for these types f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, @@ -1452,8 +1450,8 @@ float_test! { float_test! { name: to_degrees, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let pi: Float = Float::PI; @@ -1473,8 +1471,8 @@ float_test! { float_test! { name: to_radians, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let pi: Float = Float::PI; @@ -1494,8 +1492,8 @@ float_test! { float_test! { name: to_algebraic, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { let a: Float = 123.0; @@ -1518,8 +1516,8 @@ float_test! { float_test! { name: to_bits_conv, attrs: { - f16: #[cfg(target_has_reliable_f16)], - f128: #[cfg(target_has_reliable_f128)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], }, test { assert_biteq!(flt(1.0), Float::RAW_1); From 431ef038a3b20e680687a98c4ad2507ae27a7b0a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 24 Sep 2025 15:18:31 +0000 Subject: [PATCH 222/537] impl Ord for params and use unstable sort --- compiler/rustc_hir_analysis/src/constrained_generic_params.rs | 2 +- .../rustc_hir_analysis/src/impl_wf_check/min_specialization.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 366b3943a058..2a633810cd70 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeV use rustc_span::Span; use tracing::debug; -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct Parameter(pub u32); impl From for Parameter { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b38639ed8c62..13c744ab4613 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -275,7 +275,7 @@ fn check_duplicate_params<'tcx>( span: Span, ) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(tcx, parent_args, true); - base_params.sort_by_key(|param| param.0); + base_params.sort_unstable(); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; return Err(tcx From 4e62715541925e1a62aebb3b8a0f633a674b808d Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 19 Sep 2025 07:07:49 +0000 Subject: [PATCH 223/537] Improve the pretty print of UnstableFeature clause --- compiler/rustc_middle/src/ty/print/pretty.rs | 3 +-- .../const-generics/adt_const_params/unsized_field-1.stderr | 6 +++--- .../unstable_impl_coherence.disabled.stderr | 2 +- .../unstable_impl_coherence.enabled.stderr | 2 +- .../unstable_impl_method_selection.stderr | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1b7ef8de8454..8f7c8170f7ad 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3177,8 +3177,7 @@ define_print! { write!(p, "` can be evaluated")?; } ty::ClauseKind::UnstableFeature(symbol) => { - write!(p, "unstable feature: ")?; - write!(p, "`{symbol}`")?; + write!(p, "feature({symbol}) is enabled")?; } } } diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr index a5ae5c726da8..134dbba0d63a 100644 --- a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr @@ -7,7 +7,7 @@ LL | LL | struct A([u8]); | ---- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy_` impl for `[u8]` requires that `unstable feature: `unsized_const_params`` +note: the `ConstParamTy_` impl for `[u8]` requires that `feature(unsized_const_params) is enabled` --> $DIR/unsized_field-1.rs:10:10 | LL | struct A([u8]); @@ -22,7 +22,7 @@ LL | LL | struct B(&'static [u8]); | ------------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy_` impl for `&'static [u8]` requires that `unstable feature: `unsized_const_params`` +note: the `ConstParamTy_` impl for `&'static [u8]` requires that `feature(unsized_const_params) is enabled` --> $DIR/unsized_field-1.rs:14:10 | LL | struct B(&'static [u8]); @@ -37,7 +37,7 @@ LL | LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); | ---------------------------------------------------------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `unstable feature: `unsized_const_params`` +note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `feature(unsized_const_params) is enabled` --> $DIR/unsized_field-1.rs:21:10 | LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr index c3147558b03f..afef024e1b9c 100644 --- a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr @@ -6,7 +6,7 @@ LL | impl aux::Trait for LocalTy {} | = note: conflicting implementation in crate `unstable_impl_coherence_aux`: - impl Trait for T - where unstable feature: `foo`; + where feature(foo) is enabled; error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr index c3147558b03f..afef024e1b9c 100644 --- a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr @@ -6,7 +6,7 @@ LL | impl aux::Trait for LocalTy {} | = note: conflicting implementation in crate `unstable_impl_coherence_aux`: - impl Trait for T - where unstable feature: `foo`; + where feature(foo) is enabled; error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr index c2bb10f043b2..840af730154d 100644 --- a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr +++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr @@ -7,7 +7,7 @@ LL | vec![].foo(); = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate: - impl Trait for Vec; - impl Trait for Vec - where unstable feature: `bar`; + where feature(bar) is enabled; error: aborting due to 1 previous error From b2634e31c435aeff149c5660f9329a0578ad1e72 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:10:15 -0500 Subject: [PATCH 224/537] std: add support for armv7a-vex-v5 target Co-authored-by: Lewis McClelland --- .../src/spec/targets/armv7a_vex_v5.rs | 2 +- library/Cargo.lock | 10 + library/std/Cargo.toml | 7 +- library/std/build.rs | 1 + library/std/src/env.rs | 2 + library/std/src/sys/alloc/mod.rs | 3 + library/std/src/sys/alloc/vexos.rs | 96 +++ library/std/src/sys/env_consts.rs | 11 + library/std/src/sys/fs/mod.rs | 4 + library/std/src/sys/fs/vexos.rs | 615 ++++++++++++++++++ library/std/src/sys/pal/mod.rs | 4 + library/std/src/sys/pal/vexos/mod.rs | 80 +++ library/std/src/sys/pal/vexos/time.rs | 28 + library/std/src/sys/random/mod.rs | 2 + library/std/src/sys/stdio/mod.rs | 4 + library/std/src/sys/stdio/vexos.rs | 100 +++ library/std/src/sys/thread/mod.rs | 7 + library/std/src/sys/thread/vexos.rs | 17 + library/std/src/sys/thread_local/mod.rs | 2 + .../src/platform-support/armv7a-vex-v5.md | 26 +- src/tools/tidy/src/deps.rs | 1 + 21 files changed, 1012 insertions(+), 10 deletions(-) create mode 100644 library/std/src/sys/alloc/vexos.rs create mode 100644 library/std/src/sys/fs/vexos.rs create mode 100644 library/std/src/sys/pal/vexos/mod.rs create mode 100644 library/std/src/sys/pal/vexos/time.rs create mode 100644 library/std/src/sys/stdio/vexos.rs create mode 100644 library/std/src/sys/thread/vexos.rs diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index e78f78399747..06dd26297758 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -34,7 +34,7 @@ pub(crate) fn target() -> Target { description: Some("ARMv7-A Cortex-A9 VEX V5 Brain".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/library/Cargo.lock b/library/Cargo.lock index e4b3839847b1..47fbf5169f49 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -326,6 +326,7 @@ dependencies = [ "rustc-demangle", "std_detect", "unwind", + "vex-sdk", "wasi 0.11.1+wasi-snapshot-preview1", "wasi 0.14.4+wasi-0.2.4", "windows-targets 0.0.0", @@ -379,6 +380,15 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "vex-sdk" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f74fce61d7a7ba1589da9634c6305a72befb7cc9150c1f872d87d8060f32b9" +dependencies = [ + "rustc-std-workspace-core", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d28a7f0b4602..b4d349d66def 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -62,7 +62,7 @@ path = "../windows_targets" rand = { version = "0.9.0", default-features = false, features = ["alloc"] } rand_xorshift = "0.4.0" -[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] @@ -89,6 +89,11 @@ wasip2 = { version = '0.14.4', features = [ r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } +[target.'cfg(target_os = "vexos")'.dependencies] +vex-sdk = { version = "0.27.0", features = [ + 'rustc-dep-of-std', +], default-features = false } + [features] backtrace = [ 'addr2line/rustc-dep-of-std', diff --git a/library/std/build.rs b/library/std/build.rs index ef695601a448..8a5a785060c8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -52,6 +52,7 @@ fn main() { || target_os == "rtems" || target_os == "nuttx" || target_os == "cygwin" + || target_os == "vexos" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e457cd61c759..6d716bd85443 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -1098,6 +1098,7 @@ pub mod consts { /// * `"redox"` /// * `"solaris"` /// * `"solid_asp3` + /// * `"vexos"` /// * `"vita"` /// * `"vxworks"` /// * `"xous"` @@ -1148,6 +1149,7 @@ pub mod consts { /// ///
Full list of possible values /// + /// * `"bin"` /// * `"exe"` /// * `"efi"` /// * `"js"` diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 6d4b09494a3f..2045b2fecc6a 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -92,6 +92,9 @@ cfg_select! { target_os = "uefi" => { mod uefi; } + target_os = "vexos" => { + mod vexos; + } target_family = "wasm" => { mod wasm; } diff --git a/library/std/src/sys/alloc/vexos.rs b/library/std/src/sys/alloc/vexos.rs new file mode 100644 index 000000000000..c1fb6896a89a --- /dev/null +++ b/library/std/src/sys/alloc/vexos.rs @@ -0,0 +1,96 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sync::atomic::{AtomicBool, Ordering}; + +// Symbols for heap section boundaries defined in the target's linkerscript +unsafe extern "C" { + static mut __heap_start: u8; + static mut __heap_end: u8; +} + +static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new_with_allocator(Vexos); + +struct Vexos; + +unsafe impl dlmalloc::Allocator for Vexos { + /// Allocs system resources + fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { + static INIT: AtomicBool = AtomicBool::new(false); + + if !INIT.swap(true, Ordering::Relaxed) { + // This target has no growable heap, as user memory has a fixed + // size/location and VEXos does not manage allocation for us. + unsafe { + ( + (&raw mut __heap_start).cast::(), + (&raw const __heap_end).offset_from_unsigned(&raw const __heap_start), + 0, + ) + } + } else { + (ptr::null_mut(), 0, 0) + } + } + + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + return false; + } + + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 0x1000 + } +} + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling malloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.malloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling calloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.calloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling free() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling realloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } + } +} diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs index 711ba0a5f8a9..573f540483b1 100644 --- a/library/std/src/sys/env_consts.rs +++ b/library/std/src/sys/env_consts.rs @@ -323,6 +323,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "efi"; } +#[cfg(target_os = "vexos")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "vexos"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ".bin"; + pub const EXE_EXTENSION: &str = "bin"; +} + #[cfg(target_os = "visionos")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 0276bf6e64c8..64f5a6b36d3d 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -35,6 +35,10 @@ cfg_select! { mod uefi; use uefi as imp; } + target_os = "vexos" => { + mod vexos; + use vexos as imp; + } target_os = "wasi" => { mod wasi; use wasi as imp; diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs new file mode 100644 index 000000000000..f642e7cb074e --- /dev/null +++ b/library/std/src/sys/fs/vexos.rs @@ -0,0 +1,615 @@ +use crate::ffi::{OsString, c_char}; +use crate::fmt; +use crate::fs::TryLockError; +use crate::hash::Hash; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::time::SystemTime; +use crate::sys::{unsupported, unsupported_err}; + +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_fs; +pub use unsupported_fs::{ + DirBuilder, FileTimes, canonicalize, link, readlink, remove_dir_all, rename, rmdir, symlink, + unlink, +}; + +/// VEXos file descriptor. +/// +/// This stores an opaque pointer to a [FatFs file object structure] managed by VEXos +/// representing an open file on disk. +/// +/// [FatFs file object structure]: https://github.com/Xilinx/embeddedsw/blob/master/lib/sw_services/xilffs/src/include/ff.h?rgh-link-date=2025-09-23T20%3A03%3A43Z#L215 +/// +/// # Safety +/// +/// Since this platform uses a pointer to to an internal filesystem structure with a lifetime +/// associated with it (rather than a UNIX-style file descriptor table), care must be taken to +/// ensure that the pointer held by `FileDesc` is valid for as long as it exists. +#[derive(Debug)] +struct FileDesc(*mut vex_sdk::FIL); + +// SAFETY: VEXos's FDs can be used on a thread other than the one they were created on. +unsafe impl Send for FileDesc {} +// SAFETY: We assume an environment without threads (i.e. no RTOS). +// (If there were threads, it is possible that a mutex would be required.) +unsafe impl Sync for FileDesc {} + +pub struct File { + fd: FileDesc, +} + +#[derive(Clone)] +pub enum FileAttr { + Dir, + File { size: u64 }, +} + +pub struct ReadDir(!); + +pub struct DirEntry { + path: PathBuf, +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions {} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct FileType { + is_dir: bool, +} + +impl FileAttr { + pub fn size(&self) -> u64 { + match self { + Self::File { size } => *size, + Self::Dir => 0, + } + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions {} + } + + pub fn file_type(&self) -> FileType { + FileType { is_dir: matches!(self, FileAttr::Dir) } + } + + pub fn modified(&self) -> io::Result { + unsupported() + } + + pub fn accessed(&self) -> io::Result { + unsupported() + } + + pub fn created(&self) -> io::Result { + unsupported() + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + false + } + + pub fn set_readonly(&mut self, _readonly: bool) { + panic!("Perimissions do not exist") + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is_dir + } + + pub fn is_file(&self) -> bool { + !self.is_dir + } + + pub fn is_symlink(&self) -> bool { + // No symlinks in VEXos - entries are either files or directories. + false + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.0 + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.path.clone() + } + + pub fn file_name(&self) -> OsString { + self.path.file_name().unwrap_or_default().into() + } + + pub fn metadata(&self) -> io::Result { + stat(&self.path) + } + + pub fn file_type(&self) -> io::Result { + Ok(self.metadata()?.file_type()) + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + pub fn create(&mut self, create: bool) { + self.create = create; + } + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + run_path_with_cstr(path, &|path| { + // Enforce the invariants of `create_new`/`create`. + // + // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce + // the requirements that `create_new` can't have an existing file and `!create` + // doesn't create a file ourselves. + if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) { + let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; + + if opts.create_new && status != 0 { + return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",)); + } else if !opts.create && status == 0 { + return Err(io::const_error!( + io::ErrorKind::NotFound, + "no such file or directory", + )); + } + } + + let file = match opts { + // read + write - unsupported + OpenOptions { read: true, write: true, .. } => { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "opening files with read and write access is unsupported on this target", + )); + } + + // read + OpenOptions { + read: true, + write: false, + append: _, + truncate: false, + create: false, + create_new: false, + } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) }, + + // append + OpenOptions { + read: false, + write: _, + append: true, + truncate: false, + create: _, + create_new: _, + } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) }, + + // write + OpenOptions { + read: false, + write: true, + append: false, + truncate, + create: _, + create_new: _, + } => unsafe { + if *truncate { + vex_sdk::vexFileOpenCreate(path.as_ptr()) + } else { + // Open in append, but jump to the start of the file. + let fd = vex_sdk::vexFileOpenWrite(path.as_ptr()); + vex_sdk::vexFileSeek(fd, 0, 0); + fd + } + }, + + _ => { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument")); + } + }; + + if file.is_null() { + Err(io::const_error!(io::ErrorKind::NotFound, "could not open file")) + } else { + Ok(Self { fd: FileDesc(file) }) + } + }) + } + + pub fn file_attr(&self) -> io::Result { + // `vexFileSize` returns -1 upon error, so u64::try_from will fail on error. + if let Ok(size) = u64::try_from(unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileSize(self.fd.0) + }) { + Ok(FileAttr::File { size }) + } else { + Err(io::const_error!(io::ErrorKind::InvalidData, "failed to get file size")) + } + } + + pub fn fsync(&self) -> io::Result<()> { + self.flush() + } + + pub fn datasync(&self) -> io::Result<()> { + self.flush() + } + + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) + } + + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + unsupported() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let len = buf.len() as u32; + let buf_ptr = buf.as_mut_ptr(); + let read = unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileRead(buf_ptr.cast::(), 1, len, self.fd.0) + }; + + if read < 0 { + Err(io::const_error!(io::ErrorKind::Other, "could not read from file")) + } else { + Ok(read as usize) + } + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|b| self.read(b), cursor) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let len = buf.len() as u32; + let buf_ptr = buf.as_ptr(); + let written = unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast::(), 1, len, self.fd.0) + }; + + if written < 0 { + Err(io::const_error!(io::ErrorKind::Other, "could not write to file")) + } else { + Ok(written as usize) + } + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileSync(self.fd.0); + } + Ok(()) + } + + pub fn tell(&self) -> io::Result { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + let position = unsafe { vex_sdk::vexFileTell(self.fd.0) }; + + position.try_into().map_err(|_| { + io::const_error!(io::ErrorKind::InvalidData, "failed to get current location in file") + }) + } + + pub fn size(&self) -> Option> { + None + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + const SEEK_SET: i32 = 0; + const SEEK_CUR: i32 = 1; + const SEEK_END: i32 = 2; + + fn try_convert_offset>(offset: T) -> io::Result { + offset.try_into().map_err(|_| { + io::const_error!( + io::ErrorKind::InvalidInput, + "cannot seek to an offset too large to fit in a 32 bit integer", + ) + }) + } + + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + match pos { + SeekFrom::Start(offset) => unsafe { + map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))? + }, + SeekFrom::End(offset) => unsafe { + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_END, + ))? + } else { + // `vexFileSeek` does not support seeking with negative offset, meaning + // we have to calculate the offset from the end of the file ourselves. + + // Seek to the end of the file to get the end position in the open buffer. + map_fresult(vex_sdk::vexFileSeek(self.fd.0, 0, SEEK_END))?; + let end_position = self.tell()?; + + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + // NOTE: Files internally use a 32-bit representation for stream + // position, so `end_position as i64` should never overflow. + try_convert_offset(end_position as i64 + offset)?, + SEEK_SET, + ))? + } + }, + SeekFrom::Current(offset) => unsafe { + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_CUR, + ))? + } else { + // `vexFileSeek` does not support seeking with negative offset, meaning + // we have to calculate the offset from the stream position ourselves. + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset((self.tell()? as i64) + offset)?, + SEEK_SET, + ))? + } + }, + } + + Ok(self.tell()?) + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + unsupported() + } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").field("fd", &self.fd.0).finish() + } +} +impl Drop for File { + fn drop(&mut self) { + unsafe { vex_sdk::vexFileClose(self.fd.0) }; + } +} + +pub fn readdir(_p: &Path) -> io::Result { + // While there *is* a userspace function for reading file directories, + // the necessary implementation cannot currently be done cleanly, as + // VEXos does not expose directory length to user programs. + // + // This means that we would need to create a large fixed-length buffer + // and hope that the folder's contents didn't exceed that buffer's length, + // which obviously isn't behavior we want to rely on in the standard library. + unsupported() +} + +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + unsupported() +} + +pub fn exists(path: &Path) -> io::Result { + run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0)) +} + +pub fn stat(p: &Path) -> io::Result { + // `vexFileStatus` returns 3 if the given path is a directory, 1 if the path is a + // file, or 0 if no such path exists. + const FILE_STATUS_DIR: u32 = 3; + + run_path_with_cstr(p, &|c_path| { + let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) }; + + // We can't get the size if its a directory because we cant open it as a file + if file_type == FILE_STATUS_DIR { + Ok(FileAttr::Dir) + } else { + let mut opts = OpenOptions::new(); + opts.read(true); + let file = File::open(p, &opts)?; + file.file_attr() + } + }) +} + +pub fn lstat(p: &Path) -> io::Result { + // Symlinks aren't supported in this filesystem + stat(p) +} + +// Cannot use `copy` from `common` here, since `File::set_permissions` is unsupported on this target. +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + // NOTE: If `from` is a directory, this call should fail due to vexFileOpen* returning null. + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} + +fn map_fresult(fresult: vex_sdk::FRESULT) -> io::Result<()> { + // VEX uses a derivative of FatFs (Xilinx's xilffs library) for filesystem operations. + match fresult { + vex_sdk::FRESULT::FR_OK => Ok(()), + vex_sdk::FRESULT::FR_DISK_ERR => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "internal function reported an unrecoverable hard error", + )), + vex_sdk::FRESULT::FR_INT_ERR => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "internal error in filesystem runtime", + )), + vex_sdk::FRESULT::FR_NOT_READY => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "the storage device could not be prepared to work", + )), + vex_sdk::FRESULT::FR_NO_FILE => Err(io::const_error!( + io::ErrorKind::NotFound, + "could not find the file in the directory" + )), + vex_sdk::FRESULT::FR_NO_PATH => Err(io::const_error!( + io::ErrorKind::NotFound, + "a directory in the path name could not be found", + )), + vex_sdk::FRESULT::FR_INVALID_NAME => Err(io::const_error!( + io::ErrorKind::InvalidInput, + "the given string is invalid as a path name", + )), + vex_sdk::FRESULT::FR_DENIED => Err(io::const_error!( + io::ErrorKind::PermissionDenied, + "the required access for this operation was denied", + )), + vex_sdk::FRESULT::FR_EXIST => Err(io::const_error!( + io::ErrorKind::AlreadyExists, + "an object with the same name already exists in the directory", + )), + vex_sdk::FRESULT::FR_INVALID_OBJECT => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "invalid or null file/directory object", + )), + vex_sdk::FRESULT::FR_WRITE_PROTECTED => Err(io::const_error!( + io::ErrorKind::PermissionDenied, + "a write operation was performed on write-protected media", + )), + vex_sdk::FRESULT::FR_INVALID_DRIVE => Err(io::const_error!( + io::ErrorKind::InvalidInput, + "an invalid drive number was specified in the path name", + )), + vex_sdk::FRESULT::FR_NOT_ENABLED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "work area for the logical drive has not been registered", + )), + vex_sdk::FRESULT::FR_NO_FILESYSTEM => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "valid FAT volume could not be found on the drive", + )), + vex_sdk::FRESULT::FR_MKFS_ABORTED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "failed to create filesystem volume" + )), + vex_sdk::FRESULT::FR_TIMEOUT => Err(io::const_error!( + io::ErrorKind::TimedOut, + "the function was canceled due to a timeout of thread-safe control", + )), + vex_sdk::FRESULT::FR_LOCKED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "the operation to the object was rejected by file sharing control", + )), + vex_sdk::FRESULT::FR_NOT_ENOUGH_CORE => { + Err(io::const_error!(io::ErrorKind::OutOfMemory, "not enough memory for the operation")) + } + vex_sdk::FRESULT::FR_TOO_MANY_OPEN_FILES => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "maximum number of open files has been reached", + )), + vex_sdk::FRESULT::FR_INVALID_PARAMETER => { + Err(io::const_error!(io::ErrorKind::InvalidInput, "a given parameter was invalid")) + } + _ => unreachable!(), // C-style enum + } +} diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 513121c6d30e..dd5e83ee570b 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -45,6 +45,10 @@ cfg_select! { mod trusty; pub use self::trusty::*; } + target_os = "vexos" => { + mod vexos; + pub use self::vexos::*; + } all(target_os = "wasi", target_env = "p2") => { mod wasip2; pub use self::wasip2::*; diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs new file mode 100644 index 000000000000..61a34b0f68a3 --- /dev/null +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -0,0 +1,80 @@ +#[path = "../unsupported/os.rs"] +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +pub mod time; + +#[expect(dead_code)] +#[path = "../unsupported/common.rs"] +mod unsupported_common; + +pub use unsupported_common::{ + decode_error_kind, init, is_interrupted, unsupported, unsupported_err, +}; + +use crate::arch::global_asm; +use crate::ptr; +use crate::sys::stdio; +use crate::time::{Duration, Instant}; + +global_asm!( + r#" + .section .boot, "ax" + .global _boot + + _boot: + ldr sp, =__stack_top @ Set up the user stack. + b _start @ Jump to the Rust entrypoint. + "# +); + +#[cfg(not(test))] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn _start() -> ! { + unsafe extern "C" { + static mut __bss_start: u8; + static mut __bss_end: u8; + + fn main() -> i32; + } + + // Clear the .bss (uninitialized statics) section by filling it with zeroes. + // This is required, since the compiler assumes it will be zeroed on first access. + ptr::write_bytes( + &raw mut __bss_start, + 0, + (&raw mut __bss_end).offset_from_unsigned(&raw mut __bss_start), + ); + + main(); + + cleanup(); + abort_internal() +} + +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() { + let exit_time = Instant::now(); + const FLUSH_TIMEOUT: Duration = Duration::from_millis(15); + + // Force the serial buffer to flush + while exit_time.elapsed() < FLUSH_TIMEOUT { + vex_sdk::vexTasksRun(); + + // If the buffer has been fully flushed, exit the loop + if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) { + break; + } + } +} + +pub fn abort_internal() -> ! { + unsafe { + vex_sdk::vexSystemExitRequest(); + + loop { + vex_sdk::vexTasksRun(); + } + } +} diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs new file mode 100644 index 000000000000..f95d96cd27ac --- /dev/null +++ b/library/std/src/sys/pal/vexos/time.rs @@ -0,0 +1,28 @@ +use crate::time::Duration; + +#[expect(dead_code)] +#[path = "../unsupported/time.rs"] +mod unsupported_time; +pub use unsupported_time::{SystemTime, UNIX_EPOCH}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +impl Instant { + pub fn now() -> Instant { + let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() }; + Self(Duration::from_micros(micros)) + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) + } +} diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 1e0eec07b500..3c5a4c82a9f1 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -101,6 +101,7 @@ cfg_select! { any( all(target_family = "wasm", target_os = "unknown"), target_os = "xous", + target_os = "vexos", ) => { // FIXME: finally remove std support for wasm32-unknown-unknown // FIXME: add random data generation to xous @@ -116,6 +117,7 @@ cfg_select! { all(target_family = "wasm", target_os = "unknown"), all(target_os = "wasi", target_env = "p2"), target_os = "xous", + target_os = "vexos", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 7436e4d9de4d..404ac8779269 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -29,6 +29,10 @@ cfg_select! { mod uefi; pub use uefi::*; } + target_os = "vexos" => { + mod vexos; + pub use vexos::*; + } all(target_os = "wasi", target_env = "p1") => { mod wasip1; pub use wasip1::*; diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs new file mode 100644 index 000000000000..1f2251c6421d --- /dev/null +++ b/library/std/src/sys/stdio/vexos.rs @@ -0,0 +1,100 @@ +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub type Stderr = Stdout; + +pub const STDIO_CHANNEL: u32 = 1; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + let mut count = 0; + + for out_byte in buf.iter_mut() { + let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) }; + if byte < 0 { + break; + } + + *out_byte = byte as u8; + count += 1; + } + + Ok(count) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + let mut written = 0; + + // HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1 + // roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we + // must block until that buffer is flushed to USB1 before writing the rest of `buf`. + // + // This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed + // recursive panic when using macros such as `print!` to write large amounts of data + // (buf.len() > 2048) to stdout at once. + for chunk in buf.chunks(STDOUT_BUF_SIZE) { + if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() { + self.flush().unwrap(); + } + + let count: usize = unsafe { + vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32) + } + .try_into() + .map_err(|_| { + io::const_error!(io::ErrorKind::Uncategorized, "internal write error occurred") + })?; + + written += count; + + // This is a sanity check to ensure that we don't end up with non-contiguous + // buffer writes. e.g. a chunk gets only partially written, but we continue + // attempting to write the remaining chunks. + // + // In practice, this should never really occur since the previous flush ensures + // enough space in FIFO to write the entire chunk to vexSerialWriteBuffer. + if count != chunk.len() { + break; + } + } + + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + // This may block for up to a millisecond. + unsafe { + while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE { + vex_sdk::vexTasksRun(); + } + } + + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 4096; +pub const STDOUT_BUF_SIZE: usize = 2048; + +pub fn is_ebadf(_err: &io::Error) -> bool { + false +} + +pub fn panic_output() -> Option { + Some(Stdout::new()) +} diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 6bb7fc1a20e2..3bd83dd760ac 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -81,6 +81,13 @@ cfg_select! { ))] pub use unsupported::set_name; } + target_os = "vexos" => { + mod vexos; + pub use vexos::{sleep, yield_now}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE}; + } all(target_os = "wasi", target_env = "p1") => { mod wasip1; pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now}; diff --git a/library/std/src/sys/thread/vexos.rs b/library/std/src/sys/thread/vexos.rs new file mode 100644 index 000000000000..d917dde4d0bc --- /dev/null +++ b/library/std/src/sys/thread/vexos.rs @@ -0,0 +1,17 @@ +use crate::time::{Duration, Instant}; + +pub fn yield_now() { + unsafe { + vex_sdk::vexTasksRun(); + } +} + +pub fn sleep(dur: Duration) { + let start = Instant::now(); + + while start.elapsed() < dur { + unsafe { + vex_sdk::vexTasksRun(); + } + } +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index cff74857c473..d5c795093cf0 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -29,6 +29,7 @@ cfg_select! { target_os = "uefi", target_os = "zkvm", target_os = "trusty", + target_os = "vexos", ) => { mod no_threads; pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner}; @@ -98,6 +99,7 @@ pub(crate) mod guard { target_os = "uefi", target_os = "zkvm", target_os = "trusty", + target_os = "vexos", ) => { pub(crate) fn enable() { // FIXME: Right now there is no concept of "thread exit" on diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index a7da1b16f7e3..3677f8931dd6 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -4,7 +4,7 @@ Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics. -Rust support for this target is not affiliated with VEX Robotics or IFI. +Rust support for this target is not affiliated with VEX Robotics or IFI, and does not link to any official VEX SDK. ## Target maintainers @@ -17,11 +17,24 @@ This target is maintained by members of the [vexide](https://github.com/vexide) ## Requirements -This target is cross-compiled and currently requires `#![no_std]`. Dynamic linking is unsupported. +This target is cross-compiled. Dynamic linking is unsupported. -When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (soft float ABI). +`#![no_std]` crates can be built using `build-std` to build `core` and `panic_abort` and optionally `alloc`. Unwinding panics are not yet supported on this target. -This target generates binaries in the ELF format that may uploaded to the brain with external tools. +`std` has only partial support due platform limitations. Notably: +- `std::process` and `std::net` are unimplemented. `std::thread` only supports sleeping and yielding, as this is a single-threaded environment. +- `std::time` has full support for `Instant`, but no support for `SystemTime`. +- `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to to USB channel 1 on this platform and are not differentiated. +- `std::fs` has limited support for reading or writing to files. Directory operations, file deletion, and some file opening features are unsupported and will return errors. +- A global allocator implemented on top of `dlmalloc` is provided. +- Modules that do not need to interact with the OS beyond allocation such as `std::collections`, `std::hash`, `std::future`, `std::sync`, etc are fully supported. +- Random number generation and hashing is insecure, as there is no reliable source of entropy on this platform. + +In order to support some APIs, users are expected to provide a supporting runtime SDK for `libstd` to link against. This library may be provided either by [`vex-sdk-build`](https://github.com/vexide/vex-sdk/tree/main/packages/vex-sdk-build) (which will download an official SDK from VEX) or through an open-source implementation such as [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable). + +When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (softfp ABI). + +This target generates binaries in the ELF format that may be uploaded to the brain with external tools. ## Building the target @@ -29,10 +42,7 @@ You can build Rust with support for this target by adding it to the `target` lis ## Building Rust programs -Rust does not yet ship pre-compiled artifacts for this target. To compile for -this target, you will either need to build Rust with the target enabled (see -"Building the target" above), or build your own copy of `core` by using -`build-std` or similar. +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using `build-std` or similar. When the compiler builds a binary, an ELF build artifact will be produced. Additional tools are required for this artifact to be recognizable to VEXos as a user program. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 568ec0c11989..7c5f823b57c7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -575,6 +575,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-literal-escaper", "shlex", "unwinding", + "vex-sdk", "wasi", "windows-sys", "windows-targets", From a3840d9592e764f48617bf178c4c00bdb0b8ab84 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 22 Sep 2025 08:59:36 +0300 Subject: [PATCH 225/537] Implement fallback properly fallback.rs was ported straight from rustc (minus the lint parts). This fixes the `!` regressions. --- src/tools/rust-analyzer/Cargo.lock | 18 + src/tools/rust-analyzer/Cargo.toml | 1 + .../rust-analyzer/crates/hir-ty/Cargo.toml | 1 + .../crates/hir-ty/src/consteval.rs | 2 +- .../crates/hir-ty/src/consteval/tests.rs | 48 +- .../crates/hir-ty/src/consteval_nextsolver.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 95 +++- .../crates/hir-ty/src/infer/coerce.rs | 28 +- .../crates/hir-ty/src/infer/fallback.rs | 439 ++++++++++++++++++ .../crates/hir-ty/src/infer/unify.rs | 330 ++++++------- .../crates/hir-ty/src/next_solver.rs | 2 +- .../crates/hir-ty/src/next_solver/region.rs | 10 +- .../crates/hir-ty/src/next_solver/ty.rs | 9 + .../crates/hir-ty/src/tests/never_type.rs | 10 +- .../crates/hir-ty/src/tests/regression.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 1 + 16 files changed, 769 insertions(+), 229 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 17dea1ba4cde..9d0f63d2bcec 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -545,6 +545,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.2" @@ -775,6 +781,7 @@ dependencies = [ "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "oorandom", + "petgraph", "project-model", "query-group-macro", "ra-ap-rustc_abi", @@ -1594,6 +1601,17 @@ dependencies = [ "libc", ] +[[package]] +name = "petgraph" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.4", + "indexmap", +] + [[package]] name = "pin-project-lite" version = "0.2.16" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 0401367f7864..d3a4e375613e 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -170,6 +170,7 @@ tracing-subscriber = { version = "0.3.20", default-features = false, features = triomphe = { version = "0.1.14", default-features = false, features = ["std"] } url = "2.5.4" xshell = "0.2.7" +petgraph = { version = "0.8.2", default-features = false } # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 138d02e5a610..4013d19ad08e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -34,6 +34,7 @@ rustc_apfloat = "0.2.3" query-group.workspace = true salsa.workspace = true salsa-macros.workspace = true +petgraph.workspace = true ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index e2a8d1cedc28..b2daed425ef1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -327,7 +327,7 @@ pub(crate) fn eval_to_const( debruijn: DebruijnIndex, ) -> Const { let db = ctx.db; - let infer = ctx.clone().resolve_all(); + let infer = ctx.fixme_resolve_all_clone(); fn has_closure(body: &Body, expr: ExprId) -> bool { if matches!(body[expr], Expr::Closure { .. }) { return true; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 299b73a7d6cc..1586846bbe58 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -36,12 +36,12 @@ fn check_fail( error: impl FnOnce(ConstEvalError) -> bool, ) { let (db, file_id) = TestDB::with_single_file(ra_fixture); - match eval_goal(&db, file_id) { + salsa::attach(&db, || match eval_goal(&db, file_id) { Ok(_) => panic!("Expected fail, but it succeeded"), Err(e) => { - assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db)) + assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, &db)) } - } + }) } #[track_caller] @@ -79,36 +79,38 @@ fn check_answer( check: impl FnOnce(&[u8], &MemoryMap<'_>), ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); - let file_id = *file_ids.last().unwrap(); - let r = match eval_goal(&db, file_id) { - Ok(t) => t, - Err(e) => { - let err = pretty_print_err(e, db); - panic!("Error in evaluating goal: {err}"); - } - }; - match &r.data(Interner).value { - chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(b, mm) => { - check(b, mm); + salsa::attach(&db, || { + let file_id = *file_ids.last().unwrap(); + let r = match eval_goal(&db, file_id) { + Ok(t) => t, + Err(e) => { + let err = pretty_print_err(e, &db); + panic!("Error in evaluating goal: {err}"); } - x => panic!("Expected number but found {x:?}"), - }, - _ => panic!("result of const eval wasn't a concrete const"), - } + }; + match &r.data(Interner).value { + chalk_ir::ConstValue::Concrete(c) => match &c.interned { + ConstScalar::Bytes(b, mm) => { + check(b, mm); + } + x => panic!("Expected number but found {x:?}"), + }, + _ => panic!("result of const eval wasn't a concrete const"), + } + }); } -fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { +fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); let display_target = - DisplayTarget::from_crate(&db, *db.all_crates().last().expect("no crate graph present")); + DisplayTarget::from_crate(db, *db.all_crates().last().expect("no crate graph present")); match e { ConstEvalError::MirLowerError(e) => { - e.pretty_print(&mut err, &db, span_formatter, display_target) + e.pretty_print(&mut err, db, span_formatter, display_target) } ConstEvalError::MirEvalError(e) => { - e.pretty_print(&mut err, &db, span_formatter, display_target) + e.pretty_print(&mut err, db, span_formatter, display_target) } } .unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs index 6e07d3afe552..155f1336e41d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs @@ -222,7 +222,7 @@ pub(crate) fn const_eval_discriminant_variant( // and make this function private. See the fixme comment on `InferenceContext::resolve_all`. pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) -> Const<'db> { let interner = DbInterner::new_with(ctx.db, None, None); - let infer = ctx.clone().resolve_all(); + let infer = ctx.fixme_resolve_all_clone(); fn has_closure(body: &Body, expr: ExprId) -> bool { if matches!(body[expr], Expr::Closure { .. }) { return true; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index fd10f923987f..287afb039b45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -19,6 +19,7 @@ pub(crate) mod closure; mod coerce; pub(crate) mod diagnostics; mod expr; +mod fallback; mod mutability; mod pat; mod path; @@ -53,16 +54,16 @@ use indexmap::IndexSet; use intern::sym; use la_arena::{ArenaMap, Entry}; use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_type_ir::inherent::Ty as _; use stdx::{always, never}; use triomphe::Arc; -use crate::db::InternedClosureId; use crate::{ AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, PathLoweringDiagnostic, ProjectionTy, Substitution, TargetFeatures, TraitEnvironment, Ty, TyBuilder, TyExt, - db::HirDatabase, + db::{HirDatabase, InternedClosureId}, fold_tys, generics::Generics, infer::{ @@ -75,6 +76,7 @@ use crate::{ mir::MirSpan, next_solver::{ self, DbInterner, + infer::{DefineOpaqueTypes, traits::ObligationCause}, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, static_lifetime, to_assoc_type_id, @@ -138,6 +140,20 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc for InferenceResult { } } +#[derive(Debug, Clone)] +struct InternedStandardTypesNextSolver<'db> { + unit: crate::next_solver::Ty<'db>, + never: crate::next_solver::Ty<'db>, + i32: crate::next_solver::Ty<'db>, + f64: crate::next_solver::Ty<'db>, +} + +impl<'db> InternedStandardTypesNextSolver<'db> { + fn new(interner: DbInterner<'db>) -> Self { + Self { + unit: crate::next_solver::Ty::new_unit(interner), + never: crate::next_solver::Ty::new(interner, crate::next_solver::TyKind::Never), + i32: crate::next_solver::Ty::new_int(interner, rustc_type_ir::IntTy::I32), + f64: crate::next_solver::Ty::new_float(interner, rustc_type_ir::FloatTy::F64), + } + } +} + /// The inference context contains all information needed during type inference. #[derive(Clone, Debug)] pub(crate) struct InferenceContext<'db> { @@ -718,6 +752,7 @@ pub(crate) struct InferenceContext<'db> { resume_yield_tys: Option<(Ty, Ty)>, diverges: Diverges, breakables: Vec>, + types: InternedStandardTypesNextSolver<'db>, /// Whether we are inside the pattern of a destructuring assignment. inside_assignment: bool, @@ -798,11 +833,13 @@ impl<'db> InferenceContext<'db> { resolver: Resolver<'db>, ) -> Self { let trait_env = db.trait_environment_for_body(owner); + let table = unify::InferenceTable::new(db, trait_env); InferenceContext { + types: InternedStandardTypesNextSolver::new(table.interner), target_features: OnceCell::new(), generics: OnceCell::new(), result: InferenceResult::default(), - table: unify::InferenceTable::new(db, trait_env), + table, tuple_field_accesses_rev: Default::default(), return_ty: TyKind::Error.intern(Interner), // set in collect_* calls resume_yield_tys: None, @@ -865,24 +902,33 @@ impl<'db> InferenceContext<'db> { self.result.has_errors = true; } - // FIXME: This function should be private in module. It is currently only used in the consteval, since we need - // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you - // used this function for another workaround, mention it here. If you really need this function and believe that - // there is no problem in it being `pub(crate)`, remove this comment. - pub(crate) fn resolve_all(mut self) -> InferenceResult { - self.table.select_obligations_where_possible(); - self.table.fallback_if_possible(); + /// Clones `self` and calls `resolve_all()` on it. + // FIXME: Remove this. + pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult { + let mut ctx = self.clone(); + + ctx.type_inference_fallback(); // Comment from rustc: // Even though coercion casts provide type hints, we check casts after fallback for // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - let cast_checks = std::mem::take(&mut self.deferred_cast_checks); + let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks); for mut cast in cast_checks.into_iter() { - if let Err(diag) = cast.check(&mut self) { - self.diagnostics.push(diag); + if let Err(diag) = cast.check(&mut ctx) { + ctx.diagnostics.push(diag); } } + ctx.table.select_obligations_where_possible(); + + ctx.resolve_all() + } + + // FIXME: This function should be private in module. It is currently only used in the consteval, since we need + // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you + // used this function for another workaround, mention it here. If you really need this function and believe that + // there is no problem in it being `pub(crate)`, remove this comment. + pub(crate) fn resolve_all(self) -> InferenceResult { let InferenceContext { mut table, mut result, tuple_field_accesses_rev, diagnostics, .. } = self; @@ -914,11 +960,6 @@ impl<'db> InferenceContext<'db> { diagnostics: _, } = &mut result; - // FIXME resolve obligations as well (use Guidance if necessary) - table.select_obligations_where_possible(); - - // make sure diverging type variables are marked as such - table.propagate_diverging_flag(); for ty in type_of_expr.values_mut() { *ty = table.resolve_completely(ty.clone()); *has_errors = *has_errors || ty.contains_unknown(); @@ -1673,6 +1714,22 @@ impl<'db> InferenceContext<'db> { self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) } + fn demand_eqtype( + &mut self, + expected: crate::next_solver::Ty<'db>, + actual: crate::next_solver::Ty<'db>, + ) { + let result = self + .table + .infer_ctxt + .at(&ObligationCause::new(), self.table.trait_env.env) + .eq(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); + if let Err(_err) = result { + // FIXME: Emit diagnostic. + } + } + fn resolve_associated_type_with_params( &mut self, inner_ty: Ty, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 219b519e46bb..62ce00a2e33d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -210,9 +210,8 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { // Coercing from `!` to any type is allowed: if a.is_never() { // If we're coercing into an inference var, mark it as possibly diverging. - // FIXME: rustc does this differently. - if let TyKind::Infer(rustc_type_ir::TyVar(b)) = b.kind() { - self.table.set_diverging(b.as_u32().into(), chalk_ir::TyVariableKind::General); + if b.is_infer() { + self.table.set_diverging(b); } if self.coerce_never { @@ -1613,16 +1612,21 @@ fn coerce<'db>( chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner), } == Some(iv)) }; - let fallback = |iv, kind, default, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) - .map_or(default, |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), - chalk_ir::VariableKind::Lifetime => find_var(iv).map_or(default, |i| { - crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner) - }), - chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or(default, |i| { - crate::BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner) - }), + let fallback = |iv, kind, binder| match kind { + chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else( + || chalk_ir::TyKind::Error.intern(Interner).cast(Interner), + |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner), + ), + chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else( + || crate::LifetimeData::Error.intern(Interner).cast(Interner), + |i| crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner), + ), + chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else( + || crate::unknown_const(ty.clone()).cast(Interner), + |i| crate::BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner), + ), }; // FIXME also map the types in the adjustments + // FIXME: We don't fallback correctly since this is done on `InferenceContext` and we only have `InferenceTable`. Ok((adjustments, table.resolve_with_fallback(ty.to_chalk(table.interner), &fallback))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs new file mode 100644 index 000000000000..2022447ad433 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs @@ -0,0 +1,439 @@ +//! Fallback of infer vars to `!` and `i32`/`f64`. + +use intern::sym; +use petgraph::{ + Graph, + visit::{Dfs, Walker}, +}; +use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; +use rustc_type_ir::{ + TyVid, + inherent::{IntoKind, Ty as _}, +}; +use tracing::debug; + +use crate::{ + infer::InferenceContext, + next_solver::{CoercePredicate, PredicateKind, SubtypePredicate, Ty, TyKind}, +}; + +#[derive(Copy, Clone)] +pub(crate) enum DivergingFallbackBehavior { + /// Always fallback to `()` (aka "always spontaneous decay") + ToUnit, + /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken. + ContextDependent, + /// Always fallback to `!` (which should be equivalent to never falling back + not making + /// never-to-any coercions unless necessary) + ToNever, +} + +impl<'db> InferenceContext<'db> { + pub(super) fn type_inference_fallback(&mut self) { + debug!( + "type-inference-fallback start obligations: {:#?}", + self.table.fulfillment_cx.pending_obligations() + ); + + // All type checking constraints were added, try to fallback unsolved variables. + self.table.select_obligations_where_possible(); + + debug!( + "type-inference-fallback post selection obligations: {:#?}", + self.table.fulfillment_cx.pending_obligations() + ); + + let fallback_occurred = self.fallback_types(); + + if !fallback_occurred { + return; + } + + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. + // + // In code like this: + // + // ```rust + // type MyType = impl Copy; + // fn produce() -> MyType { true } + // fn bad_produce() -> MyType { panic!() } + // ``` + // + // we want to unify the opaque inference variable in `bad_produce` + // with the diverging fallback for `panic!` (e.g. `()` or `!`). + // This will produce a nice error message about conflicting concrete + // types for `MyType`. + // + // If we had tried to fallback the opaque inference variable to `MyType`, + // we will generate a confusing type-check error that does not explicitly + // refer to opaque types. + self.table.select_obligations_where_possible(); + } + + fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior { + if self.krate().data(self.db).edition.at_least_2024() { + return DivergingFallbackBehavior::ToNever; + } + + if self.resolver.def_map().is_unstable_feature_enabled(&sym::never_type_fallback) { + return DivergingFallbackBehavior::ContextDependent; + } + + DivergingFallbackBehavior::ToUnit + } + + fn fallback_types(&mut self) -> bool { + // Check if we have any unresolved variables. If not, no need for fallback. + let unresolved_variables = self.table.infer_ctxt.unresolved_variables(); + + if unresolved_variables.is_empty() { + return false; + } + + let diverging_fallback_behavior = self.diverging_fallback_behavior(); + + let diverging_fallback = + self.calculate_diverging_fallback(&unresolved_variables, diverging_fallback_behavior); + + // We do fallback in two passes, to try to generate + // better error messages. + // The first time, we do *not* replace opaque types. + let mut fallback_occurred = false; + for ty in unresolved_variables { + debug!("unsolved_variable = {:?}", ty); + fallback_occurred |= self.fallback_if_possible(ty, &diverging_fallback); + } + + fallback_occurred + } + + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // + // - Unconstrained ints are replaced with `i32`. + // + // - Unconstrained floats are replaced with `f64`. + // + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback` + // (and the setting of `#![feature(never_type_fallback)]`). + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. + // + // Sets `FnCtxt::fallback_has_occurred` if fallback is performed + // during this call. + fn fallback_if_possible( + &mut self, + ty: Ty<'db>, + diverging_fallback: &FxHashMap, Ty<'db>>, + ) -> bool { + // Careful: we do NOT shallow-resolve `ty`. We know that `ty` + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. + // + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) + // + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) + let fallback = match ty.kind() { + TyKind::Infer(rustc_type_ir::IntVar(_)) => self.types.i32, + TyKind::Infer(rustc_type_ir::FloatVar(_)) => self.types.f64, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, + }, + }; + debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); + + self.demand_eqtype(ty, fallback); + true + } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// # fn foo() -> i32 { 4 } + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ```ignore (not-rust) + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unresolved_variables: &[Ty<'db>], + behavior: DivergingFallbackBehavior, + ) -> FxHashMap, Ty<'db>> { + debug!("calculate_diverging_fallback({:?})", unresolved_variables); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids = unresolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .table + .diverging_type_vars + .iter() + .map(|&ty| self.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.table.infer_ctxt.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.table.diverging_type_vars + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = Dfs::empty(&coercion_graph); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for unsolved_vid in unsolved_vids { + let root_vid = self.table.infer_ctxt.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", + unsolved_vid, + root_vid, + diverging_roots.contains(&root_vid), + ); + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.move_to(root_vid.as_u32().into()); + + // drain the iterator to visit all nodes reachable from this node + while roots_reachable_from_diverging.next(&coercion_graph).is_some() {} + } else { + non_diverging_vids.push(unsolved_vid); + } + } + + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = Dfs::empty(&coercion_graph); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.table.infer_ctxt.root_var(non_diverging_vid); + if roots_reachable_from_diverging.discovered.contains(root_vid.as_usize()) { + continue; + } + roots_reachable_from_non_diverging.move_to(root_vid.as_u32().into()); + while roots_reachable_from_non_diverging.next(&coercion_graph).is_some() {} + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + debug!("obligations: {:#?}", self.table.fulfillment_cx.pending_obligations()); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = + FxHashMap::with_capacity_and_hasher(diverging_vids.len(), FxBuildHasher); + + for &diverging_vid in &diverging_vids { + let diverging_ty = Ty::new_var(self.table.interner, diverging_vid); + let root_vid = self.table.infer_ctxt.root_var(diverging_vid); + let can_reach_non_diverging = Dfs::new(&coercion_graph, root_vid.as_u32().into()) + .iter(&coercion_graph) + .any(|n| roots_reachable_from_non_diverging.discovered.contains(n.index())); + + let mut fallback_to = |ty| { + diverging_fallback.insert(diverging_ty, ty); + }; + + match behavior { + DivergingFallbackBehavior::ToUnit => { + debug!("fallback to () - legacy: {:?}", diverging_vid); + fallback_to(self.types.unit); + } + DivergingFallbackBehavior::ContextDependent => { + // FIXME: rustc does the following, but given this is only relevant when the unstable + // `never_type_fallback` feature is active, I chose to not port this. + // if found_infer_var_info.self_in_trait && found_infer_var_info.output { + // // This case falls back to () to ensure that the code pattern in + // // tests/ui/never_type/fallback-closure-ret.rs continues to + // // compile when never_type_fallback is enabled. + // // + // // This rule is not readily explainable from first principles, + // // but is rather intended as a patchwork fix to ensure code + // // which compiles before the stabilization of never type + // // fallback continues to work. + // // + // // Typically this pattern is encountered in a function taking a + // // closure as a parameter, where the return type of that closure + // // (checked by `relationship.output`) is expected to implement + // // some trait (checked by `relationship.self_in_trait`). This + // // can come up in non-closure cases too, so we do not limit this + // // rule to specifically `FnOnce`. + // // + // // When the closure's body is something like `panic!()`, the + // // return type would normally be inferred to `!`. However, it + // // needs to fall back to `()` in order to still compile, as the + // // trait is specifically implemented for `()` but not `!`. + // // + // // For details on the requirements for these relationships to be + // // set, see the relationship finding module in + // // compiler/rustc_trait_selection/src/traits/relationships.rs. + // debug!("fallback to () - found trait and projection: {:?}", diverging_vid); + // fallback_to(self.types.unit); + // } + if can_reach_non_diverging { + debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); + fallback_to(self.types.unit); + } else { + debug!("fallback to ! - all diverging: {:?}", diverging_vid); + fallback_to(self.types.never); + } + } + DivergingFallbackBehavior::ToNever => { + debug!( + "fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}", + diverging_vid + ); + fallback_to(self.types.never); + } + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> Graph<(), ()> { + let pending_obligations = self.table.fulfillment_cx.pending_obligations(); + let pending_obligations_len = pending_obligations.len(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.kind().no_bound_vars() + }) + .filter_map(|atom| { + // We consider both subtyping and coercion to imply 'flow' from + // some position in the code `a` to a different position `b`. + // This is then used to determine which variables interact with + // live code, and as such must fall back to `()` to preserve + // soundness. + // + // In practice currently the two ways that this happens is + // coercion and subtyping. + let (a, b) = match atom { + PredicateKind::Coerce(CoercePredicate { a, b }) => (a, b), + PredicateKind::Subtype(SubtypePredicate { a_is_expected: _, a, b }) => (a, b), + _ => return None, + }; + + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid.as_u32(), b_vid.as_u32())) + }); + let num_ty_vars = self.table.infer_ctxt.num_ty_vars(); + let mut graph = Graph::with_capacity(num_ty_vars, pending_obligations_len); + for _ in 0..num_ty_vars { + graph.add_node(()); + } + graph.extend_with_edges(coercion_edges); + graph + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'db>) -> Option { + Some(self.table.infer_ctxt.root_var(self.shallow_resolve(ty).ty_vid()?)) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index dd7e77ba8c09..108cf5b1a2b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -3,8 +3,7 @@ use std::fmt; use chalk_ir::{ - CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable, - interner::HasInterner, + CanonicalVarKind, TyVariableKind, cast::Cast, fold::TypeFoldable, interner::HasInterner, }; use either::Either; use hir_def::{AdtId, lang_item::LangItem}; @@ -12,7 +11,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ - FloatVid, IntVid, TyVid, TypeVisitableExt, UpcastFrom, + TyVid, TypeVisitableExt, UpcastFrom, inherent::{IntoKind, Span, Term as _, Ty as _}, relate::{Relate, solver_relating::RelateExt}, solve::{Certainty, GoalSource}, @@ -23,8 +22,8 @@ use triomphe::Arc; use super::{InferResult, InferenceContext, TypeError}; use crate::{ AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData, - InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Scalar, Substitution, - TraitEnvironment, Ty, TyExt, TyKind, VariableKind, + InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, TraitEnvironment, Ty, + TyExt, TyKind, VariableKind, consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, @@ -143,7 +142,6 @@ pub fn could_unify_deeply( let ty1_with_vars = table.normalize_associated_types_in(ty1_with_vars); let ty2_with_vars = table.normalize_associated_types_in(ty2_with_vars); table.select_obligations_where_possible(); - table.propagate_diverging_flag(); let ty1_with_vars = table.resolve_completely(ty1_with_vars); let ty2_with_vars = table.resolve_completely(ty2_with_vars); table.unify_deeply(&ty1_with_vars, &ty2_with_vars) @@ -170,13 +168,19 @@ pub(crate) fn unify( GenericArgData::Const(c) => c.inference_var(Interner), } == Some(iv)) }; - let fallback = |iv, kind, default, binder| match kind { - chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)), - chalk_ir::VariableKind::Lifetime => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)), - chalk_ir::VariableKind::Const(ty) => find_var(iv) - .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)), + let fallback = |iv, kind, binder| match kind { + chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else( + || TyKind::Error.intern(Interner).cast(Interner), + |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner), + ), + chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else( + || crate::error_lifetime().cast(Interner), + |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner), + ), + chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else( + || crate::unknown_const(ty.clone()).cast(Interner), + |i| BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner), + ), }; Some(Substitution::from_iter( Interner, @@ -215,14 +219,13 @@ pub(crate) struct InferenceTable<'db> { pub(crate) trait_env: Arc>, pub(crate) tait_coercion_table: Option>, pub(crate) infer_ctxt: InferCtxt<'db>, - diverging_tys: FxHashSet, pub(super) fulfillment_cx: FulfillmentCtxt<'db>, + pub(super) diverging_type_vars: FxHashSet>, } pub(crate) struct InferenceTableSnapshot<'db> { ctxt_snapshot: CombinedSnapshot, obligations: FulfillmentCtxt<'db>, - diverging_tys: FxHashSet, } impl<'db> InferenceTable<'db> { @@ -238,7 +241,7 @@ impl<'db> InferenceTable<'db> { tait_coercion_table: None, fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), infer_ctxt, - diverging_tys: FxHashSet::default(), + diverging_type_vars: FxHashSet::default(), } } @@ -321,74 +324,8 @@ impl<'db> InferenceTable<'db> { } } - /// Chalk doesn't know about the `diverging` flag, so when it unifies two - /// type variables of which one is diverging, the chosen root might not be - /// diverging and we have no way of marking it as such at that time. This - /// function goes through all type variables and make sure their root is - /// marked as diverging if necessary, so that resolving them gives the right - /// result. - pub(super) fn propagate_diverging_flag(&mut self) { - let mut new_tys = FxHashSet::default(); - for ty in self.diverging_tys.iter() { - match ty.kind(Interner) { - TyKind::InferenceVar(var, kind) => match kind { - TyVariableKind::General => { - let root = InferenceVar::from( - self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32(), - ); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } - } - TyVariableKind::Integer => { - let root = InferenceVar::from( - self.infer_ctxt - .inner - .borrow_mut() - .int_unification_table() - .find(IntVid::from_usize(var.index() as usize)) - .as_u32(), - ); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } - } - TyVariableKind::Float => { - let root = InferenceVar::from( - self.infer_ctxt - .inner - .borrow_mut() - .float_unification_table() - .find(FloatVid::from_usize(var.index() as usize)) - .as_u32(), - ); - if root.index() != var.index() { - new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner)); - } - } - }, - _ => {} - } - } - self.diverging_tys.extend(new_tys); - } - - pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind) { - self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner)); - } - - fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - let is_diverging = - self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner)); - if is_diverging { - return TyKind::Never.intern(Interner); - } - match kind { - TyVariableKind::General => TyKind::Error, - TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), - TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), - } - .intern(Interner) + pub(super) fn set_diverging(&mut self, ty: crate::next_solver::Ty<'db>) { + self.diverging_type_vars.insert(ty); } pub(crate) fn canonicalize(&mut self, t: T) -> rustc_type_ir::Canonical, T> @@ -529,7 +466,7 @@ impl<'db> InferenceTable<'db> { let ty = var.to_ty(Interner, kind); if diverging { - self.diverging_tys.insert(ty.clone()); + self.diverging_type_vars.insert(ty.to_nextsolver(self.interner)); } ty } @@ -573,7 +510,7 @@ impl<'db> InferenceTable<'db> { pub(crate) fn resolve_with_fallback( &mut self, t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, ) -> T where T: HasInterner + TypeFoldable, @@ -615,7 +552,7 @@ impl<'db> InferenceTable<'db> { fn resolve_with_fallback_inner( &mut self, t: T, - fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, ) -> T where T: HasInterner + TypeFoldable, @@ -632,53 +569,15 @@ impl<'db> InferenceTable<'db> { T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { - let t = self.resolve_with_fallback(t, &|_, _, d, _| d); - let t = self.normalize_associated_types_in(t); - // let t = self.resolve_opaque_tys_in(t); - // Resolve again, because maybe normalization inserted infer vars. - self.resolve_with_fallback(t, &|_, _, d, _| d) - } + let value = t.to_nextsolver(self.interner); + let value = self.infer_ctxt.resolve_vars_if_possible(value); - /// Apply a fallback to unresolved scalar types. Integer type variables and float type - /// variables are replaced with i32 and f64, respectively. - /// - /// This method is only intended to be called just before returning inference results (i.e. in - /// `InferenceContext::resolve_all()`). - /// - /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables - /// whereas rustc replaces them with `()` or `!`. - pub(super) fn fallback_if_possible(&mut self) { - let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner); - let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner); + let mut goals = vec![]; + let value = value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals)); - let int_vars = self.infer_ctxt.inner.borrow_mut().int_unification_table().len(); - for v in 0..int_vars { - let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer); - let maybe_resolved = self.resolve_ty_shallow(&var); - if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { - // I don't think we can ever unify these vars with float vars, but keep this here for now - let fallback = match kind { - TyVariableKind::Integer => &int_fallback, - TyVariableKind::Float => &float_fallback, - TyVariableKind::General => unreachable!(), - }; - self.unify(&var, fallback); - } - } - let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len(); - for v in 0..float_vars { - let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Float); - let maybe_resolved = self.resolve_ty_shallow(&var); - if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) { - // I don't think we can ever unify these vars with float vars, but keep this here for now - let fallback = match kind { - TyVariableKind::Integer => &int_fallback, - TyVariableKind::Float => &float_fallback, - TyVariableKind::General => unreachable!(), - }; - self.unify(&var, fallback); - } - } + // FIXME(next-solver): Handle `goals`. + + value.to_chalk(self.interner) } /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that. @@ -829,15 +728,13 @@ impl<'db> InferenceTable<'db> { pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> { let ctxt_snapshot = self.infer_ctxt.start_snapshot(); - let diverging_tys = self.diverging_tys.clone(); let obligations = self.fulfillment_cx.clone(); - InferenceTableSnapshot { ctxt_snapshot, diverging_tys, obligations } + InferenceTableSnapshot { ctxt_snapshot, obligations } } #[tracing::instrument(skip_all)] pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) { self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot); - self.diverging_tys = snapshot.diverging_tys; self.fulfillment_cx = snapshot.obligations; } @@ -1166,14 +1063,10 @@ impl fmt::Debug for InferenceTable<'_> { mod resolve { use super::InferenceTable; use crate::{ - ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg, - InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind, - next_solver::mapping::NextSolverToChalk, - }; - use chalk_ir::{ - cast::Cast, - fold::{TypeFoldable, TypeFolder}, + Const, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind, + VariableKind, next_solver::mapping::NextSolverToChalk, }; + use chalk_ir::fold::{TypeFoldable, TypeFolder}; use rustc_type_ir::{FloatVid, IntVid, TyVid}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -1187,7 +1080,7 @@ mod resolve { pub(super) struct Resolver< 'a, 'b, - F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, > { pub(super) table: &'a mut InferenceTable<'b>, pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>, @@ -1195,7 +1088,7 @@ mod resolve { } impl TypeFolder for Resolver<'_, '_, F> where - F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg, { fn as_dyn(&mut self) -> &mut dyn TypeFolder { self @@ -1217,8 +1110,7 @@ mod resolve { let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type - let default = self.table.fallback_value(var, kind).cast(Interner); - return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone(); } @@ -1230,8 +1122,7 @@ mod resolve { self.var_stack.pop(); result } else { - let default = self.table.fallback_value(var, kind).cast(Interner); - (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone() } @@ -1247,8 +1138,7 @@ mod resolve { let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type - let default = self.table.fallback_value(var, kind).cast(Interner); - return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone(); } @@ -1260,8 +1150,7 @@ mod resolve { self.var_stack.pop(); result } else { - let default = self.table.fallback_value(var, kind).cast(Interner); - (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone() } @@ -1277,8 +1166,7 @@ mod resolve { let var = InferenceVar::from(vid.as_u32()); if self.var_stack.contains(&(var, VarKind::Ty(kind))) { // recursive type - let default = self.table.fallback_value(var, kind).cast(Interner); - return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + return (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone(); } @@ -1290,8 +1178,7 @@ mod resolve { self.var_stack.pop(); result } else { - let default = self.table.fallback_value(var, kind).cast(Interner); - (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + (self.fallback)(var, VariableKind::Ty(kind), outer_binder) .assert_ty_ref(Interner) .clone() } @@ -1310,15 +1197,9 @@ mod resolve { .infer_ctxt .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index())); let var = InferenceVar::from(vid.as_u32()); - let default = ConstData { - ty: ty.clone(), - value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }), - } - .intern(Interner) - .cast(Interner); if self.var_stack.contains(&(var, VarKind::Const)) { // recursive - return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) + return (self.fallback)(var, VariableKind::Const(ty), outer_binder) .assert_const_ref(Interner) .clone(); } @@ -1330,7 +1211,7 @@ mod resolve { self.var_stack.pop(); result } else { - (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) + (self.fallback)(var, VariableKind::Const(ty), outer_binder) .assert_const_ref(Interner) .clone() } @@ -1349,3 +1230,124 @@ mod resolve { } } } + +mod resolve_completely { + use rustc_type_ir::{ + DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable, + inherent::{Const as _, Ty as _}, + }; + + use crate::next_solver::Region; + use crate::{ + infer::unify::InferenceTable, + next_solver::{ + Const, DbInterner, ErrorGuaranteed, Goal, Predicate, Term, Ty, + infer::traits::ObligationCause, + normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, + }, + }; + + pub(super) struct Resolver<'a, 'db> { + ctx: &'a mut InferenceTable<'db>, + /// Whether we should normalize, disabled when resolving predicates. + should_normalize: bool, + nested_goals: &'a mut Vec>>, + } + + impl<'a, 'db> Resolver<'a, 'db> { + pub(super) fn new( + ctx: &'a mut InferenceTable<'db>, + should_normalize: bool, + nested_goals: &'a mut Vec>>, + ) -> Resolver<'a, 'db> { + Resolver { ctx, nested_goals, should_normalize } + } + + fn handle_term( + &mut self, + value: T, + outer_exclusive_binder: impl FnOnce(T) -> DebruijnIndex, + ) -> T + where + T: Into> + TypeSuperFoldable> + Copy, + { + let value = if self.should_normalize { + let cause = ObligationCause::new(); + let at = self.ctx.infer_ctxt.at(&cause, self.ctx.trait_env.env); + let universes = vec![None; outer_exclusive_binder(value).as_usize()]; + match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( + at, value, universes, + ) { + Ok((value, goals)) => { + self.nested_goals.extend(goals); + value + } + Err(_errors) => { + // FIXME: Report the error. + value + } + } + } else { + value + }; + + value.fold_with(&mut ReplaceInferWithError { interner: self.ctx.interner }) + } + } + + impl<'cx, 'db> TypeFolder> for Resolver<'cx, 'db> { + fn cx(&self) -> DbInterner<'db> { + self.ctx.interner + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if r.is_var() { Region::error(self.ctx.interner) } else { r } + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + self.handle_term(ty, |it| it.outer_exclusive_binder()) + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + self.handle_term(ct, |it| it.outer_exclusive_binder()) + } + + fn fold_predicate(&mut self, predicate: Predicate<'db>) -> Predicate<'db> { + assert!( + !self.should_normalize, + "normalizing predicates in writeback is not generally sound" + ); + predicate.super_fold_with(self) + } + } + + struct ReplaceInferWithError<'db> { + interner: DbInterner<'db>, + } + + impl<'db> TypeFolder> for ReplaceInferWithError<'db> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + if t.is_infer() { + Ty::new_error(self.interner, ErrorGuaranteed) + } else { + t.super_fold_with(self) + } + } + + fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { + if c.is_ct_infer() { + Const::new_error(self.interner, ErrorGuaranteed) + } else { + c.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if r.is_var() { Region::error(self.interner) } else { r } + } + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 073a02908dee..ab167e88af2e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -13,7 +13,7 @@ pub(crate) mod inspect; pub mod interner; mod ir_print; pub mod mapping; -mod normalize; +pub mod normalize; pub mod obligation_ctxt; mod opaques; pub mod predicate; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index d6214d991560..0bfd2b8003d0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -15,7 +15,7 @@ use super::{ interner::{BoundVarKind, DbInterner, Placeholder}, }; -type RegionKind<'db> = rustc_type_ir::RegionKind>; +pub type RegionKind<'db> = rustc_type_ir::RegionKind>; #[salsa::interned(constructor = new_, debug)] pub struct Region<'db> { @@ -53,6 +53,10 @@ impl<'db> Region<'db> { Region::new(interner, RegionKind::ReVar(v)) } + pub fn new_erased(interner: DbInterner<'db>) -> Region<'db> { + Region::new(interner, RegionKind::ReErased) + } + pub fn is_placeholder(&self) -> bool { matches!(self.inner(), RegionKind::RePlaceholder(..)) } @@ -61,6 +65,10 @@ impl<'db> Region<'db> { matches!(self.inner(), RegionKind::ReStatic) } + pub fn is_var(&self) -> bool { + matches!(self.inner(), RegionKind::ReVar(_)) + } + pub fn error(interner: DbInterner<'db>) -> Self { Region::new(interner, RegionKind::ReError(ErrorGuaranteed)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index c7a747ade3e7..16bf082b01a3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -7,6 +7,7 @@ use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId}; use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; +use rustc_type_ir::TyVid; use rustc_type_ir::{ BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, @@ -338,6 +339,14 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty()) } + #[inline] + pub fn ty_vid(self) -> Option { + match self.kind() { + TyKind::Infer(rustc_type_ir::TyVar(vid)) => Some(vid), + _ => None, + } + } + /// Given a `fn` type, returns an equivalent `unsafe fn` type; /// that is, a `fn` type that is equivalent in every way for being /// unsafe. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index af5290d72035..4d68179a88b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -14,8 +14,6 @@ fn test() { ); } -// FIXME(next-solver): The never type fallback implemented in r-a no longer works properly because of -// `Coerce` predicates. We should reimplement fallback like rustc. #[test] fn infer_never2() { check_types( @@ -26,7 +24,7 @@ fn test() { let a = gen(); if false { a } else { loop {} }; a; -} //^ {unknown} +} //^ ! "#, ); } @@ -41,7 +39,7 @@ fn test() { let a = gen(); if false { loop {} } else { a }; a; - //^ {unknown} + //^ ! } "#, ); @@ -56,7 +54,7 @@ enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; -} //^ Option<{unknown}> +} //^ Option "#, ); } @@ -220,7 +218,7 @@ fn test(a: i32) { _ => loop {}, }; i; -} //^ {unknown} +} //^ ! "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index a6215ef8fe4f..00835aa03130 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1951,7 +1951,7 @@ fn main() { Alias::Braced; //^^^^^^^^^^^^^ {unknown} let Alias::Braced = loop {}; - //^^^^^^^^^^^^^ {unknown} + //^^^^^^^^^^^^^ ! let Alias::Braced(..) = loop {}; //^^^^^^^^^^^^^^^^^ Enum diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 1db4f8ecd6ba..920bdd9568fc 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -516,4 +516,5 @@ define_symbols! { flags, precision, width, + never_type_fallback, } From 60dd0df6e73e195b9779121bac7e2927ddcf48f2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 24 Sep 2025 13:52:33 -0400 Subject: [PATCH 226/537] Address review comments --- .../rustc_error_codes/src/error_codes/E0719.md | 2 +- .../src/hir_ty_lowering/bounds.rs | 5 +++-- .../src/hir_ty_lowering/dyn_trait.rs | 6 ++++-- .../src/hir_ty_lowering/mod.rs | 18 +++++++++++++++--- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md index 17cbd2de49ef..6aec38b42a3b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0719.md +++ b/compiler/rustc_error_codes/src/error_codes/E0719.md @@ -1,4 +1,4 @@ -An associated item value was specified more than once in a trait object. +An associated item was specified more than once in a trait object. Erroneous code example: diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a8d75ba223ab..a59520f16feb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -21,7 +21,8 @@ use tracing::{debug, instrument}; use super::errors::GenericsArgsErrExtend; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, + AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, + RegionInferReason, }; #[derive(Debug, Default)] @@ -362,7 +363,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { param_ty, bounds, predicate_filter, - false, + OverlappingAsssocItemConstraints::Allowed, ); } hir::GenericBound::Outlives(lifetime) => { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index a4179776572d..c0b137730892 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -23,7 +23,9 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; -use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, +}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a trait object type from the HIR to our internal notion of a type. @@ -60,7 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, - true, + OverlappingAsssocItemConstraints::Forbidden, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { potential_assoc_types.extend(invalid_args); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 0ff1fabd7b30..cc5c0d0ad6ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition { MethodCall, } +/// Whether to allow duplicate associated iten constraints in a trait ref, e.g. +/// `Trait`. This is forbidden in `dyn Trait<...>` +/// but allowed everywhere else. +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum OverlappingAsssocItemConstraints { + Allowed, + Forbidden, +} + /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. #[derive(Clone, Debug)] @@ -752,7 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, - for_dyn: bool, + overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints, ) -> GenericArgCountResult { let tcx = self.tcx(); @@ -909,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let mut dup_constraints = FxIndexMap::default(); + let mut dup_constraints = (overlapping_assoc_item_constraints + == OverlappingAsssocItemConstraints::Forbidden) + .then_some(FxIndexMap::default()); + for constraint in trait_segment.args().constraints { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they @@ -928,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { poly_trait_ref, constraint, bounds, - for_dyn.then_some(&mut dup_constraints), + dup_constraints.as_mut(), constraint.span, predicate_filter, ); From a86f14072714fb817a6f60fa20be5a4e875d049f Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Tue, 12 Aug 2025 06:39:50 +0800 Subject: [PATCH 227/537] do not materialise X in [X; 0] when X is unsizing a const --- .../src/builder/expr/as_rvalue.rs | 21 ++++++++++++- ...no_local_for_coerced_const-issue-143671.rs | 30 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index a4ef6e927392..d6dc12e5955a 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -8,6 +8,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::{CastTy, mir_cast_kind}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; @@ -656,6 +657,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(rvalue) } + /// Recursively inspect a THIR expression and probe through unsizing + /// operations that can be const-folded today. + fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool { + loop { + match kind { + &ExprKind::PointerCoercion { + cast: PointerCoercion::Unsize, + source: eid, + is_from_as_cast: _, + } + | &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => { + kind = &self.thir[eid].kind + } + _ => return matches!(Category::of(&kind), Some(Category::Constant)), + } + } + } + fn build_zero_repeat( &mut self, mut block: BasicBlock, @@ -666,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let this = self; let value_expr = &this.thir[value]; let elem_ty = value_expr.ty; - if let Some(Category::Constant) = Category::of(&value_expr.kind) { + if this.check_constness(&value_expr.kind) { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` diff --git a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs new file mode 100644 index 000000000000..eb814e9723c1 --- /dev/null +++ b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(unsize)] +#![feature(coerce_unsized)] + +use std::fmt::Display; +use std::marker::Unsize; +use std::ops::CoerceUnsized; + +#[repr(transparent)] +struct X<'a, T: ?Sized> { + f: &'a T, +} + +impl<'a, T: ?Sized> Drop for X<'a, T> { + fn drop(&mut self) { + panic!() + } +} + +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for X<'a, T> where + &'a T: CoerceUnsized<&'a U> +{ +} + +const Y: X<'static, i32> = X { f: &0 }; + +fn main() { + let _: [X<'static, dyn Display>; 0] = [Y; 0]; +} From 120162e30ffa92308a6a3a76f2328467fbd10ced Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Wed, 13 Aug 2025 02:26:04 +0800 Subject: [PATCH 228/537] add test fixture for newly allowed const expr Signed-off-by: Ding Xiang Fei Co-authored-by: Theemathas Chirananthavat --- .../coercion/no_local_for_coerced_const-issue-143671.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs index eb814e9723c1..5924809f34c8 100644 --- a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs +++ b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs @@ -6,6 +6,7 @@ use std::fmt::Display; use std::marker::Unsize; use std::ops::CoerceUnsized; +use std::rc::Weak; #[repr(transparent)] struct X<'a, T: ?Sized> { @@ -27,4 +28,11 @@ const Y: X<'static, i32> = X { f: &0 }; fn main() { let _: [X<'static, dyn Display>; 0] = [Y; 0]; + coercion_on_weak_in_const(); +} + +fn coercion_on_weak_in_const() { + const X: Weak = Weak::new(); + const Y: [Weak; 0] = [X; 0]; + let _ = Y; } From b77de834c031890c048f8164d4b5979d2511c00e Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 25 Sep 2025 01:53:34 +0800 Subject: [PATCH 229/537] mark THIR use as candidate for constness check --- compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs | 5 ++++- .../coercion/no_local_for_coerced_const-issue-143671.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index d6dc12e5955a..3a5839f2d404 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -661,8 +661,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// operations that can be const-folded today. fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool { loop { + debug!(?kind, "check_constness"); match kind { - &ExprKind::PointerCoercion { + &ExprKind::ValueTypeAscription { source: eid, user_ty: _, user_ty_span: _ } + | &ExprKind::Use { source: eid } + | &ExprKind::PointerCoercion { cast: PointerCoercion::Unsize, source: eid, is_from_as_cast: _, diff --git a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs index 5924809f34c8..38479d9070b8 100644 --- a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs +++ b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs @@ -29,6 +29,7 @@ const Y: X<'static, i32> = X { f: &0 }; fn main() { let _: [X<'static, dyn Display>; 0] = [Y; 0]; coercion_on_weak_in_const(); + coercion_on_weak_as_cast(); } fn coercion_on_weak_in_const() { @@ -36,3 +37,10 @@ fn coercion_on_weak_in_const() { const Y: [Weak; 0] = [X; 0]; let _ = Y; } + +fn coercion_on_weak_as_cast() { + const Y: X<'static, i32> = X { f: &0 }; + // What happens in the following code is that + // a constant is explicitly coerced into + let _a: [X<'static, dyn Display>; 0] = [Y as X<'static, dyn Display>; 0]; +} From 5bec161ce12501695356492129ea8fc952a30f85 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 24 Sep 2025 10:34:52 -0700 Subject: [PATCH 230/537] rustdoc-search: stringdex update with more packing Before: 18M build/x86_64-unknown-linux-gnu/doc/search.index/ 57M build/x86_64-unknown-linux-gnu/compiler-doc/search.index/ After: 16M build/x86_64-unknown-linux-gnu/doc/search.index/ 49M build/x86_64-unknown-linux-gnu/compiler-doc/search.index/ --- Cargo.lock | 4 +- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/static/js/stringdex.js | 78 ++++++++++++++-------- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2e635b4cfe6..7c2eb559b21e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5233,9 +5233,9 @@ dependencies = [ [[package]] name = "stringdex" -version = "0.0.1-alpha9" +version = "0.0.1-alpha10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7081029913fd7d591c0112182aba8c98ae886b4f12edb208130496cd17dc3c15" +checksum = "0fa846a7d509d1828a4f90962dc09810e161abcada7fc6a921e92c168d0811d7" dependencies = [ "stacker", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index f37a8d85361f..0d77fe64e30f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" -stringdex = { version = "0.0.1-alpha9" } +stringdex = { version = "0.0.1-alpha10" } tempfile = "3" threadpool = "1.8.1" tracing = "0.1" diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index 5bdc81e330ef..6299576d5643 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -1108,22 +1108,39 @@ function loadDatabase(hooks) { const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]); leaves = RoaringBitmap.makeSingleton(id1) .union(RoaringBitmap.makeSingleton(id2)); + } else if (!isWhole && (nodeid[0] & 0xf0) === 0x80) { + const id1 = ((nodeid[0] & 0x0f) << 16) | (nodeid[1] << 8) | nodeid[2]; + const id2 = id1 + ((nodeid[3] << 4) | ((nodeid[4] >> 4) & 0x0f)); + const id3 = id2 + (((nodeid[4] & 0x0f) << 8) | nodeid[5]); + leaves = RoaringBitmap.makeSingleton(id1) + .union(RoaringBitmap.makeSingleton(id2)) + .union(RoaringBitmap.makeSingleton(id3)); } else { leaves = RoaringBitmap.makeSingleton( (nodeid[2] << 24) | (nodeid[3] << 16) | (nodeid[4] << 8) | nodeid[5], ); } - const data = (nodeid[0] & 0x20) !== 0 ? - Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) : - EMPTY_UINT8; - newPromise = Promise.resolve(new PrefixSearchTree( - EMPTY_SEARCH_TREE_BRANCHES, - EMPTY_SEARCH_TREE_BRANCHES, - data, - isWhole ? leaves : EMPTY_BITMAP, - isWhole ? EMPTY_BITMAP : leaves, - )); + if (isWhole) { + const data = (nodeid[0] & 0x20) !== 0 ? + Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) : + EMPTY_UINT8; + newPromise = Promise.resolve(new PrefixSearchTree( + EMPTY_SEARCH_TREE_BRANCHES, + EMPTY_SEARCH_TREE_BRANCHES, + data, + leaves, + EMPTY_BITMAP, + )); + } else { + const data = (nodeid[0] & 0xf0) === 0x80 ? 0 : ( + ((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)); + newPromise = Promise.resolve(new SuffixSearchTree( + EMPTY_SEARCH_TREE_BRANCHES, + data, + leaves, + )); + } } else { const hashHex = makeHexFromUint8Array(nodeid); newPromise = new Promise((resolve, reject) => { @@ -2748,6 +2765,7 @@ function loadDatabase(hooks) { // because that's the canonical, hashed version of the data let compression_tag = input[i]; const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0; + let no_leaves_flag; if (compression_tag > 1) { // compressed node const is_long_compressed = (compression_tag & 0x04) !== 0; @@ -2759,7 +2777,8 @@ function loadDatabase(hooks) { compression_tag |= input[i] << 16; i += 1; } - let dlen = input[i]; + let dlen = input[i] & 0x7F; + no_leaves_flag = input[i] & 0x80; i += 1; if (is_data_compressed) { data = data_history[data_history.length - dlen - 1]; @@ -2786,10 +2805,15 @@ function loadDatabase(hooks) { let whole; let suffix; if (is_pure_suffixes_only_node) { - suffix = input[i] === 0 ? - EMPTY_BITMAP1 : - new RoaringBitmap(input, i); - i += suffix.consumed_len_bytes; + if (no_leaves_flag) { + whole = EMPTY_BITMAP; + suffix = EMPTY_BITMAP; + } else { + suffix = input[i] === 0 ? + EMPTY_BITMAP1 : + new RoaringBitmap(input, i); + i += suffix.consumed_len_bytes; + } tree = new SuffixSearchTree( branches, dlen, @@ -2807,7 +2831,7 @@ function loadDatabase(hooks) { let ci = 0; canonical[ci] = 1; ci += 1; - canonical[ci] = dlen; + canonical[ci] = dlen | no_leaves_flag; ci += 1; canonical[ci] = input[coffset]; // suffix child count ci += 1; @@ -2821,10 +2845,9 @@ function loadDatabase(hooks) { } siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash); } else { - if (input[i] === 0xff) { + if (no_leaves_flag) { whole = EMPTY_BITMAP; - suffix = EMPTY_BITMAP1; - i += 1; + suffix = EMPTY_BITMAP; } else { whole = input[i] === 0 ? EMPTY_BITMAP1 : @@ -2856,7 +2879,7 @@ function loadDatabase(hooks) { let ci = 0; canonical[ci] = 0; ci += 1; - canonical[ci] = dlen; + canonical[ci] = dlen | no_leaves_flag; ci += 1; canonical.set(data, ci); ci += data.length; @@ -2880,9 +2903,11 @@ function loadDatabase(hooks) { } hash[2] &= 0x7f; } else { + i += 1; // uncompressed node - const dlen = input [i + 1]; - i += 2; + const dlen = input[i] & 0x7F; + no_leaves_flag = input[i] & 0x80; + i += 1; if (dlen === 0 || is_pure_suffixes_only_node) { data = EMPTY_UINT8; } else { @@ -2897,16 +2922,15 @@ function loadDatabase(hooks) { i += branches_consumed_len_bytes; let whole; let suffix; - if (is_pure_suffixes_only_node) { + if (no_leaves_flag) { + whole = EMPTY_BITMAP; + suffix = EMPTY_BITMAP; + } else if (is_pure_suffixes_only_node) { whole = EMPTY_BITMAP; suffix = input[i] === 0 ? EMPTY_BITMAP1 : new RoaringBitmap(input, i); i += suffix.consumed_len_bytes; - } else if (input[i] === 0xff) { - whole = EMPTY_BITMAP; - suffix = EMPTY_BITMAP; - i += 1; } else { whole = input[i] === 0 ? EMPTY_BITMAP1 : From a9554b4d5f2666b0bce66dfb8f70a41092c9265f Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 24 Sep 2025 20:02:34 +0100 Subject: [PATCH 231/537] Clarify Display for error should not include source --- library/core/src/error.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 92b3c83d1bf3..9ca91ee009ee 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -16,13 +16,19 @@ use crate::fmt::{self, Debug, Display, Formatter}; /// assert_eq!(err.to_string(), "invalid digit found in string"); /// ``` /// +/// # Error source +/// /// Errors may provide cause information. [`Error::source()`] is generally /// used when errors cross "abstraction boundaries". If one module must report /// an error that is caused by an error from a lower-level module, it can allow -/// accessing that error via [`Error::source()`]. This makes it possible for the +/// accessing that error via `Error::source()`. This makes it possible for the /// high-level module to provide its own errors while also revealing some of the /// implementation for debugging. /// +/// In error types that wrap an underlying error, the underlying error +/// should be either returned by the outer error's `Error::source()`, or rendered +/// by the outer error's `Display` implementation, but not both. +/// /// # Example /// /// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too. From a00f24116e9bcecc8c73f9f7ec0c399964b37a92 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Thu, 18 Sep 2025 15:02:49 -0400 Subject: [PATCH 232/537] unstably constify float mul_add methods Co-authored-by: Ralf Jung --- .../src/interpret/intrinsics.rs | 46 +++++++++++++++++++ .../rustc_const_eval/src/interpret/machine.rs | 8 ++++ library/core/src/intrinsics/mod.rs | 16 +++---- library/core/src/num/f128.rs | 3 +- library/core/src/num/f16.rs | 3 +- library/core/src/num/f32.rs | 3 +- library/core/src/num/f64.rs | 3 +- library/coretests/tests/floats/f128.rs | 18 -------- library/coretests/tests/floats/f16.rs | 18 -------- library/coretests/tests/floats/f32.rs | 21 --------- library/coretests/tests/floats/f64.rs | 21 --------- library/coretests/tests/floats/mod.rs | 39 +++++++++++++++- library/coretests/tests/lib.rs | 1 + library/std/src/lib.rs | 1 + library/std/src/num/f32.rs | 3 +- library/std/src/num/f64.rs | 3 +- src/tools/miri/src/intrinsics/math.rs | 41 ----------------- src/tools/miri/src/machine.rs | 5 ++ 18 files changed, 118 insertions(+), 135 deletions(-) delete mode 100644 library/coretests/tests/floats/f32.rs delete mode 100644 library/coretests/tests/floats/f64.rs diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 418dd658121d..785978b4d711 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,6 +636,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest, rustc_apfloat::Round::NearestTiesToEven, )?, + sym::fmaf16 => self.fma_intrinsic::(args, dest)?, + sym::fmaf32 => self.fma_intrinsic::(args, dest)?, + sym::fmaf64 => self.fma_intrinsic::(args, dest)?, + sym::fmaf128 => self.fma_intrinsic::(args, dest)?, + sym::fmuladdf16 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf32 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf64 => self.float_muladd_intrinsic::(args, dest)?, + sym::fmuladdf128 => self.float_muladd_intrinsic::(args, dest)?, // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), @@ -1035,4 +1043,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(res, dest)?; interp_ok(()) } + + fn fma_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let res = a.mul_add(b, c).value; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_muladd_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let fuse = M::float_fuse_mul_add(self); + + let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index e22629993fba..1725635e0b47 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -289,6 +289,9 @@ pub trait Machine<'tcx>: Sized { a } + /// Determines whether the `fmuladd` intrinsics fuse the multiply-add or use separate operations. + fn float_fuse_mul_add(_ecx: &mut InterpCx<'tcx, Self>) -> bool; + /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { @@ -672,6 +675,11 @@ pub macro compile_time_machine(<$tcx: lifetime>) { match fn_val {} } + #[inline(always)] + fn float_fuse_mul_add(_ecx: &mut InterpCx<$tcx, Self>) -> bool { + true + } + #[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 diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a174ced5a2a6..98eec7303da6 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1312,28 +1312,28 @@ pub fn log2f128(x: f128) -> f128; /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf16(a: f16, b: f16, c: f16) -> f16; +pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; +pub const fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; +pub const fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values. /// /// The stabilized version of this intrinsic is /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; +pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// Returns `a * b + c` for `f16` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the @@ -1347,7 +1347,7 @@ pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; +pub const fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1360,7 +1360,7 @@ pub fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; +pub const fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1373,7 +1373,7 @@ pub fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; +pub const fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -1386,7 +1386,7 @@ pub fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// example. #[rustc_intrinsic] #[rustc_nounwind] -pub fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; +pub const fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// Returns the largest integer less than or equal to an `f16`. /// diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 6088fb6fa178..7653db0bf7db 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1659,7 +1659,8 @@ impl f128 { #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f128, b: f128) -> f128 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f128, b: f128) -> f128 { intrinsics::fmaf128(self, a, b) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3f66c5973d4a..58b4dfb4bdf8 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1634,7 +1634,8 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f16, b: f16) -> f16 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f16, b: f16) -> f16 { intrinsics::fmaf16(self, a, b) } diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index ebce89e5b3da..6ff7d24726b5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1799,7 +1799,8 @@ pub mod math { #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "core_float_math", issue = "137578")] - pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(x: f32, y: f32, z: f32) -> f32 { intrinsics::fmaf32(x, y, z) } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 91e3949fc390..f8529a5469bc 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1797,7 +1797,8 @@ pub mod math { #[doc(alias = "fma", alias = "fusedMultiplyAdd")] #[unstable(feature = "core_float_math", issue = "137578")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(x: f64, a: f64, b: f64) -> f64 { intrinsics::fmaf64(x, a, b) } diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index d31eba863f5f..62278bf96c3c 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -20,24 +20,6 @@ const TOL_PRECISE: f128 = 1e-28; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_mul_add() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(12.3f128.mul_add(4.5, 6.7), 62.0500000000000000000000000000000037); - assert_biteq!((-12.3f128).mul_add(-4.5, -6.7), 48.6500000000000000000000000000000049); - assert_biteq!(0.0f128.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f128.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f128.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_max_recip() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 302fd0861d75..7ffafd467a51 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -22,24 +22,6 @@ const TOL_P4: f16 = 10.0; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_mul_add() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(12.3f16.mul_add(4.5, 6.7), 62.031); - assert_biteq!((-12.3f16).mul_add(-4.5, -6.7), 48.625); - assert_biteq!(0.0f16.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f16.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f16.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_max_recip() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs deleted file mode 100644 index a1fe8b076501..000000000000 --- a/library/coretests/tests/floats/f32.rs +++ /dev/null @@ -1,21 +0,0 @@ -use core::f32; - -use super::assert_biteq; - -// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] -#[test] -fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(f32::math::mul_add(12.3f32, 4.5, 6.7), 62.05); - assert_biteq!(f32::math::mul_add(-12.3f32, -4.5, -6.7), 48.65); - assert_biteq!(f32::math::mul_add(0.0f32, 8.9, 1.2), 1.2); - assert_biteq!(f32::math::mul_add(3.4f32, -0.0, 5.6), 5.6); - assert!(f32::math::mul_add(nan, 7.8, 9.0).is_nan()); - assert_biteq!(f32::math::mul_add(inf, 7.8, 9.0), inf); - assert_biteq!(f32::math::mul_add(neg_inf, 7.8, 9.0), neg_inf); - assert_biteq!(f32::math::mul_add(8.9f32, inf, 3.2), inf); - assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); -} diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs deleted file mode 100644 index 4c5a3d68d1fd..000000000000 --- a/library/coretests/tests/floats/f64.rs +++ /dev/null @@ -1,21 +0,0 @@ -use core::f64; - -use super::assert_biteq; - -// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ -#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] -#[test] -fn test_mul_add() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(12.3f64.mul_add(4.5, 6.7), 62.050000000000004); - assert_biteq!((-12.3f64).mul_add(-4.5, -6.7), 48.650000000000006); - assert_biteq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_biteq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_biteq!(inf.mul_add(7.8, 9.0), inf); - assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_biteq!(8.9f64.mul_add(inf, 3.2), inf); - assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); -} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 31515561c637..9f52adcb6e20 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -34,6 +34,10 @@ trait TestableFloat: Sized { const RAW_12_DOT_5: Self; const RAW_1337: Self; const RAW_MINUS_14_DOT_25: Self; + /// The result of 12.3.mul_add(4.5, 6.7) + const MUL_ADD_RESULT: Self; + /// The result of (-12.3).mul_add(-4.5, -6.7) + const NEG_MUL_ADD_RESULT: Self; } impl TestableFloat for f16 { @@ -58,6 +62,8 @@ impl TestableFloat for f16 { const RAW_12_DOT_5: Self = Self::from_bits(0x4a40); const RAW_1337: Self = Self::from_bits(0x6539); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20); + const MUL_ADD_RESULT: Self = 62.031; + const NEG_MUL_ADD_RESULT: Self = 48.625; } impl TestableFloat for f32 { @@ -84,6 +90,8 @@ impl TestableFloat for f32 { const RAW_12_DOT_5: Self = Self::from_bits(0x41480000); const RAW_1337: Self = Self::from_bits(0x44a72000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000); + const MUL_ADD_RESULT: Self = 62.05; + const NEG_MUL_ADD_RESULT: Self = 48.65; } impl TestableFloat for f64 { @@ -106,6 +114,8 @@ impl TestableFloat for f64 { const RAW_12_DOT_5: Self = Self::from_bits(0x4029000000000000); const RAW_1337: Self = Self::from_bits(0x4094e40000000000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000); + const MUL_ADD_RESULT: Self = 62.050000000000004; + const NEG_MUL_ADD_RESULT: Self = 48.650000000000006; } impl TestableFloat for f128 { @@ -128,6 +138,8 @@ impl TestableFloat for f128 { const RAW_12_DOT_5: Self = Self::from_bits(0x40029000000000000000000000000000); const RAW_1337: Self = Self::from_bits(0x40094e40000000000000000000000000); const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000); + const MUL_ADD_RESULT: Self = 62.0500000000000000000000000000000037; + const NEG_MUL_ADD_RESULT: Self = 48.6500000000000000000000000000000049; } /// Determine the tolerance for values of the argument type. @@ -359,8 +371,6 @@ macro_rules! float_test { mod f128; mod f16; -mod f32; -mod f64; float_test! { name: num, @@ -1542,3 +1552,28 @@ float_test! { assert_biteq!(Float::from_bits(masked_nan2), Float::from_bits(masked_nan2)); } } + +float_test! { + name: mul_add, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ + f32: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], + f64: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!(flt(12.3).mul_add(4.5, 6.7), Float::MUL_ADD_RESULT); + assert_biteq!((flt(-12.3)).mul_add(-4.5, -6.7), Float::NEG_MUL_ADD_RESULT); + assert_biteq!(flt(0.0).mul_add(8.9, 1.2), 1.2); + assert_biteq!(flt(3.4).mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_biteq!(inf.mul_add(7.8, 9.0), inf); + assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_biteq!(flt(8.9).mul_add(inf, 3.2), inf); + assert_biteq!((flt(-3.2)).mul_add(2.4, neg_inf), neg_inf); + } +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5c519f3a499d..a80d7f8b44d7 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_convert)] #![feature(const_destruct)] #![feature(const_eval_select)] +#![feature(const_mul_add)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 45abd6bca8a5..233e41aa3453 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -332,6 +332,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] +#![feature(const_mul_add)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index ac1d889cc373..e7810e77e76f 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -217,7 +217,8 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f32, b: f32) -> f32 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f32, b: f32) -> f32 { core::f32::math::mul_add(self, a, b) } diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 55c8593a0c0b..cbebbfb1be16 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -217,7 +217,8 @@ impl f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f64, b: f64) -> f64 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f64, b: f64) -> f64 { core::f64::math::mul_add(self, a, b) } diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index b9c99f285946..0cc4342f0d55 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -1,4 +1,3 @@ -use rand::Rng; use rustc_apfloat::{self, Float, FloatConvert, Round}; use rustc_middle::mir; use rustc_middle::ty::{self, FloatTy}; @@ -39,46 +38,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "sqrtf64" => sqrt::(this, args, dest)?, "sqrtf128" => sqrt::(this, args, dest)?, - "fmaf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmaf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let res = a.mul_add(b, c).value; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - - "fmuladdf32" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - "fmuladdf64" => { - let [a, b, c] = check_intrinsic_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); - let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; - let res = this.adjust_nan(res, &[a, b, c]); - this.write_scalar(res, dest)?; - } - #[rustfmt::skip] | "fadd_fast" | "fsub_fast" diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 04c8bee72c03..d307636e782f 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1293,6 +1293,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.equal_float_min_max(a, b) } + #[inline(always)] + fn float_fuse_mul_add(ecx: &mut InterpCx<'tcx, Self>) -> bool { + ecx.machine.float_nondet && ecx.machine.rng.get_mut().random() + } + #[inline(always)] fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { interp_ok(ecx.tcx.sess.ub_checks()) From a22334371cb7d3cf358c025772292d5b8f2b9519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 24 Sep 2025 21:49:12 +0200 Subject: [PATCH 233/537] Make install test target independent --- src/bootstrap/src/core/builder/tests.rs | 116 +++++++++++++----------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 87bea431a058..e595ca5b28e1 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2857,63 +2857,69 @@ mod snapshot { // Using backslashes fails with `--set` "--set", &format!("install.prefix={}", ctx.dir().display()).replace("\\", "/"), "--set", &format!("install.sysconfdir={}", ctx.dir().display()).replace("\\", "/"), - "--set", "build.extended=true" + "--set", "build.extended=true", + // For Cranelift to be disted + "--build", "x86_64-unknown-linux-gnu", + "--host", "x86_64-unknown-linux-gnu" ]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd 1 - [build] rustc 0 -> UnstableBookGen 1 - [build] rustc 0 -> Rustbook 1 - [doc] unstable-book (book) - [build] rustc 1 -> std 1 - [doc] book (book) - [doc] book/first-edition (book) - [doc] book/second-edition (book) - [doc] book/2018-edition (book) - [build] rustdoc 1 - [doc] rustc 1 -> standalone 2 - [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd 2 - [build] rustc 1 -> error-index 2 - [doc] rustc 1 -> error-index 2 - [doc] nomicon (book) - [doc] rustc 1 -> reference (book) 2 - [doc] rustdoc (book) - [doc] rust-by-example (book) - [build] rustc 0 -> LintDocs 1 - [doc] rustc (book) - [doc] cargo (book) - [doc] clippy (book) - [doc] embedded-book (book) - [doc] edition-guide (book) - [doc] style-guide (book) - [doc] rustc 1 -> releases 2 - [build] rustc 0 -> RustInstaller 1 - [dist] docs - [dist] rustc 1 -> std 1 - [build] rustdoc 2 - [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 - [build] rustc 0 -> GenerateCopyright 1 - [dist] rustc - [build] rustc 1 -> cargo 2 - [dist] rustc 1 -> cargo 2 - [build] rustc 1 -> rust-analyzer 2 - [dist] rustc 1 -> rust-analyzer 2 - [build] rustc 1 -> rustfmt 2 - [build] rustc 1 -> cargo-fmt 2 - [dist] rustc 1 -> rustfmt 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [dist] rustc 1 -> clippy 2 - [build] rustc 1 -> miri 2 - [build] rustc 1 -> cargo-miri 2 - [dist] rustc 1 -> miri 2 + .get_steps() + .render_with(RenderConfig { + normalize_host: false + }), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> WasmComponentLd 1 + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 + [doc] unstable-book (book) + [build] rustc 1 -> std 1 + [doc] book (book) + [doc] book/first-edition (book) + [doc] book/second-edition (book) + [doc] book/2018-edition (book) + [build] rustdoc 1 + [doc] rustc 1 -> standalone 2 + [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> WasmComponentLd 2 + [build] rustc 1 -> error-index 2 + [doc] rustc 1 -> error-index 2 + [doc] nomicon (book) + [doc] rustc 1 -> reference (book) 2 + [doc] rustdoc (book) + [doc] rust-by-example (book) + [build] rustc 0 -> LintDocs 1 + [doc] rustc (book) + [doc] cargo (book) + [doc] clippy (book) + [doc] embedded-book (book) + [doc] edition-guide (book) + [doc] style-guide (book) + [doc] rustc 1 -> releases 2 + [build] rustc 0 -> RustInstaller 1 + [dist] docs + [dist] rustc 1 -> std 1 + [build] rustdoc 2 + [build] rustc 1 -> rust-analyzer-proc-macro-srv 2 + [build] rustc 0 -> GenerateCopyright 1 + [dist] rustc + [build] rustc 1 -> cargo 2 + [dist] rustc 1 -> cargo 2 + [build] rustc 1 -> rust-analyzer 2 + [dist] rustc 1 -> rust-analyzer 2 + [build] rustc 1 -> rustfmt 2 + [build] rustc 1 -> cargo-fmt 2 + [dist] rustc 1 -> rustfmt 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [dist] rustc 1 -> clippy 2 + [build] rustc 1 -> miri 2 + [build] rustc 1 -> cargo-miri 2 + [dist] rustc 1 -> miri 2 [dist] src <> - [build] rustc 1 -> rustc_codegen_cranelift 2 - [dist] rustc 1 -> rustc_codegen_cranelift 2 - [build] rustc 1 -> LlvmBitcodeLinker 2 + [build] rustc 1 -> rustc_codegen_cranelift 2 + [dist] rustc 1 -> rustc_codegen_cranelift 2 + [build] rustc 1 -> LlvmBitcodeLinker 2 "); } From 92859e98ee1a2101df8322a8581e4d638eb15078 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 24 Sep 2025 20:32:50 +0100 Subject: [PATCH 234/537] Repro duration_since regression from issue 146228 --- library/std/src/sys/pal/hermit/time.rs | 11 +++++++++-- library/std/src/sys/pal/unix/time.rs | 27 ++++++++++++-------------- library/std/tests/time.rs | 16 +++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index f76a5f96c875..bd6fd5a3de42 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -26,15 +26,22 @@ impl Timespec { } fn sub_timespec(&self, other: &Timespec) -> Result { + fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { + debug_assert!(a >= b); + a.wrapping_sub(b).cast_unsigned() + } + if self >= other { + // Logic here is identical to Unix version of `Timestamp::sub_timespec`, + // check comments there why operations do not overflow. Ok(if self.t.tv_nsec >= other.t.tv_nsec { Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, + sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec), (self.t.tv_nsec - other.t.tv_nsec) as u32, ) } else { Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, + sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec), (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, ) }) diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index bd7f74fea6a9..c207f41cad4b 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -134,28 +134,25 @@ impl Timespec { } pub fn sub_timespec(&self, other: &Timespec) -> Result { + // When a >= b, the difference fits in u64. + fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { + debug_assert!(a >= b); + a.wrapping_sub(b).cast_unsigned() + } + if self >= other { - // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM - // to optimize it into a branchless form (see also #75545): - // - // 1. `self.tv_sec - other.tv_sec` shows up as a common expression - // in both branches, i.e. the `else` must have its `- 1` - // subtraction after the common one, not interleaved with it - // (it used to be `self.tv_sec - 1 - other.tv_sec`) - // - // 2. the `Duration::new` call (or any other additional complexity) - // is outside of the `if`-`else`, not duplicated in both branches - // - // Ideally this code could be rearranged such that it more - // directly expresses the lower-cost behavior we want from it. let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { ( - (self.tv_sec - other.tv_sec) as u64, + sub_ge_to_unsigned(self.tv_sec, other.tv_sec), self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), ) } else { + // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow. + debug_assert!(self.tv_nsec < other.tv_nsec); + debug_assert!(self.tv_sec > other.tv_sec); + debug_assert!(self.tv_sec > i64::MIN); ( - (self.tv_sec - other.tv_sec - 1) as u64, + sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec), self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), ) }; diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 40709eae37cf..be1948af9156 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -227,3 +227,19 @@ fn big_math() { check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub); check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub); } + +#[test] +#[cfg(unix)] +fn system_time_duration_since_max_range_on_unix() { + // Repro regression https://github.com/rust-lang/rust/issues/146228 + + // Min and max values of `SystemTime` on Unix. + let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); + let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + + let delta_a = max.duration_since(min).expect("duration_since overflow"); + let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); + + assert_eq!(Duration::MAX, delta_a); + assert_eq!(Duration::MAX, delta_b); +} From 43057698c12e8ceab1f49eff8a3e5a38cc05f7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 24 Sep 2025 21:06:54 +0000 Subject: [PATCH 235/537] Tweak handling of "struct like start" where a struct isn't supported This improves the case where someone tries to write a `match` expr where the patterns have type ascription syntax. Makes them less verbose, by giving up on the first encounter in the block, and makes them more accurate by only treating them as a struct literal if successfuly parsed as such. --- .../rustc_parse/src/parser/diagnostics.rs | 40 ++++------ compiler/rustc_parse/src/parser/expr.rs | 61 +++++++++----- .../issues/issue-87086-colon-path-sep.rs | 3 +- .../issues/issue-87086-colon-path-sep.stderr | 20 ++--- tests/ui/parser/type-ascription-in-pattern.rs | 17 ++-- .../parser/type-ascription-in-pattern.stderr | 80 +++++-------------- 6 files changed, 93 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a28af7833c38..a9fbd0fa33d5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2748,28 +2748,7 @@ impl<'a> Parser<'a> { if token::Colon != self.token.kind { return first_pat; } - if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_non_reserved_ident()) - { - let mut snapshot_type = self.create_snapshot_for_diagnostic(); - snapshot_type.bump(); // `:` - match snapshot_type.parse_ty() { - Err(inner_err) => { - inner_err.cancel(); - } - Ok(ty) => { - let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else { - return first_pat; - }; - err.span_label(ty.span, "specifying the type of a pattern isn't supported"); - self.restore_snapshot(snapshot_type); - let span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(span, PatKind::Wild); - err.emit(); - } - } - return first_pat; - } + // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` let colon_span = self.token.span; @@ -2857,7 +2836,13 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } else { - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = self.mk_pat( + new_span, + PatKind::Err( + self.dcx() + .span_delayed_bug(colon_span, "recovered bad path pattern"), + ), + ); } self.restore_snapshot(snapshot_pat); } @@ -2870,7 +2855,14 @@ impl<'a> Parser<'a> { err.span_label(ty.span, "specifying the type of a pattern isn't supported"); self.restore_snapshot(snapshot_type); let new_span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = + self.mk_pat( + new_span, + PatKind::Err(self.dcx().span_delayed_bug( + colon_span, + "recovered bad pattern with type", + )), + ); } } err.emit(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 81a5d48d94e8..2f4158450d83 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3612,36 +3612,55 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1) } - fn is_certainly_not_a_block(&self) -> bool { - // `{ ident, ` and `{ ident: ` cannot start a block. - self.look_ahead(1, |t| t.is_ident()) - && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) - } - fn maybe_parse_struct_expr( &mut self, qself: &Option>, path: &ast::Path, ) -> Option>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if struct_allowed || self.is_certainly_not_a_block() { - if let Err(err) = self.expect(exp!(OpenBrace)) { - return Some(Err(err)); + let is_ident = self.look_ahead(1, |t| t.is_ident()); + let is_comma = self.look_ahead(2, |t| t == &token::Comma); + let is_colon = self.look_ahead(2, |t| t == &token::Colon); + match (struct_allowed, is_ident, is_comma, is_colon) { + (false, true, true, _) | (false, true, _, true) => { + // We have something like `match foo { bar,` or `match foo { bar:`, which means the + // user might have meant to write a struct literal as part of the `match` + // discriminant. + let snapshot = self.create_snapshot_for_diagnostic(); + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + match self.parse_expr_struct(qself.clone(), path.clone(), false) { + Ok(expr) => { + // This is a struct literal, but we don't accept them here. + self.dcx().emit_err(errors::StructLiteralNotAllowedHere { + span: expr.span, + sub: errors::StructLiteralNotAllowedHereSugg { + left: path.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + Some(Ok(expr)) + } + Err(err) => { + // We couldn't parse a valid struct, rollback and let the parser emit an + // error elsewhere. + err.cancel(); + self.restore_snapshot(snapshot); + None + } + } } - let expr = self.parse_expr_struct(qself.clone(), path.clone(), true); - if let (Ok(expr), false) = (&expr, struct_allowed) { - // This is a struct literal, but we don't can't accept them here. - self.dcx().emit_err(errors::StructLiteralNotAllowedHere { - span: expr.span, - sub: errors::StructLiteralNotAllowedHereSugg { - left: path.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); + (true, _, _, _) => { + // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for + // any kind of recovery. + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + Some(self.parse_expr_struct(qself.clone(), path.clone(), true)) } - return Some(expr); + (false, _, _, _) => None, } - None } pub(super) fn parse_struct_fields( diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs index d081c06044f1..e1ea38f2795d 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -37,10 +37,9 @@ fn g1() { //~| HELP: maybe write a path separator here _ => {} } - if let Foo:Bar = f() { //~ WARN: irrefutable `if let` pattern + if let Foo:Bar = f() { //~^ ERROR: expected one of //~| HELP: maybe write a path separator here - //~| HELP: consider replacing the `if let` with a `let` } } diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr index a9bad96f9af7..061586882e0c 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -64,7 +64,7 @@ LL | if let Foo::Bar = f() { | + error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:49:16 + --> $DIR/issue-87086-colon-path-sep.rs:48:16 | LL | ref qux: Foo::Baz => {} | ^ -------- specifying the type of a pattern isn't supported @@ -77,7 +77,7 @@ LL | ref qux::Foo::Baz => {} | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:58:16 + --> $DIR/issue-87086-colon-path-sep.rs:57:16 | LL | mut qux: Foo::Baz => {} | ^ -------- specifying the type of a pattern isn't supported @@ -90,7 +90,7 @@ LL | mut qux::Foo::Baz => {} | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:69:12 + --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} | ^-------- specifying the type of a pattern isn't supported @@ -103,7 +103,7 @@ LL | Foo::Bar::Baz => {} | + error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:75:12 + --> $DIR/issue-87086-colon-path-sep.rs:74:12 | LL | Foo:Bar => {} | ^--- specifying the type of a pattern isn't supported @@ -115,15 +115,5 @@ help: maybe write a path separator here LL | Foo::Bar => {} | + -warning: irrefutable `if let` pattern - --> $DIR/issue-87086-colon-path-sep.rs:40:8 - | -LL | if let Foo:Bar = f() { - | ^^^^^^^^^^^^^^^^^ - | - = note: this pattern will always match, so the `if let` is useless - = help: consider replacing the `if let` with a `let` - = note: `#[warn(irrefutable_let_patterns)]` on by default - -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 9 previous errors diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs index 18d7061d69c8..75059d33db64 100644 --- a/tests/ui/parser/type-ascription-in-pattern.rs +++ b/tests/ui/parser/type-ascription-in-pattern.rs @@ -1,15 +1,16 @@ fn foo(x: bool) -> i32 { - match x { //~ ERROR struct literals are not allowed here - x: i32 => x, //~ ERROR expected - true => 42., //~ ERROR expected identifier - false => 0.333, //~ ERROR expected identifier + match x { + x: i32 => x, //~ ERROR: expected + //~^ ERROR: mismatched types + true => 42., + false => 0.333, } -} //~ ERROR expected one of +} fn main() { match foo(true) { - 42: i32 => (), //~ ERROR expected - _: f64 => (), //~ ERROR expected - x: i32 => (), //~ ERROR expected + 42: i32 => (), //~ ERROR: expected + _: f64 => (), //~ ERROR: expected + x: i32 => (), //~ ERROR: expected } } diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr index 135879f208b2..091907549936 100644 --- a/tests/ui/parser/type-ascription-in-pattern.stderr +++ b/tests/ui/parser/type-ascription-in-pattern.stderr @@ -1,64 +1,18 @@ -error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>` - --> $DIR/type-ascription-in-pattern.rs:3:16 +error: expected one of `@` or `|`, found `:` + --> $DIR/type-ascription-in-pattern.rs:3:10 | -LL | match x { - | - while parsing this struct LL | x: i32 => x, - | -^^ expected one of 8 possible tokens - | | - | help: try adding a comma: `,` - -error: expected identifier, found keyword `true` - --> $DIR/type-ascription-in-pattern.rs:4:9 + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` | -LL | match x { - | - while parsing this struct -LL | x: i32 => x, -LL | true => 42., - | ^^^^ expected identifier, found keyword - -error: expected identifier, found keyword `false` - --> $DIR/type-ascription-in-pattern.rs:5:9 +help: maybe write a path separator here | -LL | match x { - | - while parsing this struct -... -LL | false => 0.333, - | ^^^^^ expected identifier, found keyword - -error: struct literals are not allowed here - --> $DIR/type-ascription-in-pattern.rs:2:11 - | -LL | match x { - | ___________^ -LL | | x: i32 => x, -LL | | true => 42., -LL | | false => 0.333, -LL | | } - | |_____^ - | -help: surround the struct literal with parentheses - | -LL ~ match (x { -LL | x: i32 => x, -LL | true => 42., -LL | false => 0.333, -LL ~ }) - | - -error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/type-ascription-in-pattern.rs:7:1 - | -LL | match x { - | ----- while parsing this `match` expression -... -LL | } - | - expected one of `.`, `?`, `{`, or an operator -LL | } - | ^ unexpected token +LL | x::i32 => x, + | ~~ error: expected one of `...`, `..=`, `..`, or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:11:11 + --> $DIR/type-ascription-in-pattern.rs:12:11 | LL | 42: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -66,7 +20,7 @@ LL | 42: i32 => (), | expected one of `...`, `..=`, `..`, or `|` error: expected `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:12:10 + --> $DIR/type-ascription-in-pattern.rs:13:10 | LL | _: f64 => (), | ^ --- specifying the type of a pattern isn't supported @@ -74,7 +28,7 @@ LL | _: f64 => (), | expected `|` error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:13:10 + --> $DIR/type-ascription-in-pattern.rs:14:10 | LL | x: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -86,5 +40,15 @@ help: maybe write a path separator here LL | x::i32 => (), | ~~ -error: aborting due to 8 previous errors +error[E0308]: mismatched types + --> $DIR/type-ascription-in-pattern.rs:3:19 + | +LL | fn foo(x: bool) -> i32 { + | --- expected `i32` because of return type +LL | match x { +LL | x: i32 => x, + | ^ expected `i32`, found `bool` +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. From aa75d340353dd07bf347978360a9566831128e35 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 24 Sep 2025 23:47:05 +0200 Subject: [PATCH 236/537] Small string formatting cleanup --- compiler/rustc_interface/src/util.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 26e09c95e769..76ccd12797e5 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -386,8 +386,8 @@ fn get_codegen_sysroot( .collect::>() .join("\n* "); let err = format!( - "failed to find a `codegen-backends` folder \ - in the sysroot candidates:\n* {candidates}" + "failed to find a `codegen-backends` folder in the sysroot candidates:\n\ + * {candidates}" ); early_dcx.early_fatal(err); }); @@ -396,10 +396,8 @@ fn get_codegen_sysroot( let d = sysroot.read_dir().unwrap_or_else(|e| { let err = format!( - "failed to load default codegen backend, couldn't \ - read `{}`: {}", + "failed to load default codegen backend, couldn't read `{}`: {e}", sysroot.display(), - e ); early_dcx.early_fatal(err); }); From 852da23a2d06de5a7821b1fdb356fe3a410b2d00 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Wed, 24 Sep 2025 15:56:38 -0700 Subject: [PATCH 237/537] Explicitly note `&[SocketAddr]` impl of `ToSocketAddrs`. Although the examples below this list do imply that there's an impl of `ToSocketAddrs` for `&[SocketAddr]`, it's not actually noted in the list of default implementations. --- library/std/src/net/socket_addr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index 5b56dd3f7447..8214ad381f1f 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -28,6 +28,8 @@ use crate::{io, iter, option, slice, vec}; /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `:` pair where `` is a [`u16`] value. /// +/// * &[[SocketAddr]]: all [`SocketAddr`] values in the slice will be used. +/// /// This trait allows constructing network objects like [`TcpStream`] or /// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than From 16460273e0b980b8b34213eac9426066777a520b Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Wed, 24 Sep 2025 18:47:36 -0500 Subject: [PATCH 238/537] fix SCIP panicking due to salsa not attaching --- src/tools/rust-analyzer/crates/ide/src/static_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 8214b4d1de22..9911b85799b6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -278,7 +278,7 @@ impl StaticIndex<'_> { for token in tokens { let range = token.text_range(); let node = token.parent().unwrap(); - match get_definitions(&sema, token.clone()) { + match salsa::attach(self.db, || get_definitions(&sema, token.clone())) { Some(it) => { for i in it { add_token(i, range, &node); From fe440ec934995e499360dc05ae485f1ccbd0e694 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 24 Sep 2025 16:53:17 -0700 Subject: [PATCH 239/537] llvm: add a destructor to call releaseSerializer --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index ef85ce153b88..9953f5e17316 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1685,6 +1685,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( RemarkStreamer(std::move(RemarkStreamer)), LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {} +#if LLVM_VERSION_GE(22, 0) + ~RustDiagnosticHandler() { + if (RemarkStreamer) { + RemarkStreamer->releaseSerializer(); + } + } +#endif + virtual bool handleDiagnostics(const DiagnosticInfo &DI) override { // If this diagnostic is one of the optimization remark kinds, we can // check if it's enabled before emitting it. This can avoid many From 137d4eaf12139af894da6c0b6fe74195d6b7b98c Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Sat, 20 Sep 2025 16:54:51 -0700 Subject: [PATCH 240/537] BTreeMap: Don't leak allocators when initializing nodes Memory was allocated via `Box::leak` and thence intended to be tracked and deallocated manually, but the allocator was also leaked, not tracked, and never dropped. Now it is dropped immediately. According to my reading of the `Allocator` trait, if a copy of the allocator remains live, then its allocations must remain live. Since the B-tree has a copy of the allocator that will only be dropped after the nodes, it's safe to not store the allocator in each node (which would be a much more intrusive change). --- library/alloc/src/collections/btree/map.rs | 3 +++ library/alloc/src/collections/btree/node.rs | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index cebd25c6039c..e3b53b2fe291 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -194,6 +194,9 @@ pub struct BTreeMap< root: Option>, length: usize, /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes). + // Although some of the accessory types store a copy of the allocator, the nodes do not. + // Because allocations will remain live as long as any copy (like this one) of the allocator + // is live, it's unnecessary to store the allocator in each node. pub(super) alloc: ManuallyDrop, // For dropck; the `Box` avoids making the `Unpin` impl more strict than before _marker: PhantomData>, diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index b233e1740b7b..77bd90f2c750 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -224,7 +224,11 @@ impl NodeRef { } fn from_new_leaf(leaf: Box, A>) -> Self { - NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData } + // The allocator must be dropped, not leaked. See also `BTreeMap::alloc`. + let (leaf, _alloc) = Box::into_raw_with_allocator(leaf); + // SAFETY: the node was just allocated. + let node = unsafe { NonNull::new_unchecked(leaf) }; + NodeRef { height: 0, node, _marker: PhantomData } } } @@ -242,7 +246,11 @@ impl NodeRef { height: usize, ) -> Self { debug_assert!(height > 0); - let node = NonNull::from(Box::leak(internal)).cast(); + // The allocator must be dropped, not leaked. See also `BTreeMap::alloc`. + let (internal, _alloc) = Box::into_raw_with_allocator(internal); + // SAFETY: the node was just allocated. + let internal = unsafe { NonNull::new_unchecked(internal) }; + let node = internal.cast(); let mut this = NodeRef { height, node, _marker: PhantomData }; this.borrow_mut().correct_all_childrens_parent_links(); this From 3280c210dd6e5f26595ff4857572f8feba678992 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 25 Sep 2025 04:11:22 +0000 Subject: [PATCH 241/537] Prepare for merging from rust-lang/rust This updates the rust-version file to caccb4d0368bd918ef6668af8e13834d07040417. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 02b217f7d80d..8854fb95997b 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -21a19c297d4f5a03501d92ca251bd7a17073c08a +caccb4d0368bd918ef6668af8e13834d07040417 From bc37dd4a724fc3e3043a46f488775dbe1bfd9649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 24 Sep 2025 15:48:34 +0200 Subject: [PATCH 242/537] Remove an erroneous normalization step in `tests/run-make/linker-warning` --- tests/run-make/linker-warning/rmake.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index 9ea706af5035..b0c40dd171d3 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -61,7 +61,6 @@ fn main() { diff() .expected_file("short-error.txt") .actual_text("(linker error)", out.stderr()) - .normalize(r#"/rustc[^/_-]*/"#, "/rustc/") .normalize("libpanic_abort", "libpanic_unwind") .normalize( regex::escape( From 61792afab930c9726e11bf838999bfa1e5f6caad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 25 Sep 2025 10:19:23 +0300 Subject: [PATCH 243/537] Also install rustfmt on stable --- src/tools/rust-analyzer/.github/workflows/ci.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 770652494f4a..e87ece5b6524 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -98,9 +98,9 @@ jobs: run: | rustup update --no-self-update stable rustup default stable - rustup component add --toolchain stable rust-src clippy - # We always use a nightly rustfmt, regardless of channel, because we need - # --file-lines. + rustup component add --toolchain stable rust-src clippy rustfmt + # We also install a nightly rustfmt, because we use `--file-lines` in + # a test. rustup toolchain install nightly --profile minimal --component rustfmt # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json - name: Install Rust Problem Matcher From 932f3a8ecd0158fcb70a54c8591dec70e43b53d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 25 Sep 2025 09:29:10 +0200 Subject: [PATCH 244/537] rustdoc: Fix documentation for `--doctest-build-arg` --- src/doc/rustdoc/src/unstable-features.md | 26 +++++------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 25c929a1dbad..4327a80cd083 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -739,7 +739,7 @@ This flag can be passed multiple times to nest wrappers. ## Passing arguments to rustc when compiling doctests -You can use the `--doctest-compilation-args` flag if you want to add options when compiling the +You can use the `--doctest-build-arg` flag if you want to add options when compiling the doctest. For example if you have: ```rust,no_run @@ -784,10 +784,10 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s ``` -But if you can limit the lint level to warning by using `--doctest_compilation_args=--cap-lints=warn`: +But if you can limit the lint level to warning by using `--doctest-build-arg=--cap-lints=warn`: ```console -$ rustdoc --test --doctest_compilation_args=--cap-lints=warn file.rs +$ rustdoc --test --doctest-build-arg=--cap-lints=warn file.rs running 1 test test tests/rustdoc-ui/doctest/rustflags.rs - Bar (line 5) ... ok @@ -795,24 +795,8 @@ test tests/rustdoc-ui/doctest/rustflags.rs - Bar (line 5) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s ``` -The parsing of arguments works as follows: if it encounters a `"` or a `'`, it will continue -until it finds the character unescaped (without a prepending `\`). If not inside a string, a -whitespace character will also split arguments. Example: - -```text -"hello 'a'\" ok" how are 'you today?' -``` - -will be split as follows: - -```text -[ - "hello 'a'\" ok", - "how", - "are", - "you today?", -] -``` +In order to pass multiple arguments to the underlying compiler, +pass `--doctest-build-arg ARG` for each argument `ARG`. ## `--generate-macro-expansion`: Generate macros expansion toggles in source code From 13d512f2d57a4ad1b97cb0f543b3d85c4cbd1962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 25 Sep 2025 10:54:58 +0300 Subject: [PATCH 245/537] Install cargo for proc-macro-srv tests --- src/tools/rust-analyzer/.github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index e87ece5b6524..0eb57a605f82 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -56,8 +56,8 @@ jobs: # Install a pinned rustc commit to avoid surprises - name: Install Rust toolchain run: | - RUSTC_VERSION=`cat rust-version` - rustup-toolchain-install-master ${RUSTC_VERSION} -c rust-src -c rustfmt + RUSTC_VERSION=$(cat rust-version) + rustup-toolchain-install-master ${RUSTC_VERSION} -c cargo -c rust-src -c rustfmt rustup default ${RUSTC_VERSION} # Emulate a nightly toolchain, because the toolchain installed above does not have "nightly" From d226e7aa93425ba2090f423642341a99ab047838 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 19 Sep 2025 14:53:16 +0200 Subject: [PATCH 246/537] Use standard attribute logic for allocator shim Use llfn_attrs_from_instance() to generate the attributes for the allocator shim. This ensures that we generate all the usual attributes (and don't get to find out one-by-one that a certain attribute is important for a certain target). Additionally this will enable emitting the allocator-specific attributes (not included here). This change is quite awkward because the allocator shim uses SimpleCx, while llfn_attrs_from_instance uses CodegenCx. I've switched it to use SimpleCx plus tcx/sess arguments where necessary. If there's a simpler way to do this, I'd love to know about it... --- compiler/rustc_codegen_llvm/src/abi.rs | 8 +- compiler/rustc_codegen_llvm/src/allocator.rs | 25 +-- compiler/rustc_codegen_llvm/src/attributes.rs | 191 ++++++++++-------- compiler/rustc_codegen_llvm/src/base.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/context.rs | 10 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- 7 files changed, 126 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 11be70411679..861227f7c2a7 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -538,7 +538,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // If the declaration has an associated instance, compute extra attributes based on that. if let Some(instance) = instance { - llfn_attrs_from_instance(cx, llfn, instance); + llfn_attrs_from_instance( + cx, + cx.tcx, + llfn, + &cx.tcx.codegen_instance_attrs(instance.def), + Some(instance), + ); } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index df3e49279d97..abd631203973 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -5,15 +5,16 @@ use rustc_ast::expand::allocator::{ }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; use rustc_symbol_mangling::mangle_internal_symbol; -use smallvec::SmallVec; +use crate::attributes::llfn_attrs_from_instance; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; use crate::llvm::{self, FALSE, TRUE, Type, Value}; -use crate::{SimpleCx, attributes, debuginfo, llvm_util}; +use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, @@ -149,18 +150,8 @@ fn create_wrapper_function( ty, ); - let mut attrs = SmallVec::<[_; 2]>::new(); - - let target_cpu = llvm_util::target_cpu(tcx.sess); - let target_cpu_attr = llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu); - - let tune_cpu_attr = llvm_util::tune_cpu(tcx.sess) - .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu)); - - attrs.push(target_cpu_attr); - attrs.extend(tune_cpu_attr); - - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs); + let attrs = CodegenFnAttrs::new(); + llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None); let no_return = if no_return { // -> ! DIFlagNoReturn @@ -171,12 +162,6 @@ fn create_wrapper_function( None }; - if tcx.sess.must_emit_unwind_tables() { - let uwtable = - attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); - } - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; let mut bx = SBuilder::build(&cx, llbb); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index dcf6b9454978..8070ea0b3e92 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,20 +1,21 @@ //! Set and unset common attributes on LLVM values. -use rustc_codegen_ssa::traits::*; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_hir::def_id::DefId; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; +use rustc_middle::middle::codegen_fn_attrs::{ + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, +}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; -use crate::context::CodegenCx; +use crate::context::SimpleCx; use crate::errors::SanitizerMemtagRequiresMte; use crate::llvm::AttributePlace::Function; use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects}; use crate::value::Value; -use crate::{attributes, llvm_util}; +use crate::{Session, attributes, llvm_util}; pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) { if !attrs.is_empty() { @@ -30,18 +31,19 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[ /// Get LLVM attribute for the provided inline heuristic. pub(crate) fn inline_attr<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>, ) -> Option<&'ll Attribute> { // `optnone` requires `noinline` - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) { (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never, - (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint, + (InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint, (inline, _) => inline, }; - if !cx.tcx.sess.opts.unstable_opts.inline_llvm { + if !tcx.sess.opts.unstable_opts.inline_llvm { // disable LLVM inlining return Some(AttributeKind::NoInline.create_attr(cx.llcx)); } @@ -51,7 +53,7 @@ pub(crate) fn inline_attr<'ll, 'tcx>( Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)) } InlineAttr::Never => { - if cx.sess().target.arch != "amdgpu" { + if tcx.sess.target.arch != "amdgpu" { Some(AttributeKind::NoInline.create_attr(cx.llcx)) } else { None @@ -63,12 +65,13 @@ pub(crate) fn inline_attr<'ll, 'tcx>( #[inline] fn patchable_function_entry_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, + cx: &SimpleCx<'ll>, + sess: &Session, attr: Option, ) -> SmallVec<[&'ll Attribute; 2]> { let mut attrs = SmallVec::new(); let patchable_spec = attr.unwrap_or_else(|| { - PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry) + PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry) }); let entry = patchable_spec.entry(); let prefix = patchable_spec.prefix(); @@ -91,12 +94,13 @@ fn patchable_function_entry_attrs<'ll>( /// Get LLVM sanitize attributes. #[inline] -pub(crate) fn sanitize_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, +pub(crate) fn sanitize_attrs<'ll, 'tcx>( + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, no_sanitize: SanitizerSet, ) -> SmallVec<[&'ll Attribute; 4]> { let mut attrs = SmallVec::new(); - let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize; + let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize; if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) { attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx)); } @@ -114,11 +118,11 @@ pub(crate) fn sanitize_attrs<'ll>( } if enabled.contains(SanitizerSet::MEMTAG) { // Check to make sure the mte target feature is actually enabled. - let features = cx.tcx.global_backend_features(()); + let features = tcx.global_backend_features(()); let mte_feature = features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..])); if let None | Some("-mte") = mte_feature { - cx.tcx.dcx().emit_err(SanitizerMemtagRequiresMte); + tcx.dcx().emit_err(SanitizerMemtagRequiresMte); } attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx)); @@ -139,9 +143,12 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option) llvm::CreateUWTableAttr(llcx, async_unwind) } -pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let mut fp = cx.sess().target.frame_pointer; - let opts = &cx.sess().opts; +pub(crate) fn frame_pointer_type_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> Option<&'ll Attribute> { + let mut fp = sess.target.frame_pointer; + let opts = &sess.opts; // "mcount" function relies on stack pointer. // See . if opts.unstable_opts.instrument_mcount { @@ -156,8 +163,8 @@ pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&' Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value)) } -fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let function_return_attr = match cx.sess().opts.unstable_opts.function_return { +fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + let function_return_attr = match sess.opts.unstable_opts.function_return { FunctionReturn::Keep => return None, FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern, }; @@ -167,17 +174,20 @@ fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> /// Tell LLVM what instrument function to insert. #[inline] -fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { +fn instrument_function_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> SmallVec<[&'ll Attribute; 4]> { let mut attrs = SmallVec::new(); - if cx.sess().opts.unstable_opts.instrument_mcount { + if sess.opts.unstable_opts.instrument_mcount { // Similar to `clang -pg` behavior. Handled by the // `post-inline-ee-instrument` LLVM pass. // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. - let mcount_name = match &cx.sess().target.llvm_mcount_intrinsic { + let mcount_name = match &sess.target.llvm_mcount_intrinsic { Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(), - None => cx.sess().target.mcount.as_ref(), + None => sess.target.mcount.as_ref(), }; attrs.push(llvm::CreateAttrStringValue( @@ -186,7 +196,7 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr mcount_name, )); } - if let Some(options) = &cx.sess().opts.unstable_opts.instrument_xray { + if let Some(options) = &sess.opts.unstable_opts.instrument_xray { // XRay instrumentation is similar to __cyg_profile_func_{enter,exit}. // Function prologue and epilogue are instrumented with NOP sleds, // a runtime library later replaces them with detours into tracing code. @@ -217,20 +227,20 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr attrs } -fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - if !cx.sess().opts.unstable_opts.no_jump_tables { +fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + if !sess.opts.unstable_opts.no_jump_tables { return None; } Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true")) } -fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { +fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> { // Currently stack probes seem somewhat incompatible with the address // sanitizer and thread sanitizer. With asan we're already protected from // stack overflow anyway so we don't really need stack probes regardless. - if cx - .sess() + if tcx + .sess .opts .unstable_opts .sanitizer @@ -240,22 +250,22 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { } // probestack doesn't play nice either with `-C profile-generate`. - if cx.sess().opts.cg.profile_generate.enabled() { + if tcx.sess.opts.cg.profile_generate.enabled() { return None; } - let attr_value = match cx.sess().target.stack_probes { + let attr_value = match tcx.sess.target.stack_probes { StackProbeType::None => return None, // Request LLVM to generate the probes inline. If the given LLVM version does not support // this, no probe is generated at all (even if the attribute is specified). StackProbeType::Inline => "inline-asm", // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. - StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"), + StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"), // Pick from the two above based on the LLVM version. StackProbeType::InlineOrCall { min_llvm_version_for_inline } => { if llvm_util::get_version() < min_llvm_version_for_inline { - &mangle_internal_symbol(cx.tcx, "__rust_probestack") + &mangle_internal_symbol(tcx, "__rust_probestack") } else { "inline-asm" } @@ -264,8 +274,8 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value)) } -fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let sspattr = match cx.sess().stack_protector() { +fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + let sspattr = match sess.stack_protector() { StackProtector::None => return None, StackProtector::All => AttributeKind::StackProtectReq, StackProtector::Strong => AttributeKind::StackProtectStrong, @@ -275,33 +285,34 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { Some(sspattr.create_attr(cx.llcx)) } -fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - if cx.sess().target.arch != "s390x" { +fn backchain_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + if sess.target.arch != "s390x" { return None; } - let requested_features = cx.sess().opts.cg.target_feature.split(','); + let requested_features = sess.opts.cg.target_feature.split(','); let found_positive = requested_features.clone().any(|r| r == "+backchain"); if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None } } -pub(crate) fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute { - let target_cpu = llvm_util::target_cpu(cx.tcx.sess); +pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute { + let target_cpu = llvm_util::target_cpu(sess); llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu) } -pub(crate) fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - llvm_util::tune_cpu(cx.tcx.sess) +pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + llvm_util::tune_cpu(sess) .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu)) } /// Get the `target-features` LLVM attribute. -pub(crate) fn target_features_attr<'ll>( - cx: &CodegenCx<'ll, '_>, +pub(crate) fn target_features_attr<'ll, 'tcx>( + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, function_features: Vec, ) -> Option<&'ll Attribute> { - let global_features = cx.tcx.global_backend_features(()).iter().map(String::as_str); + let global_features = tcx.global_backend_features(()).iter().map(String::as_str); let function_features = function_features.iter().map(String::as_str); let target_features = global_features.chain(function_features).intersperse(",").collect::(); @@ -311,22 +322,22 @@ pub(crate) fn target_features_attr<'ll>( /// Get the `NonLazyBind` LLVM attribute, /// if the codegen options allow skipping the PLT. -pub(crate) fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { +pub(crate) fn non_lazy_bind_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> Option<&'ll Attribute> { // Don't generate calls through PLT if it's not necessary - if !cx.sess().needs_plt() { - Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) - } else { - None - } + if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None } } /// Get the default optimizations attrs for a function. #[inline] pub(crate) fn default_optimisation_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, + cx: &SimpleCx<'ll>, + sess: &Session, ) -> SmallVec<[&'ll Attribute; 2]> { let mut attrs = SmallVec::new(); - match cx.sess().opts.optimize { + match sess.opts.optimize { OptLevel::Size => { attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx)); } @@ -347,17 +358,18 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute { /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, llfn: &'ll Value, - instance: ty::Instance<'tcx>, + codegen_fn_attrs: &CodegenFnAttrs, + instance: Option>, ) { - let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); - + let sess = tcx.sess; let mut to_add = SmallVec::<[_; 16]>::new(); match codegen_fn_attrs.optimize { OptimizeAttr::Default => { - to_add.extend(default_optimisation_attrs(cx)); + to_add.extend(default_optimisation_attrs(cx, sess)); } OptimizeAttr::DoNotOptimize => { to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx)); @@ -369,21 +381,21 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( OptimizeAttr::Speed => {} } - if cx.sess().must_emit_unwind_tables() { - to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); + if sess.must_emit_unwind_tables() { + to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind)); } - if cx.sess().opts.unstable_opts.profile_sample_use.is_some() { + if sess.opts.unstable_opts.profile_sample_use.is_some() { to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } // FIXME: none of these functions interact with source level attributes. - to_add.extend(frame_pointer_type_attr(cx)); - to_add.extend(function_return_attr(cx)); - to_add.extend(instrument_function_attr(cx)); - to_add.extend(nojumptables_attr(cx)); - to_add.extend(probestack_attr(cx)); - to_add.extend(stackprotector_attr(cx)); + to_add.extend(frame_pointer_type_attr(cx, sess)); + to_add.extend(function_return_attr(cx, sess)); + to_add.extend(instrument_function_attr(cx, sess)); + to_add.extend(nojumptables_attr(cx, sess)); + to_add.extend(probestack_attr(cx, tcx)); + to_add.extend(stackprotector_attr(cx, sess)); if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) { to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins")); @@ -404,13 +416,13 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // not used. } else { // Do not set sanitizer attributes for naked functions. - to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.no_sanitize)); // For non-naked functions, set branch protection attributes on aarch64. if let Some(BranchProtection { bti, pac_ret, gcs }) = - cx.sess().opts.unstable_opts.branch_protection + sess.opts.unstable_opts.branch_protection { - assert!(cx.sess().target.arch == "aarch64"); + assert!(sess.target.arch == "aarch64"); if bti { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); } @@ -438,14 +450,15 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED) { to_add.push(create_alloc_family_attr(cx.llcx)); - if let Some(zv) = - cx.tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant) + if let Some(instance) = instance + && let Some(zv) = + tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant) && let Some(name) = zv.value_str() { to_add.push(llvm::CreateAttrStringValue( cx.llcx, "alloc-variant-zeroed", - &mangle_internal_symbol(cx.tcx, name.as_str()), + &mangle_internal_symbol(tcx, name.as_str()), )); } // apply to argument place instead of function @@ -490,18 +503,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } - if let Some(backchain) = backchain_attr(cx) { + if let Some(backchain) = backchain_attr(cx, sess) { to_add.push(backchain); } - to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); + to_add.extend(patchable_function_entry_attrs( + cx, + sess, + codegen_fn_attrs.patchable_function_entry, + )); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated // functions (because Clang annotates functions this way too). - to_add.push(target_cpu_attr(cx)); + to_add.push(target_cpu_attr(cx, sess)); // tune-cpu is only conveyed through the attribute for our purpose. // The target doesn't care; the subtarget reads our attribute. - to_add.extend(tune_cpu_attr(cx)); + to_add.extend(tune_cpu_attr(cx, sess)); let function_features = codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::>(); @@ -509,7 +526,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // Apply function attributes as per usual if there are no user defined // target features otherwise this will get applied at the callsite. if function_features.is_empty() { - if let Some(inline_attr) = inline_attr(cx, instance) { + if let Some(instance) = instance + && let Some(inline_attr) = inline_attr(cx, tcx, instance) + { to_add.push(inline_attr); } } @@ -517,7 +536,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = function_features .iter() // Convert to LLVMFeatures and filter out unavailable ones - .flat_map(|feat| llvm_util::to_llvm_features(cx.tcx.sess, feat)) + .flat_map(|feat| llvm_util::to_llvm_features(sess, feat)) // Convert LLVMFeatures & dependencies to +s .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}"))) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { @@ -526,20 +545,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( })) .collect::>(); - if cx.tcx.sess.target.is_like_wasm { + if sess.target.is_like_wasm { // If this function is an import from the environment but the wasm // import has a specific module/name, apply them here. - if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { + if let Some(instance) = instance + && let Some(module) = wasm_import_module(tcx, instance.def_id()) + { to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module)); let name = - codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id())); + codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id())); let name = name.as_str(); to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name)); } } - to_add.extend(target_features_attr(cx, function_features)); + to_add.extend(target_features_attr(cx, tcx, function_features)); attributes::apply_to_llfn(llfn, Function, &to_add); } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 978134cc32b1..6d12b511e9c8 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -105,7 +105,7 @@ pub(crate) fn compile_codegen_unit( if let Some(entry) = maybe_create_entry_wrapper::>(&cx, cx.codegen_unit) { - let attrs = attributes::sanitize_attrs(&cx, SanitizerSet::empty()); + let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerSet::empty()); attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0f17cc9063a8..a4dc4eb532f9 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1433,7 +1433,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // If there is an inline attribute and a target feature that matches // we will add the attribute to the callsite otherwise we'll omit // this and not add the attribute to prevent soundness issues. - && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance) + && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance) && self.cx.tcx.is_target_feature_call_safe( &fn_call_attrs.target_features, &fn_defn_attrs.target_features, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 057f525c76f0..2478042a2e62 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -876,7 +876,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { let fty = self.type_variadic_func(&[], self.type_i32()); let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty); - let target_cpu = attributes::target_cpu_attr(self); + let target_cpu = attributes::target_cpu_attr(self, self.sess()); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[target_cpu]); llfn } @@ -891,15 +891,15 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_frame_pointer_type(&self, llfn: &'ll Value) { - if let Some(attr) = attributes::frame_pointer_type_attr(self) { + if let Some(attr) = attributes::frame_pointer_type_attr(self, self.sess()) { attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[attr]); } } fn apply_target_cpu_attr(&self, llfn: &'ll Value) { let mut attrs = SmallVec::<[_; 2]>::new(); - attrs.push(attributes::target_cpu_attr(self)); - attrs.extend(attributes::tune_cpu_attr(self)); + attrs.push(attributes::target_cpu_attr(self, self.sess())); + attrs.extend(attributes::tune_cpu_attr(self, self.sess())); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs); } @@ -918,7 +918,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { attributes::apply_to_llfn( llfn, llvm::AttributePlace::Function, - attributes::target_features_attr(self, vec![]).as_slice(), + attributes::target_features_attr(self, self.tcx, vec![]).as_slice(), ); Some(llfn) } else { diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 960a895a2031..36cdb4988395 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -76,7 +76,7 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>( attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx)); } - attrs.extend(attributes::non_lazy_bind_attr(cx)); + attrs.extend(attributes::non_lazy_bind_attr(cx, cx.tcx.sess)); attributes::apply_to_llfn(llfn, Function, &attrs); From 85018f09f67bd54868fe12a4632bbd637a474853 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 25 Sep 2025 18:10:55 +1000 Subject: [PATCH 247/537] Use `LLVMDisposeTargetMachine` --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 4 +--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 ++- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index d5228f0e0dee..903a882916ee 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -95,8 +95,6 @@ impl Drop for OwnedTargetMachine { // SAFETY: constructing ensures we have a valid pointer created by // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no // double free or use after free. - unsafe { - llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr()); - } + unsafe { llvm::LLVMDisposeTargetMachine(self.tm_unique) }; } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index fd972f371df4..38a6a3119543 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1053,6 +1053,8 @@ unsafe extern "C" { SLen: c_uint, ) -> MetadataKindId; + pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull); + // Create modules. pub(crate) fn LLVMModuleCreateWithNameInContext( ModuleID: *const c_char, @@ -2499,7 +2501,6 @@ unsafe extern "C" { UseWasmEH: bool, ) -> *mut TargetMachine; - pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); pub(crate) fn LLVMRustAddLibraryInfo<'a>( PM: &PassManager<'a>, M: &'a Module, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7518b40799bc..013d68fa3e48 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -359,10 +359,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return wrap(TM); } -extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { - delete unwrap(TM); -} - // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, From 88e797784e21ecad4dc768109ede33c76293482e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 14 Sep 2025 01:12:34 +0200 Subject: [PATCH 248/537] rustdoc: Slightly clean up attr rendering --- src/librustdoc/html/render/mod.rs | 149 ++++++++--------------- src/librustdoc/html/render/print_item.rs | 8 +- 2 files changed, 58 insertions(+), 99 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index cc2744e48c8f..4b7822cd3a9f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -53,6 +53,7 @@ use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince}; use rustc_middle::ty::print::PrintTraitRefExt; @@ -2924,99 +2925,56 @@ fn render_call_locations( w.write_str("") } -struct CodeAttribute(String); - -fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) { - write!( - w, - "
{prefix}{attr}
", - prefix = prefix, - attr = code_attr.0 - ) - .unwrap(); -} - -// When an attribute is rendered inside a tag, it is formatted using -// a div to produce a newline after it. fn render_attributes_in_code( w: &mut impl fmt::Write, item: &clean::Item, prefix: &str, cx: &Context<'_>, ) { - for attr in attributes(item, cx.tcx(), cx.cache()) { - render_code_attribute(prefix, CodeAttribute(attr), w); + for attr in &item.attrs.other_attrs { + let hir::Attribute::Parsed(kind) = attr else { continue }; + let attr = match kind { + AttributeKind::LinkSection { name, .. } => { + Cow::Owned(format!("#[unsafe(link_section = \"{name}\")]")) + } + AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"), + AttributeKind::ExportName { name, .. } => { + Cow::Owned(format!("#[unsafe(export_name = \"{name}\")]")) + } + AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"), + _ => continue, + }; + render_code_attribute(prefix, attr.as_ref(), w); + } + + if let Some(def_id) = item.def_id() + && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) + { + render_code_attribute(prefix, &repr, w); } } -/// used for type aliases to only render their `repr` attribute. -fn render_repr_attributes_in_code( - w: &mut impl fmt::Write, - cx: &Context<'_>, - def_id: DefId, - item_type: ItemType, -) { - if let Some(repr) = repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { - render_code_attribute("", CodeAttribute(repr), w); +fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) { + if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) { + render_code_attribute("", &repr, w); } } -/// Get a list of attributes excluding `#[repr]` to display. -fn attributes_without_repr(item: &clean::Item) -> Vec { - item.attrs - .other_attrs - .iter() - .filter_map(|attr| match attr { - hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { - Some(format!("#[unsafe(link_section = \"{name}\")]")) - } - hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { - Some("#[unsafe(no_mangle)]".to_string()) - } - hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { - Some(format!("#[unsafe(export_name = \"{name}\")]")) - } - hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { - Some("#[non_exhaustive]".to_string()) - } - _ => None, - }) - .collect() +fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) { + write!(w, "
{prefix}{attr}
").unwrap(); } -/// Get a list of attributes to display on this item. -fn attributes(item: &clean::Item, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { - let mut attrs = attributes_without_repr(item); - - if let Some(repr_attr) = repr(item, tcx, cache) { - attrs.push(repr_attr); - } - attrs -} - -/// Returns a stringified `#[repr(...)]` attribute. -fn repr(item: &clean::Item, tcx: TyCtxt<'_>, cache: &Cache) -> Option { - repr_attributes(tcx, cache, item.def_id()?, item.type_()) -} - -/// Return a string representing the `#[repr]` attribute if present. -pub(crate) fn repr_attributes( - tcx: TyCtxt<'_>, +fn repr_attribute<'tcx>( + tcx: TyCtxt<'tcx>, cache: &Cache, def_id: DefId, - item_type: ItemType, -) -> Option { - use rustc_abi::IntegerType; - - if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) { - return None; - } - let adt = tcx.adt_def(def_id); +) -> Option> { + let adt = match tcx.def_kind(def_id) { + DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id), + _ => return None, + }; let repr = adt.repr(); - let mut out = Vec::new(); - if repr.c() { - out.push("C"); - } + if repr.transparent() { // Render `repr(transparent)` iff the non-1-ZST field is public or at least one // field is public in case all fields are 1-ZST fields. @@ -3033,34 +2991,35 @@ pub(crate) fn repr_attributes( |field| field.vis.is_public(), ); - if render_transparent { - out.push("transparent"); - } + // Since the transparent repr can't have any other reprs or + // repr modifiers beside it, we can safely return early here. + return render_transparent.then(|| "#[repr(transparent)]".into()); + } + + let mut result = Vec::>::new(); + + if repr.c() { + result.push("C".into()); } if repr.simd() { - out.push("simd"); + result.push("simd".into()); } - let pack_s; if let Some(pack) = repr.pack { - pack_s = format!("packed({})", pack.bytes()); - out.push(&pack_s); + result.push(format!("packed({})", pack.bytes()).into()); } - let align_s; if let Some(align) = repr.align { - align_s = format!("align({})", align.bytes()); - out.push(&align_s); + result.push(format!("align({})", align.bytes()).into()); } - let int_s; if let Some(int) = repr.int { - int_s = match int { - IntegerType::Pointer(is_signed) => { - format!("{}size", if is_signed { 'i' } else { 'u' }) - } - IntegerType::Fixed(size, is_signed) => { - format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) + let prefix = if int.is_signed() { 'i' } else { 'u' }; + let int = match int { + rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"), + rustc_abi::IntegerType::Fixed(int, _) => { + format!("{prefix}{}", int.size().bytes() * 8) } }; - out.push(&int_s); + result.push(int.into()); } - if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None } + + (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into()) } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index afa438f25969..adfc7481c73a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -21,7 +21,7 @@ use super::{ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference, item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_impl, - render_repr_attributes_in_code, render_rightside, render_stability_since_raw, + render_repr_attribute_in_code, render_rightside, render_stability_since_raw, render_stability_since_raw_with_extra, write_section_heading, }; use crate::clean; @@ -1555,7 +1555,7 @@ impl<'clean> DisplayEnum<'clean> { wrap_item(w, |w| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum); + render_repr_attribute_in_code(w, cx, self.def_id); } else { render_attributes_in_code(w, it, "", cx); } @@ -2017,7 +2017,7 @@ impl<'a> DisplayStruct<'a> { wrap_item(w, |w| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct); + render_repr_attribute_in_code(w, cx, self.def_id); } else { render_attributes_in_code(w, it, "", cx); } @@ -2371,7 +2371,7 @@ fn render_union( fmt::from_fn(move |mut f| { if is_type_alias { // For now the only attributes we render for type aliases are `repr` attributes. - render_repr_attributes_in_code(f, cx, def_id, ItemType::Union); + render_repr_attribute_in_code(f, cx, def_id); } else { render_attributes_in_code(f, it, "", cx); } From d7d7725b8cbeea8db490c3b033773776ce8794f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 14 Sep 2025 01:32:20 +0200 Subject: [PATCH 249/537] rustdoc: Fully escape link section and export name Escape "special characters" (e.g., double quotes `"` and line breaks `\n`). Escape HTML. Lastly, add regression tests and clean up existing tests. --- src/librustdoc/html/render/mod.rs | 4 ++-- tests/rustdoc/attribute-rendering.rs | 8 -------- tests/rustdoc/attributes.rs | 12 +++++++++++ tests/rustdoc/inline_cross/attributes.rs | 17 ++++++++++++++-- .../inline_cross/auxiliary/attributes.rs | 9 +++++++++ .../reexport/auxiliary/reexports-attrs.rs | 14 ------------- tests/rustdoc/reexport/reexport-attrs.rs | 20 ------------------- 7 files changed, 38 insertions(+), 46 deletions(-) delete mode 100644 tests/rustdoc/attribute-rendering.rs delete mode 100644 tests/rustdoc/reexport/auxiliary/reexports-attrs.rs delete mode 100644 tests/rustdoc/reexport/reexport-attrs.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4b7822cd3a9f..9280701ea3f8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2935,11 +2935,11 @@ fn render_attributes_in_code( let hir::Attribute::Parsed(kind) = attr else { continue }; let attr = match kind { AttributeKind::LinkSection { name, .. } => { - Cow::Owned(format!("#[unsafe(link_section = \"{name}\")]")) + Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}")))) } AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"), AttributeKind::ExportName { name, .. } => { - Cow::Owned(format!("#[unsafe(export_name = \"{name}\")]")) + Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}")))) } AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"), _ => continue, diff --git a/tests/rustdoc/attribute-rendering.rs b/tests/rustdoc/attribute-rendering.rs deleted file mode 100644 index fb40d0a9887c..000000000000 --- a/tests/rustdoc/attribute-rendering.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![crate_name = "foo"] - -//@ has 'foo/fn.f.html' -//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]' -//@ has - //*[@'class="rust item-decl"]' 'pub fn f()' -#[unsafe(export_name = "\ -f")] -pub fn f() {} diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs index 33e4e31bec6e..429a42a7252c 100644 --- a/tests/rustdoc/attributes.rs +++ b/tests/rustdoc/attributes.rs @@ -9,6 +9,18 @@ pub extern "C" fn f() {} #[unsafe(export_name = "bar")] pub extern "C" fn g() {} +//@ has foo/fn.escape_special.html '//*[@class="code-attribute"]' \ +// '#[unsafe(export_name = "\n\"\n")]' +#[unsafe(export_name = "\n\" +")] +pub extern "C" fn escape_special() {} + +// issue: +//@ has foo/fn.escape_html.html '//*[@class="code-attribute"]' \ +// '#[unsafe(export_name = "")]' +#[unsafe(export_name = "")] +pub extern "C" fn escape_html() {} + //@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]' #[unsafe(link_section = ".text")] pub extern "C" fn example() {} diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs index 4747f8ad67c1..1657b7bdc8f7 100644 --- a/tests/rustdoc/inline_cross/attributes.rs +++ b/tests/rustdoc/inline_cross/attributes.rs @@ -1,7 +1,20 @@ +// Ensure that we render attributes on inlined cross-crate re-exported items. +// issue: + //@ aux-crate:attributes=attributes.rs //@ edition:2021 #![crate_name = "user"] -//@ has 'user/struct.NonExhaustive.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]' +//@ has 'user/fn.no_mangle.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +pub use attributes::no_mangle; + +//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \ +// '#[unsafe(link_section = ".here")]' +pub use attributes::link_section; + +//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \ +// '#[unsafe(export_name = "exonym")]' +pub use attributes::export_name; + +//@ has 'user/struct.NonExhaustive.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]' pub use attributes::NonExhaustive; diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs index c6f155d4ba5a..6068d3855858 100644 --- a/tests/rustdoc/inline_cross/auxiliary/attributes.rs +++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs @@ -1,2 +1,11 @@ +#[unsafe(no_mangle)] +pub fn no_mangle() {} + +#[unsafe(link_section = ".here")] +pub fn link_section() {} + +#[unsafe(export_name = "exonym")] +pub fn export_name() {} + #[non_exhaustive] pub struct NonExhaustive; diff --git a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs deleted file mode 100644 index 96fa8209cde8..000000000000 --- a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs +++ /dev/null @@ -1,14 +0,0 @@ -#[unsafe(no_mangle)] -pub fn f0() {} - -#[unsafe(link_section = ".here")] -pub fn f1() {} - -#[unsafe(export_name = "f2export")] -pub fn f2() {} - -#[repr(u8)] -pub enum T0 { V1 } - -#[non_exhaustive] -pub enum T1 {} diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs deleted file mode 100644 index aec0a11c0c6a..000000000000 --- a/tests/rustdoc/reexport/reexport-attrs.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ aux-build: reexports-attrs.rs - -#![crate_name = "foo"] - -extern crate reexports_attrs; - -//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' -pub use reexports_attrs::f0; - -//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]' -pub use reexports_attrs::f1; - -//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]' -pub use reexports_attrs::f2; - -//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]' -pub use reexports_attrs::T0; - -//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]' -pub use reexports_attrs::T1; From 85c193a4ed9cf54a70d6d1edaf411b082d15fd13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 17 May 2025 14:05:07 +0200 Subject: [PATCH 250/537] rustdoc: hide `#[repr(...)]` if it isn't part of the public ABI --- src/doc/rustdoc/src/advanced-features.md | 20 ++- src/librustdoc/html/render/mod.rs | 82 +++++++--- tests/rustdoc-gui/src/test_docs/lib.rs | 8 +- tests/rustdoc/auxiliary/ext-repr.rs | 5 + tests/rustdoc/inline_cross/auxiliary/repr.rs | 42 ----- tests/rustdoc/inline_cross/repr.rs | 40 ----- tests/rustdoc/repr.rs | 154 +++++++++++++++++-- 7 files changed, 229 insertions(+), 122 deletions(-) create mode 100644 tests/rustdoc/auxiliary/ext-repr.rs delete mode 100644 tests/rustdoc/inline_cross/auxiliary/repr.rs delete mode 100644 tests/rustdoc/inline_cross/repr.rs diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index c02c9aebe7ee..f49edb2ac78b 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL to automatically go to the first result. -## `#[repr(transparent)]`: Documenting the transparent representation +## `#[repr(...)]`: Documenting the representation of a type + +Generally, rustdoc only displays the representation of a given type if none of its variants are +`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely +not meant to be considered part of the public ABI otherwise. + +Note that there's no way to overwrite that heuristic and force rustdoc to show the representation +regardless. + +### `#[repr(transparent)]` You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and in the [Rustonomicon][repr-trans-nomicon]. Since this representation is only considered part of the public ABI if the single field with non-trivial -size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays -the attribute if and only if the non-1-ZST field is public or at least one field is public in case all -fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized. +size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays +the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or +– in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`. +The term *1-ZST* refers to types that are one-aligned and zero-sized. It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]` if one wishes to declare the representation as private even if the non-1-ZST field is public. However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work. -Therefore, if you would like to do so, you should always write it down in prose independently of whether +Therefore, if you would like to do so, you should always write that down in prose independently of whether you use `cfg_attr` or not. [repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 9280701ea3f8..143911cb104d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2964,6 +2964,10 @@ fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) { write!(w, "
{prefix}{attr}
").unwrap(); } +/// Compute the *public* `#[repr]` of the item given by `DefId`. +/// +/// Read more about it here: +/// . fn repr_attribute<'tcx>( tcx: TyCtxt<'tcx>, cache: &Cache, @@ -2975,25 +2979,59 @@ fn repr_attribute<'tcx>( }; let repr = adt.repr(); + let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id); + let is_public_field = |field: &ty::FieldDef| { + (cache.document_private || field.vis.is_public()) && is_visible(field.did) + }; + if repr.transparent() { - // Render `repr(transparent)` iff the non-1-ZST field is public or at least one - // field is public in case all fields are 1-ZST fields. - let render_transparent = cache.document_private - || adt - .all_fields() - .find(|field| { - let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); - tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty)) - .is_ok_and(|layout| !layout.is_1zst()) - }) - .map_or_else( - || adt.all_fields().any(|field| field.vis.is_public()), - |field| field.vis.is_public(), - ); + // The transparent repr is public iff the non-1-ZST field is public and visible or + // – in case all fields are 1-ZST fields — at least one field is public and visible. + let is_public = 'is_public: { + // `#[repr(transparent)]` can only be applied to structs and single-variant enums. + let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant + + if !is_visible(var.def_id) { + break 'is_public false; + } + + // Side note: There can only ever be one or zero non-1-ZST fields. + let non_1zst_field = var.fields.iter().find(|field| { + let ty = ty::TypingEnv::post_analysis(tcx, field.did) + .as_query_input(tcx.type_of(field.did).instantiate_identity()); + tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst()) + }); + + match non_1zst_field { + Some(field) => is_public_field(field), + None => var.fields.is_empty() || var.fields.iter().any(is_public_field), + } + }; // Since the transparent repr can't have any other reprs or // repr modifiers beside it, we can safely return early here. - return render_transparent.then(|| "#[repr(transparent)]".into()); + return is_public.then(|| "#[repr(transparent)]".into()); + } + + // Fast path which avoids looking through the variants and fields in + // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`. + // FIXME: This check is not very robust / forward compatible! + if !repr.c() + && !repr.simd() + && repr.int.is_none() + && repr.pack.is_none() + && repr.align.is_none() + { + return None; + } + + // The repr is public iff all components are public and visible. + let is_public = adt + .variants() + .iter() + .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field)); + if !is_public { + return None; } let mut result = Vec::>::new(); @@ -3004,12 +3042,6 @@ fn repr_attribute<'tcx>( if repr.simd() { result.push("simd".into()); } - if let Some(pack) = repr.pack { - result.push(format!("packed({})", pack.bytes()).into()); - } - if let Some(align) = repr.align { - result.push(format!("align({})", align.bytes()).into()); - } if let Some(int) = repr.int { let prefix = if int.is_signed() { 'i' } else { 'u' }; let int = match int { @@ -3021,5 +3053,13 @@ fn repr_attribute<'tcx>( result.push(int.into()); } + // Render modifiers last. + if let Some(pack) = repr.pack { + result.push(format!("packed({})", pack.bytes()).into()); + } + if let Some(align) = repr.align { + result.push(format!("align({})", align.bytes()).into()); + } + (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into()) } diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 42f2fbd93b1e..de7c89a9fa37 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -459,10 +459,10 @@ pub fn safe_fn() {} #[repr(C)] pub struct WithGenerics { - s: S, - t: T, - e: E, - p: P, + pub s: S, + pub t: T, + pub e: E, + pub p: P, } pub struct StructWithPublicUndocumentedFields { diff --git a/tests/rustdoc/auxiliary/ext-repr.rs b/tests/rustdoc/auxiliary/ext-repr.rs new file mode 100644 index 000000000000..25acaa49449e --- /dev/null +++ b/tests/rustdoc/auxiliary/ext-repr.rs @@ -0,0 +1,5 @@ +#[repr(i8)] +pub enum ReprI8 { + Var0, + Var1, +} diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs deleted file mode 100644 index 0211e1a86588..000000000000 --- a/tests/rustdoc/inline_cross/auxiliary/repr.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![feature(repr_simd)] - -#[repr(C, align(8))] -pub struct ReprC { - field: u8, -} -#[repr(simd, packed(2))] -pub struct ReprSimd { - field: [u8; 1], -} -#[repr(transparent)] -pub struct ReprTransparent { - pub field: u8, -} -#[repr(isize)] -pub enum ReprIsize { - Bla, -} -#[repr(u8)] -pub enum ReprU8 { - Bla, -} - -#[repr(transparent)] // private -pub struct ReprTransparentPrivField { - field: u32, // non-1-ZST field -} - -#[repr(transparent)] // public -pub struct ReprTransparentPriv1ZstFields { - marker0: Marker, - pub main: u64, // non-1-ZST field - marker1: Marker, -} - -#[repr(transparent)] // private -pub struct ReprTransparentPrivFieldPub1ZstFields { - main: [u16; 0], // non-1-ZST field - pub marker: Marker, -} - -pub struct Marker; // 1-ZST diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs deleted file mode 100644 index d13e560b8d77..000000000000 --- a/tests/rustdoc/inline_cross/repr.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Regression test for . -// This test ensures that the re-exported items still have the `#[repr(...)]` attribute. - -//@ aux-build:repr.rs - -#![crate_name = "foo"] - -extern crate repr; - -//@ has 'foo/struct.ReprC.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]' -pub use repr::ReprC; -//@ has 'foo/struct.ReprSimd.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]' -pub use repr::ReprSimd; -//@ has 'foo/struct.ReprTransparent.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -pub use repr::ReprTransparent; -//@ has 'foo/enum.ReprIsize.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]' -pub use repr::ReprIsize; -//@ has 'foo/enum.ReprU8.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]' -pub use repr::ReprU8; - -// Regression test for . -// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one -// field is public in case all fields are 1-ZST fields. - -//@ has 'foo/struct.ReprTransparentPrivField.html' -//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -pub use repr::ReprTransparentPrivField; - -//@ has 'foo/struct.ReprTransparentPriv1ZstFields.html' -//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -pub use repr::ReprTransparentPriv1ZstFields; - -//@ has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html' -//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -pub use repr::ReprTransparentPrivFieldPub1ZstFields; diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs index f4f683b3d81a..1e8fad6ec0a6 100644 --- a/tests/rustdoc/repr.rs +++ b/tests/rustdoc/repr.rs @@ -1,29 +1,163 @@ -// Regression test for . -// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one -// field is public in case all fields are 1-ZST fields. +// Test the rendering of `#[repr]` on ADTs. +#![feature(repr_simd)] // only used for the `ReprSimd` test case + +// Check the "local case" (HIR cleaning) // + +// Don't render the default repr which is `Rust`. +//@ has 'repr/struct.ReprDefault.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]' +pub struct ReprDefault; + +// Don't render the `Rust` repr — even if given explicitly — since it's the default. +//@ has 'repr/struct.ReprRust.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]' +#[repr(Rust)] // omitted +pub struct ReprRust; + +//@ has 'repr/struct.ReprCPubFields.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]' +#[repr(C)] // public +pub struct ReprCPubFields { + pub a: u32, + pub b: u32, +} + +//@ has 'repr/struct.ReprCPrivField.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]' +#[repr(C)] // private... +pub struct ReprCPrivField { + a: u32, // ...since this is private + pub b: u32, +} + +//@ has 'repr/enum.ReprIsize.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]' +#[repr(isize)] // public +pub enum ReprIsize { + Bla, +} + +//@ has 'repr/enum.ReprU32HiddenVariant.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32)]' +#[repr(u32)] // private... +pub enum ReprU32HiddenVariant { + #[doc(hidden)] + Hidden, // ...since this is hidden + Public, +} + +//@ has 'repr/struct.ReprAlignHiddenField.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(align(4))]' +#[repr(align(4))] // private... +pub struct ReprAlignHiddenField { + #[doc(hidden)] + pub hidden: i16, // ...since this field is hidden +} + +//@ has 'repr/struct.ReprSimd.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]' +#[repr(simd, packed(2))] // public +pub struct ReprSimd { + pub field: [u8; 1], +} + +//@ has 'repr/enum.ReprU32Align.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32, align(8))]' +#[repr(u32, align(8))] // public +pub enum ReprU32Align { + Variant(u16), +} + +//@ has 'repr/enum.ReprCHiddenVariantField.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]' +#[repr(C)] // private... +pub enum ReprCHiddenVariantField { + Variant { #[doc(hidden)] field: () }, //...since this field is hidden +} //@ has 'repr/struct.ReprTransparentPrivField.html' //@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -#[repr(transparent)] // private +#[repr(transparent)] // private... pub struct ReprTransparentPrivField { - field: u32, // non-1-ZST field + field: u32, // ...since the non-1-ZST field is private } //@ has 'repr/struct.ReprTransparentPriv1ZstFields.html' //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -#[repr(transparent)] // public +#[repr(transparent)] // public... pub struct ReprTransparentPriv1ZstFields { marker0: Marker, - pub main: u64, // non-1-ZST field + pub main: u64, // ...since the non-1-ZST field is public and visible marker1: Marker, +} // the two private 1-ZST fields don't matter + +//@ has 'repr/struct.ReprTransparentPrivFieldPub1ZstField.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // private... +pub struct ReprTransparentPrivFieldPub1ZstField { + main: [u16; 0], // ...since the non-1-ZST field is private + pub marker: Marker, // this public 1-ZST field doesn't matter } //@ has 'repr/struct.ReprTransparentPub1ZstField.html' //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -#[repr(transparent)] // public +#[repr(transparent)] // public... pub struct ReprTransparentPub1ZstField { - marker0: Marker, - pub marker1: Marker, + marker0: Marker, // ...since we don't have a non-1-ZST field... + pub marker1: Marker, // ...and this field is public and visible +} + +//@ has 'repr/struct.ReprTransparentUnitStruct.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub struct ReprTransparentUnitStruct; + +//@ has 'repr/enum.ReprTransparentEnumUnitVariant.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub enum ReprTransparentEnumUnitVariant { + Variant, +} + +//@ has 'repr/enum.ReprTransparentEnumHiddenUnitVariant.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // private +pub enum ReprTransparentEnumHiddenUnitVariant { + #[doc(hidden)] Variant(u32), +} + +//@ has 'repr/enum.ReprTransparentEnumPub1ZstField.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public... +pub enum ReprTransparentEnumPub1ZstField { + Variant { + field: u64, // ...since the non-1-ZST field is public + #[doc(hidden)] + marker: Marker, // this hidden 1-ZST field doesn't matter + }, +} + +//@ has 'repr/enum.ReprTransparentEnumHidden1ZstField.html' +//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // private... +pub enum ReprTransparentEnumHidden1ZstField { + Variant { + #[doc(hidden)] + field: u64, // ...since the non-1-ZST field is public + }, } struct Marker; // 1-ZST + +// Check the "extern case" (middle cleaning) // + +// Internally, HIR and middle cleaning share `#[repr]` rendering. +// Thus we'll only test the very basics in this section. + +//@ aux-build: ext-repr.rs +extern crate ext_repr as ext; + +// Regression test for . +//@ has 'repr/enum.ReprI8.html' +//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(i8)]' +pub use ext::ReprI8; From 747019ce4647dd2194c2d9e08d482e4d9c669069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Wed, 24 Sep 2025 07:28:32 +0000 Subject: [PATCH 251/537] bootstrap.py: Respect build.jobs while building bootstrap tool On resource-constrained systems, it is vital to respect the value of build.jobs, in order to avoid overwhelming the available memory. --- src/bootstrap/bootstrap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index effd33d288fa..8b1775178c91 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -596,6 +596,7 @@ class RustBuild(object): self.download_url = ( os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"] ) + self.jobs = self.get_toml("jobs", "build") or "default" self.build = args.build or self.build_triple() @@ -1144,6 +1145,7 @@ class RustBuild(object): args = [ self.cargo(), "build", + "--jobs=" + self.jobs, "--manifest-path", os.path.join(self.rust_root, "src/bootstrap/Cargo.toml"), "-Zroot-dir=" + self.rust_root, From d834935b57bcd4604727e8a1fa93e8785979eb5c Mon Sep 17 00:00:00 2001 From: DimitriiTrater Date: Thu, 11 Sep 2025 19:17:05 +0200 Subject: [PATCH 252/537] Fix atan2 inaccuracy in documentation --- library/std/src/num/f128.rs | 10 ++++++---- library/std/src/num/f16.rs | 10 ++++++---- library/std/src/num/f32.rs | 10 ++++++---- library/std/src/num/f64.rs | 10 ++++++---- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs index b83692390b6b..5a85c1daaf0a 100644 --- a/library/std/src/num/f128.rs +++ b/library/std/src/num/f128.rs @@ -557,10 +557,12 @@ impl f128 { /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// | `x` | `y` | Piecewise Definition | Range | + /// |---------|---------|----------------------|---------------| + /// | `>= +0` | `>= +0` | `arctan(y/x)` | `[+0, +pi/2]` | + /// | `>= +0` | `<= -0` | `arctan(y/x)` | `[-pi/2, -0]` | + /// | `<= -0` | `>= +0` | `arctan(y/x) + pi` | `[+pi/2, +pi]`| + /// | `<= -0` | `<= -0` | `arctan(y/x) - pi` | `[-pi, -pi/2]`| /// /// # Unspecified precision /// diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 5599528717cb..cc10c41b9e7d 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -522,10 +522,12 @@ impl f16 { /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// | `x` | `y` | Piecewise Definition | Range | + /// |---------|---------|----------------------|---------------| + /// | `>= +0` | `>= +0` | `arctan(y/x)` | `[+0, +pi/2]` | + /// | `>= +0` | `<= -0` | `arctan(y/x)` | `[-pi/2, -0]` | + /// | `<= -0` | `>= +0` | `arctan(y/x) + pi` | `[+pi/2, +pi]`| + /// | `<= -0` | `<= -0` | `arctan(y/x) - pi` | `[-pi, -pi/2]`| /// /// # Unspecified precision /// diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 0247080a8d6b..72e5f4d4c410 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -826,10 +826,12 @@ impl f32 { /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// | `x` | `y` | Piecewise Definition | Range | + /// |---------|---------|----------------------|---------------| + /// | `>= +0` | `>= +0` | `arctan(y/x)` | `[+0, +pi/2]` | + /// | `>= +0` | `<= -0` | `arctan(y/x)` | `[-pi/2, -0]` | + /// | `<= -0` | `>= +0` | `arctan(y/x) + pi` | `[+pi/2, +pi]`| + /// | `<= -0` | `<= -0` | `arctan(y/x) - pi` | `[-pi, -pi/2]`| /// /// # Unspecified precision /// diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 1cfd3909d967..5f3e793c3a71 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -826,10 +826,12 @@ impl f64 { /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// | `x` | `y` | Piecewise Definition | Range | + /// |---------|---------|----------------------|---------------| + /// | `>= +0` | `>= +0` | `arctan(y/x)` | `[+0, +pi/2]` | + /// | `>= +0` | `<= -0` | `arctan(y/x)` | `[-pi/2, -0]` | + /// | `<= -0` | `>= +0` | `arctan(y/x) + pi` | `[+pi/2, +pi]`| + /// | `<= -0` | `<= -0` | `arctan(y/x) - pi` | `[-pi, -pi/2]`| /// /// # Unspecified precision /// From a9637efa275767c270829579f5282e5585043d19 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 25 Sep 2025 19:58:45 +0800 Subject: [PATCH 253/537] Fix fixes for unused raw variables Example --- ``` fn main() { let $0r#type = 2; } ``` **Before this PR**: ```rust fn main() { let _r#type = 2; } ``` **After this PR**: ```rust fn main() { let _type = 2; } ``` --- .../src/handlers/unused_variables.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index a4f3ca0a2672..84e63acbc04f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -6,7 +6,7 @@ use ide_db::{ label::Label, source_change::SourceChange, }; -use syntax::{AstNode, Edition, TextRange}; +use syntax::{AstNode, Edition, TextRange, ToSmolStr}; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -73,7 +73,8 @@ fn fixes( if is_in_marco { return None; } - let name = var_name.display(db, edition); + let name = var_name.display(db, edition).to_smolstr(); + let name = name.strip_prefix("r#").unwrap_or(&name); let new_name = if is_shorthand_field { format!("{name}: _{name}") } else { format!("_{name}") }; Some(vec![Assist { @@ -231,6 +232,19 @@ fn main() { } } } +"#, + ); + + check_fix( + r#" +fn main() { + let $0r#type = 2; +} +"#, + r#" +fn main() { + let _type = 2; +} "#, ); } From c1cd1da668650d0e9e0f143f89a17387d96979c2 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 3 Sep 2025 20:07:19 +0800 Subject: [PATCH 254/537] Add let-chain support for convert_to_guarded_return - And add early expression `None` in function `Option` return Example --- ```rust fn main() { if$0 let Ok(x) = Err(92) && x < 30 && let Some(y) = Some(8) { foo(x, y); } } ``` -> ```rust fn main() { let Ok(x) = Err(92) else { return }; if x >= 30 { return; } let Some(y) = Some(8) else { return }; foo(x, y); } ``` --- .../src/handlers/convert_to_guarded_return.rs | 217 +++++++++++++++--- 1 file changed, 179 insertions(+), 38 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 2ea032fb62ba..3dc4737ffc51 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -1,13 +1,11 @@ use std::iter::once; -use ide_db::{ - syntax_helpers::node_ext::{is_pattern_cond, single_let}, - ty_filter::TryEnum, -}; +use hir::Semantics; +use ide_db::{RootDatabase, ty_filter::TryEnum}; use syntax::{ AstNode, SyntaxKind::{FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE}, - T, + SyntaxNode, T, ast::{ self, edit::{AstNodeEdit, IndentLevel}, @@ -73,13 +71,7 @@ fn if_expr_to_guarded_return( return None; } - // Check if there is an IfLet that we can handle. - let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) { - let let_ = single_let(cond)?; - (Some(let_.pat()?), let_.expr()?) - } else { - (None, cond) - }; + let let_chains = flat_let_chain(cond); let then_block = if_expr.then_branch()?; let then_block = then_block.stmt_list()?; @@ -106,11 +98,7 @@ fn if_expr_to_guarded_return( let parent_container = parent_block.syntax().parent()?; - let early_expression: ast::Expr = match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), - FN => make::expr_return(None), - _ => return None, - }; + let early_expression: ast::Expr = early_expression(parent_container, &ctx.sema)?; then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?; @@ -132,32 +120,42 @@ fn if_expr_to_guarded_return( target, |edit| { let if_indent_level = IndentLevel::from_node(if_expr.syntax()); - let replacement = match if_let_pat { - None => { - // If. - let new_expr = { - let then_branch = - make::block_expr(once(make::expr_stmt(early_expression).into()), None); - let cond = invert_boolean_expression_legacy(cond_expr); - make::expr_if(cond, then_branch, None).indent(if_indent_level) - }; - new_expr.syntax().clone() - } - Some(pat) => { + let replacement = let_chains.into_iter().map(|expr| { + if let ast::Expr::LetExpr(let_expr) = &expr + && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr()) + { // If-let. let let_else_stmt = make::let_else_stmt( pat, None, - cond_expr, - ast::make::tail_only_block_expr(early_expression), + expr, + ast::make::tail_only_block_expr(early_expression.clone()), ); let let_else_stmt = let_else_stmt.indent(if_indent_level); let_else_stmt.syntax().clone() + } else { + // If. + let new_expr = { + let then_branch = make::block_expr( + once(make::expr_stmt(early_expression.clone()).into()), + None, + ); + let cond = invert_boolean_expression_legacy(expr); + make::expr_if(cond, then_branch, None).indent(if_indent_level) + }; + new_expr.syntax().clone() } - }; + }); + let newline = &format!("\n{if_indent_level}"); let then_statements = replacement - .children_with_tokens() + .enumerate() + .flat_map(|(i, node)| { + (i != 0) + .then(|| make::tokens::whitespace(newline).into()) + .into_iter() + .chain(node.children_with_tokens()) + }) .chain( then_block_items .syntax() @@ -201,11 +199,7 @@ fn let_stmt_to_guarded_return( let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; let parent_container = parent_block.syntax().parent()?; - match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), - FN => make::expr_return(None), - _ => return None, - } + early_expression(parent_container, &ctx.sema)? }; acc.add( @@ -232,6 +226,44 @@ fn let_stmt_to_guarded_return( ) } +fn early_expression( + parent_container: SyntaxNode, + sema: &Semantics<'_, RootDatabase>, +) -> Option { + if let Some(fn_) = ast::Fn::cast(parent_container.clone()) + && let Some(fn_def) = sema.to_def(&fn_) + && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db)) + { + let none_expr = make::expr_path(make::ext::ident_path("None")); + return Some(make::expr_return(Some(none_expr))); + } + Some(match parent_container.kind() { + WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), + FN => make::expr_return(None), + _ => return None, + }) +} + +fn flat_let_chain(mut expr: ast::Expr) -> Vec { + let mut chains = vec![]; + + while let ast::Expr::BinExpr(bin_expr) = &expr + && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) + && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs()) + { + if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) { + chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last)); + } else { + chains.push(rhs); + } + expr = lhs; + } + + chains.push(expr); + chains.reverse(); + chains +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -268,6 +300,37 @@ fn main() { ); } + #[test] + fn convert_inside_fn_return_option() { + check_assist( + convert_to_guarded_return, + r#" +//- minicore: option +fn ret_option() -> Option<()> { + bar(); + if$0 true { + foo(); + + // comment + bar(); + } +} +"#, + r#" +fn ret_option() -> Option<()> { + bar(); + if false { + return None; + } + foo(); + + // comment + bar(); +} +"#, + ); + } + #[test] fn convert_let_inside_fn() { check_assist( @@ -316,6 +379,58 @@ fn main() { ); } + #[test] + fn convert_if_let_chain_result() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 let Ok(x) = Err(92) + && x < 30 + && let Some(y) = Some(8) + { + foo(x, y); + } +} +"#, + r#" +fn main() { + let Ok(x) = Err(92) else { return }; + if x >= 30 { + return; + } + let Some(y) = Some(8) else { return }; + foo(x, y); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 let Ok(x) = Err(92) + && x < 30 + && y < 20 + && let Some(y) = Some(8) + { + foo(x, y); + } +} +"#, + r#" +fn main() { + let Ok(x) = Err(92) else { return }; + if !(x < 30 && y < 20) { + return; + } + let Some(y) = Some(8) else { return }; + foo(x, y); +} +"#, + ); + } + #[test] fn convert_let_ok_inside_fn() { check_assist( @@ -560,6 +675,32 @@ fn main() { ); } + #[test] + fn convert_let_stmt_inside_fn_return_option() { + check_assist( + convert_to_guarded_return, + r#" +//- minicore: option +fn foo() -> Option { + None +} + +fn ret_option() -> Option { + let x$0 = foo(); +} +"#, + r#" +fn foo() -> Option { + None +} + +fn ret_option() -> Option { + let Some(x) = foo() else { return None }; +} +"#, + ); + } + #[test] fn convert_let_stmt_inside_loop() { check_assist( From 079addf985d1902e8f79620697834c3ea3de84c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 15:07:34 +0200 Subject: [PATCH 255/537] Ensure that `--build-dir` is always specified in tests --- src/bootstrap/src/core/config/config.rs | 27 ++++--------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1e207380a0a1..74a272c740bd 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -642,12 +642,12 @@ impl Config { let llvm_assertions = llvm_assertions.unwrap_or(false); let mut target_config = HashMap::new(); let mut channel = "dev".to_string(); + + let out = flags_build_dir.or_else(|| build_build_dir.map(PathBuf::from)); let out = if cfg!(test) { - test_build_dir() + out.expect("--build-dir has to be specified in tests") } else { - flags_build_dir - .or_else(|| build_build_dir.map(PathBuf::from)) - .unwrap_or_else(|| PathBuf::from("build")) + out.unwrap_or_else(|| PathBuf::from("build")) }; // NOTE: Bootstrap spawns various commands with different working directories. @@ -2490,22 +2490,3 @@ fn find_correct_section_for_field(field_name: &str) -> Vec { }) .collect() } - -/// Resolve the build directory used for tests. -/// -/// - When tests are run through bootstrap (`x.py test`), the build system -/// sets `CARGO_TARGET_DIR`, so we can trust and use it here. -/// - When tests are run directly with cargo test, `CARGO_TARGET_DIR` will -/// not be set. In that case we fall back to resolving relative to -/// `CARGO_MANIFEST_DIR`, by walking two parents up and appending `build`. -fn test_build_dir() -> PathBuf { - env::var_os("CARGO_TARGET_DIR") - .map(|value| Path::new(&value).parent().unwrap().to_path_buf()) - .unwrap_or_else(|| { - let base = option_env!("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .unwrap_or_else(|| std::env::current_dir().expect("failed to get current dir")); - - base.ancestors().nth(2).unwrap_or_else(|| Path::new(".")).join("build") - }) -} From 1947949f3d7212c181049d96e2665481d3bddc6b Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 25 Sep 2025 21:57:10 +0800 Subject: [PATCH 256/537] Fix not applicable for if-expr in let-stmt Example --- ```rust fn main() { let _x = loop { if$0 let Ok(x) = Err(92) { foo(x); } }; } ``` **Before**: Assist not applicable **After**: ```rust fn main() { let _x = loop { let Ok(x) = Err(92) else { continue }; foo(x); }; } ``` --- .../src/handlers/convert_to_guarded_return.rs | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index 3dc4737ffc51..aee9ce7878b2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -1,6 +1,7 @@ use std::iter::once; use hir::Semantics; +use either::Either; use ide_db::{RootDatabase, ty_filter::TryEnum}; use syntax::{ AstNode, @@ -42,12 +43,9 @@ use crate::{ // } // ``` pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - if let Some(let_stmt) = ctx.find_node_at_offset() { - let_stmt_to_guarded_return(let_stmt, acc, ctx) - } else if let Some(if_expr) = ctx.find_node_at_offset() { - if_expr_to_guarded_return(if_expr, acc, ctx) - } else { - None + match ctx.find_node_at_offset::>()? { + Either::Left(let_stmt) => let_stmt_to_guarded_return(let_stmt, acc, ctx), + Either::Right(if_expr) => if_expr_to_guarded_return(if_expr, acc, ctx), } } @@ -379,6 +377,30 @@ fn main() { ); } + #[test] + fn convert_if_let_result_inside_let() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + let _x = loop { + if$0 let Ok(x) = Err(92) { + foo(x); + } + }; +} +"#, + r#" +fn main() { + let _x = loop { + let Ok(x) = Err(92) else { continue }; + foo(x); + }; +} +"#, + ); + } + #[test] fn convert_if_let_chain_result() { check_assist( From 11c35cd0bcb6e0c285be031f10d14d64bbf2bd9c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 25 Sep 2025 21:57:45 +0800 Subject: [PATCH 257/537] Add applicable in closure for convert_to_guarded_return Example --- ```rust fn main() { let _f = || { bar(); if$0 true { foo(); // comment bar(); } } } ``` -> ```rust fn main() { let _f = || { bar(); if false { return; } foo(); // comment bar(); } } ``` --- .../src/handlers/convert_to_guarded_return.rs | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index aee9ce7878b2..82213ae3217e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -1,11 +1,11 @@ use std::iter::once; -use hir::Semantics; use either::Either; +use hir::{Semantics, TypeInfo}; use ide_db::{RootDatabase, ty_filter::TryEnum}; use syntax::{ AstNode, - SyntaxKind::{FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE}, + SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE}, SyntaxNode, T, ast::{ self, @@ -228,16 +228,26 @@ fn early_expression( parent_container: SyntaxNode, sema: &Semantics<'_, RootDatabase>, ) -> Option { + let return_none_expr = || { + let none_expr = make::expr_path(make::ext::ident_path("None")); + make::expr_return(Some(none_expr)) + }; if let Some(fn_) = ast::Fn::cast(parent_container.clone()) && let Some(fn_def) = sema.to_def(&fn_) && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db)) { - let none_expr = make::expr_path(make::ext::ident_path("None")); - return Some(make::expr_return(Some(none_expr))); + return Some(return_none_expr()); } + if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body()) + && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original) + && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty) + { + return Some(return_none_expr()); + } + Some(match parent_container.kind() { WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None), - FN => make::expr_return(None), + FN | CLOSURE_EXPR => make::expr_return(None), _ => return None, }) } @@ -329,6 +339,40 @@ fn ret_option() -> Option<()> { ); } + #[test] + fn convert_inside_closure() { + check_assist( + convert_to_guarded_return, + r#" +fn main() { + let _f = || { + bar(); + if$0 true { + foo(); + + // comment + bar(); + } + } +} +"#, + r#" +fn main() { + let _f = || { + bar(); + if false { + return; + } + foo(); + + // comment + bar(); + } +} +"#, + ); + } + #[test] fn convert_let_inside_fn() { check_assist( From 89a3a445bfb31637549e4f1a652869f631416c73 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 25 Sep 2025 07:18:36 -0700 Subject: [PATCH 258/537] mbe: macro_check: Fix function comments referencing non-existent parameters Several functions had comments referencing a non-existent `valid` parameter. Remove those. The `guar` parameter that handles errors is already documented. In the process, remove another duplicate reference to an already-documented parameter (`binders`). --- compiler/rustc_expand/src/mbe/macro_check.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index ebd6e887f7d2..0eae44a05e78 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -210,8 +210,7 @@ pub(super) fn check_meta_variables( guar.map_or(Ok(()), Err) } -/// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and -/// sets `valid` to false in case of errors. +/// Checks `lhs` as part of the LHS of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -306,8 +305,7 @@ fn get_binder_info<'a>( binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name))) } -/// Checks `rhs` as part of the RHS of a macro definition and sets `valid` to false in case of -/// errors. +/// Checks `rhs` as part of the RHS of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -372,7 +370,7 @@ enum NestedMacroState { } /// Checks `tts` as part of the RHS of a macro definition, tries to recognize nested macro -/// definitions, and sets `valid` to false in case of errors. +/// definitions. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -491,8 +489,7 @@ fn check_nested_occurrences( } } -/// Checks the body of nested macro, returns where the check stopped, and sets `valid` to false in -/// case of errors. +/// Checks the body of nested macro, returns where the check stopped. /// /// The token trees are checked as long as they look like a list of (LHS) => {RHS} token trees. This /// check is a best-effort to detect a macro definition. It returns the position in `tts` where we From 9877b26fd14d32064b1f944dd1e79c9c8faccf16 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 16:42:45 +0200 Subject: [PATCH 259/537] Correctly display merged doctest compilation time --- src/librustdoc/doctest.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 95bd31729de1..9499258f983a 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -404,11 +404,15 @@ pub(crate) fn run_tests( std::mem::drop(temp_dir.take()); times.display_times(); }); - } - if nb_errors != 0 { - // We ensure temp dir destructor is called. - std::mem::drop(temp_dir); + } else { + // If the first condition branch exited successfully, `test_main_with_exit_callback` will + // not exit the process. So to prevent displaying the times twice, we put it behind an + // `else` condition. times.display_times(); + } + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir); + if nb_errors != 0 { std::process::exit(test::ERROR_EXIT_CODE); } } From 9e3f7487e9e572aee95381688bda52525d79b005 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 25 Sep 2025 07:43:25 -0700 Subject: [PATCH 260/537] mbe: Simplify check_redundant_vis_repetition Eliminate a use of `map_or` in favor of a match. Inline some variable definitions that don't add clarity, and that prevent short-circuiting. --- compiler/rustc_expand/src/mbe/macro_rules.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 1d147a0385c6..74b7de7e12bc 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -894,12 +894,12 @@ fn check_redundant_vis_repetition( seq: &SequenceRepetition, span: &DelimSpan, ) { - let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne; - let is_vis = seq.tts.first().map_or(false, |tt| { - matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. }) - }); - - if is_vis && is_zero_or_one { + if seq.kleene.op == KleeneOp::ZeroOrOne + && matches!( + seq.tts.first(), + Some(mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. }) + ) + { err.note("a `vis` fragment can already be empty"); err.multipart_suggestion( "remove the `$(` and `)?`", From 7e58c9110521d960cb97e730dfe700b3ec64c9ab Mon Sep 17 00:00:00 2001 From: helldawg <116204326+helldawg@users.noreply.github.com> Date: Fri, 19 Sep 2025 04:59:14 +0300 Subject: [PATCH 261/537] usize/isize range matching error clarification --- .../src/thir/pattern/check_match.rs | 8 +++---- ...ture-gate-precise_pointer_size_matching.rs | 4 ++-- ...-gate-precise_pointer_size_matching.stderr | 4 ++-- .../pointer-sized-int.deny.stderr | 22 +++++++++---------- .../precise_pointer_matching-message.rs | 4 ++-- .../precise_pointer_matching-message.stderr | 4 ++-- ...pes-containing-non-exhaustive-types.stderr | 16 +++++++------- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index ae67bb5075e8..3929a97eed8f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1275,13 +1275,13 @@ fn report_non_exhaustive_match<'p, 'tcx>( if ty.is_ptr_sized_integral() { if ty.inner() == cx.tcx.types.usize { err.note(format!( - "`{ty}` does not have a fixed maximum value, so half-open ranges are \ - necessary to match exhaustively", + "`{ty}::MAX` is not treated as exhaustive, \ + so half-open ranges are necessary to match exhaustively", )); } else if ty.inner() == cx.tcx.types.isize { err.note(format!( - "`{ty}` does not have fixed minimum and maximum values, so half-open \ - ranges are necessary to match exhaustively", + "`{ty}::MIN` and `{ty}::MAX` are not treated as exhaustive, \ + so half-open ranges are necessary to match exhaustively", )); } } else if ty.inner() == cx.tcx.types.str_ { diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs index b4dc1fd45564..e37e405d1aff 100644 --- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs +++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.rs @@ -3,7 +3,7 @@ fn main() { //~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered //~| NOTE pattern `usize::MAX..` not covered //~| NOTE the matched value is of type `usize` - //~| NOTE `usize` does not have a fixed maximum value + //~| NOTE `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively 0..=usize::MAX => {} } @@ -11,7 +11,7 @@ fn main() { //~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered //~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered //~| NOTE the matched value is of type `isize` - //~| NOTE `isize` does not have fixed minimum and maximum values + //~| NOTE `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively isize::MIN..=isize::MAX => {} } } diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index c89dcaf727ac..cfb00d6e7412 100644 --- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -5,7 +5,7 @@ LL | match 0usize { | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -19,7 +19,7 @@ LL | match 0isize { | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr index 7caee64a33fb..099d6e862434 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -5,7 +5,7 @@ LL | match 0usize { | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -19,7 +19,7 @@ LL | match 0isize { | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, @@ -33,7 +33,7 @@ LL | m!(0usize, 0..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } @@ -46,7 +46,7 @@ LL | m!(0usize, 0..5 | 5..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } @@ -59,7 +59,7 @@ LL | m!(0usize, 0..usize::MAX | usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } @@ -72,7 +72,7 @@ LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize:: | ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered | = note: the matched value is of type `(usize, bool)` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() } @@ -85,7 +85,7 @@ LL | m!(0isize, isize::MIN..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } @@ -98,7 +98,7 @@ LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } @@ -111,7 +111,7 @@ LL | m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } @@ -124,7 +124,7 @@ LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } @@ -137,7 +137,7 @@ LL | (0isize, true), | ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered | = note: the matched value is of type `(isize, bool)` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() } diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs index d60f479c0d15..6a0106134b50 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.rs @@ -4,7 +4,7 @@ fn main() { //~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered //~| NOTE pattern `usize::MAX..` not covered //~| NOTE the matched value is of type `usize` - //~| NOTE `usize` does not have a fixed maximum value + //~| NOTE `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively 0..=usize::MAX => {} } @@ -12,7 +12,7 @@ fn main() { //~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered //~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered //~| NOTE the matched value is of type `isize` - //~| NOTE `isize` does not have fixed minimum and maximum values + //~| NOTE `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively isize::MIN..=isize::MAX => {} } } diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr index 36743aa81029..fefe7f46ead9 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -5,7 +5,7 @@ LL | match 0usize { | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -19,7 +19,7 @@ LL | match 0isize { | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, diff --git a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr index c31411018bc4..9d7b53093df9 100644 --- a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr +++ b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr @@ -5,7 +5,7 @@ LL | match 0 { | ^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 1..=usize::MAX => (), @@ -19,7 +19,7 @@ LL | match (0usize, 0usize) { | ^^^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered | = note: the matched value is of type `(usize, usize)` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ (1..=usize::MAX, 1..=usize::MAX) => (), @@ -33,7 +33,7 @@ LL | match (0isize, 0usize) { | ^^^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered | = note: the matched value is of type `(isize, usize)` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ (isize::MIN..=isize::MAX, 1..=usize::MAX) => (), @@ -70,7 +70,7 @@ note: `Option` defined here | = note: not covered = note: the matched value is of type `Option` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => (), @@ -93,7 +93,7 @@ note: `Option>>` defined here | = note: not covered = note: the matched value is of type `Option>>` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => (), @@ -112,7 +112,7 @@ note: `A` defined here LL | struct A { | ^ = note: the matched value is of type `A` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ A { a: 1..=usize::MAX } => (), @@ -131,7 +131,7 @@ note: `B` defined here LL | struct B(T, U); | ^ = note: the matched value is of type `B` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = note: `isize::MIN` and `isize::MAX` are not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (), @@ -150,7 +150,7 @@ note: `B` defined here LL | struct B(T, U); | ^ = note: the matched value is of type `B` - = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively + = note: `usize::MAX` is not treated as exhaustive, so half-open ranges are necessary to match exhaustively help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ B(_, 1..=usize::MAX) => (), From 185ae698aabe0f6f7cc5ef7eeed13a556bce5334 Mon Sep 17 00:00:00 2001 From: Tim 'Piepmatz' Hesse Date: Thu, 25 Sep 2025 17:52:24 +0200 Subject: [PATCH 262/537] add doc for `NonZero*` const creation --- library/core/src/num/nonzero.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1b7c28bb95aa..d9184e3c9c22 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -548,6 +548,18 @@ macro_rules! nonzero_integer { #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::>());")] /// ``` /// + /// # Compile-time creation + /// + /// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to + /// define a new + #[doc = concat!("`", stringify!($Ty), "`")] + /// at compile time via: + /// ``` + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// + #[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)] + /// ``` + /// /// [null pointer optimization]: crate::option#representation #[$stability] pub type $Ty = NonZero<$Int>; From 191c7ed10f68c6891ba66e342fa58342e16db402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 17:32:17 +0200 Subject: [PATCH 263/537] Make `cargo test` work again --- src/bootstrap/src/core/config/config.rs | 38 +++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 74a272c740bd..07a6616be0c9 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -414,15 +414,17 @@ impl Config { // Set config values based on flags. let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); - let mut src = { + + let default_src_dir = { let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); // Undo `src/bootstrap` manifest_dir.parent().unwrap().parent().unwrap().to_owned() }; - - if let Some(src_) = compute_src_directory(flags_src, &exec_ctx) { - src = src_; - } + let src = if let Some(s) = compute_src_directory(flags_src, &exec_ctx) { + s + } else { + default_src_dir.clone() + }; #[cfg(test)] { @@ -659,6 +661,10 @@ impl Config { out }; + let default_stage0_rustc_path = |dir: &Path| { + dir.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) + }; + if cfg!(test) { // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the // same ones used to call the tests (if custom ones are not defined in the toml). If we @@ -667,6 +673,22 @@ impl Config { // Cargo in their bootstrap.toml. build_rustc = build_rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into())); build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); + + // If we are running only `cargo test` (and not `x test bootstrap`), which is useful + // e.g. for debugging bootstrap itself, then we won't have RUSTC and CARGO set to the + // proper paths. + // We thus "guess" that the build directory is located at /build, and try to load + // rustc and cargo from there + let is_test_outside_x = std::env::var("CARGO_TARGET_DIR").is_err(); + if is_test_outside_x && build_rustc.is_none() { + let stage0_rustc = default_stage0_rustc_path(&default_src_dir.join("build")); + assert!( + stage0_rustc.exists(), + "Trying to run cargo test without having a stage0 rustc available in {}", + stage0_rustc.display() + ); + build_rustc = Some(stage0_rustc); + } } if !flags_skip_stage0_validation { @@ -700,7 +722,7 @@ impl Config { let initial_rustc = build_rustc.unwrap_or_else(|| { download_beta_toolchain(&dwn_ctx, &out); - out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) + default_stage0_rustc_path(&out) }); let initial_sysroot = t!(PathBuf::from_str( @@ -1540,11 +1562,11 @@ impl Config { println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); println!("HELP: Consider rebasing to a newer commit if available."); return None; - }, + } Err(e) => { eprintln!("ERROR: Failed to parse CI rustc bootstrap.toml: {e}"); exit!(2); - }, + } }; let current_config_toml = Self::get_toml(config_path).unwrap(); From 5595f437c7b82b1ca18f77f8834fe9398b682153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:12:39 +0200 Subject: [PATCH 264/537] Remove `verbose_than` function --- src/bootstrap/src/core/build_steps/compile.rs | 7 +------ src/bootstrap/src/lib.rs | 13 ++++--------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 14104d7d1d78..b47b4f248a9a 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1902,12 +1902,7 @@ impl Step for Sysroot { if !path.parent().is_none_or(|p| p.ends_with(&suffix)) { return true; } - if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { - builder.verbose_than(1, || println!("ignoring {}", path.display())); - false - } else { - true - } + filtered_files.iter().all(|f| f != path.file_name().unwrap()) }); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index e953fe2945e4..db963f9c6f99 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1092,13 +1092,6 @@ impl Build { self.verbosity > level } - /// Runs a function if verbosity is greater than `level`. - fn verbose_than(&self, level: usize, f: impl Fn()) { - if self.is_verbose_than(level) { - f() - } - } - fn info(&self, msg: &str) { match self.config.get_dry_run() { DryRun::SelfCheck => (), @@ -1816,7 +1809,6 @@ impl Build { if self.config.dry_run() { return; } - self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}")); if src == dst { return; } @@ -1933,7 +1925,10 @@ impl Build { return; } let dst = dstdir.join(src.file_name().unwrap()); - self.verbose_than(1, || println!("Install {src:?} to {dst:?}")); + + #[cfg(feature = "tracing")] + let _span = trace_io!("install", ?src, ?dst); + t!(fs::create_dir_all(dstdir)); if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); From 5a6e3cccebd9cac06af815f0480ad58d14182480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:14:33 +0200 Subject: [PATCH 265/537] Remove `is_verbose_than` function --- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/lib.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index ee2bb710674c..9fc4ce669c2a 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1139,7 +1139,7 @@ impl Builder<'_> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } - if self.is_verbose_than(1) { + if self.verbosity >= 2 { // This provides very useful logs especially when debugging build cache-related stuff. cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index db963f9c6f99..75cc79e6689c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1087,11 +1087,6 @@ impl Build { }) } - /// Check if verbosity is greater than the `level` - pub fn is_verbose_than(&self, level: usize) -> bool { - self.verbosity > level - } - fn info(&self, msg: &str) { match self.config.get_dry_run() { DryRun::SelfCheck => (), From 0374df1b50d227f173c07631b390b271efb04ae6 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Fri, 5 Sep 2025 08:34:00 +0200 Subject: [PATCH 266/537] Introduce and use CmCell during import resolution. --- .../rustc_resolve/src/build_reduced_graph.rs | 19 +-- compiler/rustc_resolve/src/imports.rs | 26 ++-- compiler/rustc_resolve/src/lib.rs | 128 +++++++++++++++--- compiler/rustc_resolve/src/macros.rs | 2 +- 4 files changed, 135 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index fa3c06059b3d..c10b6ca7e71b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -5,7 +5,6 @@ //! unexpanded macros in the fragment are visited and registered. //! Imports are also considered items and placed into modules here, but not resolved yet. -use std::cell::Cell; use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; @@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::ref_mut::CmCell; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, @@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - parent.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + parent.underscore_disambiguator.update_unchecked(|d| d + 1); parent.underscore_disambiguator.get() }); if self @@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind, parent_scope: self.parent_scope, module_path, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), span, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), @@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } } - ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), + ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import), _ => unreachable!(), } } @@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ast::UseTreeKind::Glob => { if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { - let kind = ImportKind::Glob { max_vis: Cell::new(None), id }; + let kind = ImportKind::Glob { max_vis: CmCell::new(None), id }; self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } else { // Resolve the prelude import early. @@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(module), + imported_module: CmCell::new(module), has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), use_span: item.span, @@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroUse { warn_private }, root_id: item.id, parent_scope: this.parent_scope, - imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), + imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), use_span: item.span, @@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { /// directly into its parent scope's module. fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> { let invoc_id = self.visit_invoc(id); - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); + self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } @@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroExport, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), has_attributes: false, use_span_with_attributes: span, use_span: span, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d7fc028287ff..2370bf809394 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,5 @@ //! A bunch of methods and structures more or less related to resolving imports. -use std::cell::Cell; use std::mem; use rustc_ast::NodeId; @@ -32,6 +31,7 @@ use crate::errors::{ CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; +use crate::ref_mut::CmCell; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, @@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings introduced by the import. - bindings: PerNS>>, + bindings: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -89,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { Glob { // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell>, + max_vis: CmCell>, id: NodeId, }, ExternCrate { @@ -182,7 +182,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | /// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | - pub imported_module: Cell>>, + pub imported_module: CmCell>>, pub vis: Visibility, /// Span of the visibility. @@ -320,7 +320,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && (vis == import_vis || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) { - max_vis.set(Some(vis.expect_local())) + // FIXME(batched): Will be fixed in batched import resolution. + max_vis.set_unchecked(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -349,7 +350,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - module.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + module.underscore_disambiguator.update_unchecked(|d| d + 1); module.underscore_disambiguator.get() }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { @@ -482,7 +484,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else { + let Ok(glob_importers) = module.glob_importers.try_borrow_mut_unchecked() else { return t; }; @@ -862,7 +864,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - import.imported_module.set(Some(module)); + // FIXME(batched): Will be fixed in batched import resolution. + import.imported_module.set_unchecked(Some(module)); let (source, target, bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { (source, target, bindings, type_ns_only) @@ -937,7 +940,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PendingBinding::Pending } }; - bindings[ns].set(binding); + // FIXME(batched): Will be fixed in batched import resolution. + bindings[ns].set_unchecked(binding); } }); @@ -1508,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Add to module's glob_importers - module.glob_importers.borrow_mut().push(import); + module.glob_importers.borrow_mut_unchecked().push(import); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. @@ -1550,7 +1554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // reporting conflicts, and reporting unresolved imports. fn finalize_resolutions_in(&mut self, module: Module<'ra>) { // Since import resolution is finished, globs will not define any more names. - *module.globs.borrow_mut() = Vec::new(); + *module.globs.borrow_mut(self) = Vec::new(); let Some(def_id) = module.opt_def_id() else { return }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0dea6ae33273..245bcdac81e8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -19,6 +19,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(ptr_as_ref_unchecked)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] @@ -26,7 +27,7 @@ use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeSet; -use std::fmt; +use std::fmt::{self}; use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; @@ -95,6 +96,8 @@ pub mod rustdoc; pub use macros::registered_tools_ast; +use crate::ref_mut::{CmCell, CmRefCell}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] @@ -592,22 +595,22 @@ struct ModuleData<'ra> { /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Cell, + populate_on_access: Cell, // FIXME(parallel): Use an atomic in parallel import resolution /// Used to disambiguate underscore items (`const _: T = ...`) in the module. - underscore_disambiguator: Cell, + underscore_disambiguator: CmCell, /// Macro invocations that can expand into items in this module. - unexpanded_invocations: RefCell>, + unexpanded_invocations: CmRefCell>, /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - glob_importers: RefCell>>, - globs: RefCell>>, + glob_importers: CmRefCell>>, + globs: CmRefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. traits: - RefCell, Option>)]>>>, + CmRefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -656,12 +659,12 @@ impl<'ra> ModuleData<'ra> { kind, lazy_resolutions: Default::default(), populate_on_access: Cell::new(is_foreign), - underscore_disambiguator: Cell::new(0), + underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, - glob_importers: RefCell::new(Vec::new()), - globs: RefCell::new(Vec::new()), - traits: RefCell::new(None), + glob_importers: CmRefCell::new(Vec::new()), + globs: CmRefCell::new(Vec::new()), + traits: CmRefCell::new(None), span, expansion, self_binding, @@ -696,7 +699,7 @@ impl<'ra> Module<'ra> { /// This modifies `self` in place. The traits will be stored in `self.traits`. fn ensure_traits<'tcx>(self, resolver: &impl AsRef>) { - let mut traits = self.traits.borrow_mut(); + let mut traits = self.traits.borrow_mut(resolver.as_ref()); if traits.is_none() { let mut collected_traits = Vec::new(); self.for_each_child(resolver, |r, name, ns, binding| { @@ -1974,6 +1977,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { + // FIXME(batched): Will be fixed in batched import resolution. module.populate_on_access.set(false); self.build_reduced_graph_external(module); } @@ -2502,9 +2506,20 @@ pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } +/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. +/// +/// `Cm` stands for "conditionally mutable". +/// +/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + mod ref_mut { + use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; + use std::fmt; use std::ops::Deref; + use crate::Resolver; + /// A wrapper around a mutable reference that conditionally allows mutable access. pub(crate) struct RefOrMut<'a, T> { p: &'a mut T, @@ -2553,11 +2568,86 @@ mod ref_mut { self.p } } -} -/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. -/// -/// `Cm` stands for "conditionally mutable". -/// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. -type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + /// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmCell(Cell); + + impl fmt::Debug for CmCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CmCell").field(&self.get()).finish() + } + } + + impl Clone for CmCell { + #[inline] + fn clone(&self) -> CmCell { + CmCell::new(self.get()) + } + } + + impl CmCell { + pub(crate) const fn get(&self) -> T { + self.0.get() + } + + pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + let old = self.get(); + self.set_unchecked(f(old)); + } + } + + impl CmCell { + pub(crate) const fn new(value: T) -> CmCell { + CmCell(Cell::new(value)) + } + + pub(crate) fn set_unchecked(&self, val: T) { + self.0.set(val); + } + + pub(crate) fn into_inner(self) -> T { + self.0.into_inner() + } + } + + /// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmRefCell(RefCell); + + impl CmRefCell { + pub(crate) const fn new(value: T) -> CmRefCell { + CmRefCell(RefCell::new(value)) + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { + self.0.borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { + if r.assert_speculative { + panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution"); + } + self.borrow_mut_unchecked() + } + + #[inline] + #[track_caller] + pub(crate) fn try_borrow_mut_unchecked(&self) -> Result, BorrowMutError> { + self.0.try_borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow(&self) -> Ref<'_, T> { + self.0.borrow() + } + } +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5fa87b4cd9b6..3b6ef88c5303 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -189,7 +189,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); + parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion); if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) { From 8ea9122c9b9465982424f7254a9cd88147e85642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 18:16:56 +0200 Subject: [PATCH 267/537] Rename `verbose` to `do_if_verbose` --- src/bootstrap/src/core/build_steps/compile.rs | 7 ++++--- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 6 +++--- src/bootstrap/src/core/builder/mod.rs | 4 ++-- src/bootstrap/src/core/config/config.rs | 6 +++--- src/bootstrap/src/core/download.rs | 18 ++++++++++-------- src/bootstrap/src/lib.rs | 10 +++++----- src/bootstrap/src/utils/build_stamp.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 10 +++++----- src/bootstrap/src/utils/exec.rs | 6 +++--- src/bootstrap/src/utils/render_tests.rs | 2 +- src/bootstrap/src/utils/tarball.rs | 2 +- 13 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index b47b4f248a9a..e699922f4dc0 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1832,8 +1832,9 @@ impl Step for Sysroot { let sysroot = sysroot_dir(compiler.stage); trace!(stage = ?compiler.stage, ?sysroot); - builder - .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display())); + builder.do_if_verbose(|| { + println!("Removing sysroot {} to avoid caching bugs", sysroot.display()) + }); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -2591,7 +2592,7 @@ pub fn stream_cargo( cmd.arg(arg); } - builder.verbose(|| println!("running: {cmd:?}")); + builder.do_if_verbose(|| println!("running: {cmd:?}")); let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 99a1062109ad..b79d2cb413db 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2304,7 +2304,7 @@ fn maybe_install_llvm( let mut cmd = command(host_llvm_config); cmd.cached(); cmd.arg("--libfiles"); - builder.verbose(|| println!("running {cmd:?}")); + builder.do_if_verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.host_target); let target_llvm_out = &builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 717dea37e9e6..17ab8c4e2f47 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -128,7 +128,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option\n". let sysroot = stdout.trim_end(); - builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); PathBuf::from(sysroot) } } @@ -2675,7 +2675,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> return true; } - builder.verbose(|| println!("doc tests for: {}", markdown.display())); + builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); // allow for unstable options such as new editions diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8226b4325b6b..049d2647bec4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -545,7 +545,7 @@ impl StepDescription { if !builder.config.skip.is_empty() && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck) { - builder.verbose(|| { + builder.do_if_verbose(|| { println!( "{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.skip @@ -947,7 +947,7 @@ impl Step for Libdir { // Sysroot`). if !builder.download_rustc() { let sysroot_target_libdir = sysroot.join(self.target).join("lib"); - builder.verbose(|| { + builder.do_if_verbose(|| { eprintln!( "Removing sysroot {} to avoid caching bugs", sysroot_target_libdir.display() diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index dd2d5a1fd533..fb7c334491b3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1571,8 +1571,8 @@ impl Config { } /// Runs a function if verbosity is greater than 0 - pub fn verbose(&self, f: impl Fn()) { - self.exec_ctx.verbose(f); + pub fn do_if_verbose(&self, f: impl Fn()) { + self.exec_ctx.do_if_verbose(f); } pub fn any_sanitizers_to_build(&self) -> bool { @@ -2061,7 +2061,7 @@ pub fn download_ci_rustc_commit<'a>( // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { eprintln!("rustc freshness: {freshness:?}"); }); match freshness { diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 2f3c80559c0e..37871f0fe1e2 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -106,7 +106,7 @@ enum DownloadSource { /// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { - self.verbose(|| println!("downloading stage0 clippy artifacts")); + self.do_if_verbose(|| println!("downloading stage0 clippy artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -151,7 +151,9 @@ impl Config { } pub(crate) fn download_ci_rustc(&self, commit: &str) { - self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})")); + self.do_if_verbose(|| { + println!("using downloaded stage2 artifacts from CI (commit {commit})") + }); let version = self.artifact_version_part(commit); // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the @@ -258,7 +260,7 @@ impl Config { let llvm_root = self.ci_llvm_root(); let llvm_freshness = detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository()); - self.verbose(|| { + self.do_if_verbose(|| { eprintln!("LLVM freshness: {llvm_freshness:?}"); }); let llvm_sha = match llvm_freshness { @@ -557,7 +559,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef(dwn_ctx: impl AsRef>, out: &Path) { let dwn_ctx = dwn_ctx.as_ref(); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!("downloading stage0 beta artifacts"); }); @@ -812,7 +814,7 @@ fn download_component<'a>( unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix); return; } else { - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!( "ignoring cached file {} due to failed verification", tarball.display() @@ -853,7 +855,7 @@ download-rustc = false pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) -> bool { use sha2::Digest; - exec_ctx.verbose(|| { + exec_ctx.do_if_verbose(|| { println!("verifying {}", path.display()); }); @@ -934,7 +936,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str short_path = short_path.strip_prefix(pattern).unwrap_or(short_path); let dst_path = dst.join(short_path); - exec_ctx.verbose(|| { + exec_ctx.do_if_verbose(|| { println!("extracting {} to {}", original_path.display(), dst.display()); }); @@ -965,7 +967,7 @@ fn download_file<'a>( ) { let dwn_ctx = dwn_ctx.as_ref(); - dwn_ctx.exec_ctx.verbose(|| { + dwn_ctx.exec_ctx.do_if_verbose(|| { println!("download {url}"); }); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 75cc79e6689c..4f4d35673d5d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -415,7 +415,7 @@ macro_rules! forward { } forward! { - verbose(f: impl Fn()), + do_if_verbose(f: impl Fn()), is_verbose() -> bool, create(path: &Path, s: &str), remove(f: &Path), @@ -601,11 +601,11 @@ impl Build { .unwrap() .trim(); if local_release.split('.').take(2).eq(version.split('.').take(2)) { - build.verbose(|| println!("auto-detected local-rebuild {local_release}")); + build.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}")); build.local_rebuild = true; } - build.verbose(|| println!("finding compilers")); + build.do_if_verbose(|| println!("finding compilers")); utils::cc_detect::fill_compilers(&mut build); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is @@ -613,7 +613,7 @@ impl Build { // // Similarly, for `setup` we don't actually need submodules or cargo metadata. if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.verbose(|| println!("running sanity check")); + build.do_if_verbose(|| println!("running sanity check")); crate::core::sanity::check(&mut build); // Make sure we update these before gathering metadata so we don't get an error about missing @@ -631,7 +631,7 @@ impl Build { // Now, update all existing submodules. build.update_existing_submodules(); - build.verbose(|| println!("learning about cargo")); + build.do_if_verbose(|| println!("learning about cargo")); crate::core::metadata::build(&mut build); } diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 4c35388a181a..5cd68f6d4fe7 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -112,7 +112,7 @@ pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool { let stamp = BuildStamp::new(dir); let mut cleared = false; if mtime(stamp.path()) < mtime(input) { - builder.verbose(|| println!("Dirty - {}", dir.display())); + builder.do_if_verbose(|| println!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); cleared = true; } else if stamp.path().exists() { diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index d3926df9650c..0662ae304ac0 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -137,16 +137,16 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { build.cxx.insert(target, compiler); } - build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); - build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); + build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); + build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); if let Ok(cxx) = build.cxx(target) { let mut cxxflags = build.cc_handled_clags(target, CLang::Cxx); cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); - build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); - build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); + build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); + build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); } if let Some(ar) = ar { - build.verbose(|| println!("AR_{} = {ar:?}", target.triple)); + build.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple)); build.ar.insert(target, ar); } diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index e09f3086b777..f875e6e1af75 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -630,7 +630,7 @@ impl ExecutionContext { &self.dry_run } - pub fn verbose(&self, f: impl Fn()) { + pub fn do_if_verbose(&self, f: impl Fn()) { if self.is_verbose() { f() } @@ -686,7 +686,7 @@ impl ExecutionContext { if let Some(cached_output) = self.command_cache.get(&fingerprint) { command.mark_as_executed(); - self.verbose(|| println!("Cache hit: {command:?}")); + self.do_if_verbose(|| println!("Cache hit: {command:?}")); self.profiler.record_cache_hit(fingerprint); return DeferredCommand { state: CommandState::Cached(cached_output) }; } @@ -713,7 +713,7 @@ impl ExecutionContext { }; } - self.verbose(|| { + self.do_if_verbose(|| { println!("running: {command:?} (created at {created_at}, executed at {executed_at})") }); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 90fd57d976d3..e90a7ef42324 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -48,7 +48,7 @@ pub(crate) fn try_run_tests( } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - builder.verbose(|| println!("running: {cmd:?}")); + builder.do_if_verbose(|| println!("running: {cmd:?}")); let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else { return true; diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 7b77b2129341..079afb7a0054 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -356,7 +356,7 @@ impl<'a> Tarball<'a> { // For `x install` tarball files aren't needed, so we can speed up the process by not producing them. let compression_profile = if self.builder.kind == Kind::Install { - self.builder.verbose(|| { + self.builder.do_if_verbose(|| { println!("Forcing dist.compression-profile = 'no-op' for `x install`.") }); // "no-op" indicates that the rust-installer won't produce compressed tarball sources. From a2d286992409d8077a03e0994a3839abdbfccc90 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 24 Sep 2025 09:56:57 -0700 Subject: [PATCH 268/537] Add `clippy::unconditional_recursion` to `./x clippy ci` The clippy lint catches some things that rustc's equivalent builtin lint does not, for example rust-lang/rust#146940: error: function cannot return without recursing --> library/std/src/path.rs:3428:5 | 3428 | / fn eq(&self, other: &String) -> bool { 3429 | | self == &*other 3430 | | } | |_____^ | note: recursive call site --> library/std/src/path.rs:3429:9 | 3429 | self == &*other | ^^^^^^^^^^^^^^^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion = note: requested on the command line with `-D clippy::unconditional-recursion` --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 2083c675e1fd..d5b15d790864 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -564,6 +564,7 @@ impl Step for CI { "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), "clippy::to_string_in_format_args".into(), + "clippy::unconditional_recursion".into(), ], forbid: vec![], }; @@ -591,6 +592,7 @@ impl Step for CI { "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), "clippy::to_string_in_format_args".into(), + "clippy::unconditional_recursion".into(), ], forbid: vec![], }; From f89660e4aa018401ca993f0df190e5f4c4a6799b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 1 Aug 2025 21:55:11 +0300 Subject: [PATCH 269/537] resolve: Do not finalize shadowed bindings I.e. do not mark them as used, or non-speculative loaded, or similar. Previously they were sometimes finalized during early resolution, causing issues like https://github.com/rust-lang/rust/pull/144793#issuecomment-3168108005. --- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 11 ++++++----- library/alloctests/tests/lib.rs | 1 - library/std/src/sys/pal/unix/stack_overflow.rs | 2 +- src/tools/clippy/tests/ui/useless_attribute.fixed | 2 +- src/tools/clippy/tests/ui/useless_attribute.rs | 2 +- .../crates/hir-expand/src/builtin/derive_macro.rs | 2 +- .../crates/hir-expand/src/builtin/fn_macro.rs | 2 +- .../crates/hir-expand/src/builtin/quote.rs | 2 -- src/tools/rustfmt/src/config/mod.rs | 1 - tests/ui/resolve/unused-macro-import.rs | 13 +++++++++++++ tests/ui/resolve/unused-macro-import.stderr | 14 ++++++++++++++ 12 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 tests/ui/resolve/unused-macro-import.rs create mode 100644 tests/ui/resolve/unused-macro-import.stderr diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 5821ffa3a302..5d32950875ad 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -5,7 +5,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced, - parenthesized, parse_macro_input, parse_quote, token, + parenthesized, parse_macro_input, token, }; mod kw { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 35051675fd8d..51489019950a 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -492,14 +492,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::Module(module, derive_fallback_lint_id) => { - // FIXME: use `finalize_scope` here. let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) + (parent_scope, finalize_scope!()) } else { ( &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), + finalize_scope!().map(|f| Finalize { used: Used::Scope, ..f }), ) }; let binding = this.reborrow().resolve_ident_in_module_unadjusted( @@ -557,8 +556,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { - // FIXME: use `finalize_scope` here. - match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { + match this + .reborrow() + .extern_prelude_get_item(ident, finalize_scope!().is_some()) + { Some(binding) => { extern_prelude_item_binding = Some(binding); Ok((binding, Flags::empty())) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 8c3ce156f3c1..4947b38ba89e 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -46,7 +46,6 @@ #![deny(unsafe_op_in_unsafe_fn)] extern crate alloc; -extern crate test; use std::hash::{DefaultHasher, Hash, Hasher}; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0d2100d66bc0..51463eef5b77 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -72,7 +72,7 @@ mod imp { use crate::sync::OnceLock; use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering}; use crate::sys::pal::unix::os; - use crate::{io, mem, panic, ptr}; + use crate::{io, mem, ptr}; // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages // (unmapped pages) at the end of every thread's stack, so if a thread ends diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index 15070dd9c2ca..e0bc23e0788c 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -153,7 +153,7 @@ pub mod redundant_imports_issue { () => {}; } - #[expect(redundant_imports)] + #[expect(unused_imports)] pub(crate) use empty; empty!(); diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 3f530de7fd8e..30a4c354b238 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -153,7 +153,7 @@ pub mod redundant_imports_issue { () => {}; } - #[expect(redundant_imports)] + #[expect(unused_imports)] pub(crate) use empty; empty!(); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs index 15e68ff95cd5..0fa412ad7fa2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs @@ -12,7 +12,7 @@ use tracing::debug; use crate::{ ExpandError, ExpandResult, MacroCallId, - builtin::quote::{dollar_crate, quote}, + builtin::quote::dollar_crate, db::ExpandDatabase, hygiene::span_with_def_site_ctxt, name::{self, AsName, Name}, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index ec3446137616..6fe63f249cd4 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -19,7 +19,7 @@ use syntax_bridge::syntax_node_to_token_tree; use crate::{ EditionedFileId, ExpandError, ExpandResult, Lookup as _, MacroCallId, - builtin::quote::{WithDelimiter, dollar_crate, quote}, + builtin::quote::{WithDelimiter, dollar_crate}, db::ExpandDatabase, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, name, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs index 70c38d4d7c75..84dd4a24d901 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs @@ -229,8 +229,6 @@ mod tests { use span::{Edition, ROOT_ERASED_FILE_AST_ID, SpanAnchor, SyntaxContext}; use syntax::{TextRange, TextSize}; - use super::quote; - const DUMMY: tt::Span = tt::Span { range: TextRange::empty(TextSize::new(0)), anchor: SpanAnchor { diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index 6b63108c037e..525953bf4458 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -516,7 +516,6 @@ mod test { #[allow(dead_code)] mod mock { use super::super::*; - use crate::config_option_with_style_edition_default; use rustfmt_config_proc_macro::config_type; #[config_type] diff --git a/tests/ui/resolve/unused-macro-import.rs b/tests/ui/resolve/unused-macro-import.rs new file mode 100644 index 000000000000..e85f7a43993f --- /dev/null +++ b/tests/ui/resolve/unused-macro-import.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![warn(unused_imports)] + +#[macro_export] +macro_rules! mac { () => {} } + +fn main() { + // Unused, `mac` as `macro_rules!` is already in scope and has higher priority. + use crate::mac; //~ WARN unused import: `crate::mac` + + mac!(); +} diff --git a/tests/ui/resolve/unused-macro-import.stderr b/tests/ui/resolve/unused-macro-import.stderr new file mode 100644 index 000000000000..5f9813808a0a --- /dev/null +++ b/tests/ui/resolve/unused-macro-import.stderr @@ -0,0 +1,14 @@ +warning: unused import: `crate::mac` + --> $DIR/unused-macro-import.rs:10:9 + | +LL | use crate::mac; + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-macro-import.rs:3:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: 1 warning emitted + From 9316d4508c42d5e6d91480aec34f66462801ee5d Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Thu, 25 Sep 2025 20:36:58 +0200 Subject: [PATCH 270/537] Remove most `#[track_caller]` from allocating Vec methods They cause significant binary size overhead while contributing little value. Also removes them from the wrapping String methods that do not panic. --- .../alloc/src/collections/vec_deque/mod.rs | 27 ------------- .../src/collections/vec_deque/spec_extend.rs | 6 --- .../collections/vec_deque/spec_from_iter.rs | 1 - library/alloc/src/raw_vec/mod.rs | 17 --------- library/alloc/src/string.rs | 13 ------- library/alloc/src/vec/cow.rs | 1 - library/alloc/src/vec/in_place_collect.rs | 2 - library/alloc/src/vec/mod.rs | 38 ------------------- library/alloc/src/vec/spec_extend.rs | 6 --- library/alloc/src/vec/spec_from_elem.rs | 4 -- library/alloc/src/vec/spec_from_iter.rs | 2 - .../alloc/src/vec/spec_from_iter_nested.rs | 2 - library/alloc/src/vec/splice.rs | 2 - tests/ui/hygiene/panic-location.run.stderr | 2 +- 14 files changed, 1 insertion(+), 122 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index d589860524b8..ac619a42d356 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -103,7 +103,6 @@ pub struct VecDeque< #[stable(feature = "rust1", since = "1.0.0")] impl Clone for VecDeque { - #[track_caller] fn clone(&self) -> Self { let mut deq = Self::with_capacity_in(self.len(), self.allocator().clone()); deq.extend(self.iter().cloned()); @@ -114,7 +113,6 @@ impl Clone for VecDeque { /// /// This method is preferred over simply assigning `source.clone()` to `self`, /// as it avoids reallocation if possible. - #[track_caller] fn clone_from(&mut self, source: &Self) { self.clear(); self.extend(source.iter().cloned()); @@ -577,7 +575,6 @@ impl VecDeque { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[track_caller] pub fn with_capacity(capacity: usize) -> VecDeque { Self::with_capacity_in(capacity, Global) } @@ -633,7 +630,6 @@ impl VecDeque { /// let deque: VecDeque = VecDeque::with_capacity(10); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque { VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) } } @@ -799,7 +795,6 @@ impl VecDeque { /// /// [`reserve`]: VecDeque::reserve #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); let old_cap = self.capacity(); @@ -830,7 +825,6 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_reserve")] - #[track_caller] pub fn reserve(&mut self, additional: usize) { let new_cap = self.len.checked_add(additional).expect("capacity overflow"); let old_cap = self.capacity(); @@ -962,7 +956,6 @@ impl VecDeque { /// assert!(buf.capacity() >= 4); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] - #[track_caller] pub fn shrink_to_fit(&mut self) { self.shrink_to(0); } @@ -988,7 +981,6 @@ impl VecDeque { /// assert!(buf.capacity() >= 4); /// ``` #[stable(feature = "shrink_to", since = "1.56.0")] - #[track_caller] pub fn shrink_to(&mut self, min_capacity: usize) { let target_cap = min_capacity.max(self.len); @@ -1891,7 +1883,6 @@ impl VecDeque { /// assert_eq!(d.front(), Some(&2)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn push_front(&mut self, value: T) { let _ = self.push_front_mut(value); } @@ -1910,7 +1901,6 @@ impl VecDeque { /// assert_eq!(d.front(), Some(&7)); /// ``` #[unstable(feature = "push_mut", issue = "135974")] - #[track_caller] #[must_use = "if you don't need a reference to the value, use `VecDeque::push_front` instead"] pub fn push_front_mut(&mut self, value: T) -> &mut T { if self.is_full() { @@ -1937,7 +1927,6 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "put", "append")] - #[track_caller] pub fn push_back(&mut self, value: T) { let _ = self.push_back_mut(value); } @@ -1956,7 +1945,6 @@ impl VecDeque { /// assert_eq!(d.back(), Some(&10)); /// ``` #[unstable(feature = "push_mut", issue = "135974")] - #[track_caller] #[must_use = "if you don't need a reference to the value, use `VecDeque::push_back` instead"] pub fn push_back_mut(&mut self, value: T) -> &mut T { if self.is_full() { @@ -2071,7 +2059,6 @@ impl VecDeque { /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c', 'e']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] - #[track_caller] pub fn insert(&mut self, index: usize, value: T) { let _ = self.insert_mut(index, value); } @@ -2099,7 +2086,6 @@ impl VecDeque { /// assert_eq!(vec_deque, &[1, 12, 2, 3]); /// ``` #[unstable(feature = "push_mut", issue = "135974")] - #[track_caller] #[must_use = "if you don't need a reference to the value, use `VecDeque::insert` instead"] pub fn insert_mut(&mut self, index: usize, value: T) -> &mut T { assert!(index <= self.len(), "index out of bounds"); @@ -2205,7 +2191,6 @@ impl VecDeque { #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] - #[track_caller] pub fn split_off(&mut self, at: usize) -> Self where A: Clone, @@ -2272,7 +2257,6 @@ impl VecDeque { /// ``` #[inline] #[stable(feature = "append", since = "1.4.0")] - #[track_caller] pub fn append(&mut self, other: &mut Self) { if T::IS_ZST { self.len = self.len.checked_add(other.len).expect("capacity overflow"); @@ -2395,7 +2379,6 @@ impl VecDeque { // be called in cold paths. // This may panic or abort #[inline(never)] - #[track_caller] fn grow(&mut self) { // Extend or possibly remove this assertion when valid use-cases for growing the // buffer without it being full emerge @@ -2434,7 +2417,6 @@ impl VecDeque { /// assert_eq!(buf, [5, 10, 101, 102, 103]); /// ``` #[stable(feature = "vec_resize_with", since = "1.33.0")] - #[track_caller] pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut() -> T) { let len = self.len; @@ -2981,7 +2963,6 @@ impl VecDeque { /// assert_eq!(buf, [5, 10, 20, 20, 20]); /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] - #[track_caller] pub fn resize(&mut self, new_len: usize, value: T) { if new_len > self.len() { let extra = new_len - self.len(); @@ -3101,7 +3082,6 @@ impl IndexMut for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for VecDeque { - #[track_caller] fn from_iter>(iter: I) -> VecDeque { SpecFromIter::spec_from_iter(iter.into_iter()) } @@ -3141,19 +3121,16 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for VecDeque { - #[track_caller] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()); } #[inline] - #[track_caller] fn extend_one(&mut self, elem: T) { self.push_back(elem); } #[inline] - #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3169,19 +3146,16 @@ impl Extend for VecDeque { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque { - #[track_caller] fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()); } #[inline] - #[track_caller] fn extend_one(&mut self, &elem: &'a T) { self.push_back(elem); } #[inline] - #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3279,7 +3253,6 @@ impl From<[T; N]> for VecDeque { /// let deq2: VecDeque<_> = [1, 2, 3, 4].into(); /// assert_eq!(deq1, deq2); /// ``` - #[track_caller] fn from(arr: [T; N]) -> Self { let mut deq = VecDeque::with_capacity(N); let arr = ManuallyDrop::new(arr); diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index 7c7072c4c3a1..6c2199135e08 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -8,7 +8,6 @@ use crate::vec; // Specialization trait used for VecDeque::extend pub(super) trait SpecExtend { - #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -16,7 +15,6 @@ impl SpecExtend for VecDeque where I: Iterator, { - #[track_caller] default fn spec_extend(&mut self, mut iter: I) { // This function should be the moral equivalent of: // @@ -47,7 +45,6 @@ impl SpecExtend for VecDeque where I: TrustedLen, { - #[track_caller] default fn spec_extend(&mut self, iter: I) { // This is the case for a TrustedLen iterator. let (low, high) = iter.size_hint(); @@ -81,7 +78,6 @@ where #[cfg(not(test))] impl SpecExtend> for VecDeque { - #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); self.reserve(slice.len()); @@ -99,7 +95,6 @@ where I: Iterator, T: Copy, { - #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.copied()) } @@ -109,7 +104,6 @@ impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for VecDeque where T: Copy, { - #[track_caller] fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); self.reserve(slice.len()); diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs index c80a30c2103d..557666ea3b87 100644 --- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs +++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs @@ -9,7 +9,6 @@ impl SpecFromIter for VecDeque where I: Iterator, { - #[track_caller] default fn spec_from_iter(iterator: I) -> Self { // Since converting is O(1) now, just re-use the `Vec` logic for // anything where we can't do something extra-special for `VecDeque`, diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 1d4a1f592a99..bc9692f5b6c2 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -24,7 +24,6 @@ mod tests; // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] #[cfg_attr(not(panic = "immediate-abort"), inline(never))] -#[track_caller] fn capacity_overflow() -> ! { panic!("capacity overflow"); } @@ -123,7 +122,6 @@ impl RawVec { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] - #[track_caller] pub(crate) fn with_capacity(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData } } @@ -132,7 +130,6 @@ impl RawVec { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] - #[track_caller] pub(crate) fn with_capacity_zeroed(capacity: usize) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT), @@ -145,7 +142,6 @@ impl RawVecInner { #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] - #[track_caller] fn with_capacity(capacity: usize, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global, elem_layout) { Ok(res) => res, @@ -186,7 +182,6 @@ impl RawVec { /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), @@ -208,7 +203,6 @@ impl RawVec { /// of allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] pub(crate) fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT), @@ -328,7 +322,6 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] pub(crate) fn reserve(&mut self, len: usize, additional: usize) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.reserve(len, additional, T::LAYOUT) } @@ -338,7 +331,6 @@ impl RawVec { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] - #[track_caller] pub(crate) fn grow_one(&mut self) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.grow_one(T::LAYOUT) } @@ -372,7 +364,6 @@ impl RawVec { /// /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] - #[track_caller] pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.reserve_exact(len, additional, T::LAYOUT) } @@ -399,7 +390,6 @@ impl RawVec { /// /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] - #[track_caller] #[inline] pub(crate) fn shrink_to_fit(&mut self, cap: usize) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout @@ -425,7 +415,6 @@ impl RawVecInner
{ #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { @@ -450,7 +439,6 @@ impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { Ok(res) => res, @@ -553,7 +541,6 @@ impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] unsafe fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) { // Callers expect this function to be very cheap when there is already sufficient capacity. // Therefore, we move all the resizing and error-handling logic from grow_amortized and @@ -585,7 +572,6 @@ impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] unsafe fn grow_one(&mut self, elem_layout: Layout) { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { @@ -621,7 +607,6 @@ impl RawVecInner { /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] - #[track_caller] unsafe fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.try_reserve_exact(len, additional, elem_layout) } { @@ -659,7 +644,6 @@ impl RawVecInner { /// - `cap` must be less than or equal to `self.capacity(elem_layout.size())` #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] unsafe fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) { if let Err(err) = unsafe { self.shrink(cap, elem_layout) } { handle_error(err); @@ -872,7 +856,6 @@ where #[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] -#[track_caller] fn handle_error(e: TryReserveError) -> ! { match e.kind() { CapacityOverflow => capacity_overflow(), diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e669c4708ad0..ae30cabf5af5 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1105,7 +1105,6 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] #[rustc_diagnostic_item = "string_push_str"] @@ -1208,7 +1207,6 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) @@ -1260,7 +1258,6 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) } @@ -1356,7 +1353,6 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { self.vec.shrink_to_fit() @@ -1384,7 +1380,6 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.vec.shrink_to(min_capacity) @@ -1406,7 +1401,6 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn push(&mut self, ch: char) { let len = self.len(); let ch_len = ch.len_utf8(); @@ -2115,7 +2109,6 @@ impl String { #[stable(feature = "box_str", since = "1.4.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] - #[track_caller] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); unsafe { from_boxed_utf8_unchecked(slice) } @@ -2293,7 +2286,6 @@ impl Error for FromUtf16Error {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { - #[track_caller] fn clone(&self) -> Self { String { vec: self.vec.clone() } } @@ -2302,7 +2294,6 @@ impl Clone for String { /// /// This method is preferred over simply assigning `source.clone()` to `self`, /// as it avoids reallocation if possible. - #[track_caller] fn clone_from(&mut self, source: &Self) { self.vec.clone_from(&source.vec); } @@ -2477,13 +2468,11 @@ impl<'a> Extend> for String { #[unstable(feature = "ascii_char", issue = "110998")] impl Extend for String { #[inline] - #[track_caller] fn extend>(&mut self, iter: I) { self.vec.extend(iter.into_iter().map(|c| c.to_u8())); } #[inline] - #[track_caller] fn extend_one(&mut self, c: core::ascii::Char) { self.vec.push(c.to_u8()); } @@ -2493,13 +2482,11 @@ impl Extend for String { #[unstable(feature = "ascii_char", issue = "110998")] impl<'a> Extend<&'a core::ascii::Char> for String { #[inline] - #[track_caller] fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } #[inline] - #[track_caller] fn extend_one(&mut self, c: &'a core::ascii::Char) { self.vec.push(c.to_u8()); } diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 4deb35efffc1..c18091705a63 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -58,7 +58,6 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone, { - #[track_caller] fn from_iter>(it: I) -> Cow<'a, [T]> { Cow::Owned(FromIterator::from_iter(it)) } diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index b98a118048f2..8a7c0b92eccf 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -229,7 +229,6 @@ where I: Iterator + InPlaceCollect, ::Source: AsVecIntoIter, { - #[track_caller] default fn from_iter(iterator: I) -> Self { // Select the implementation in const eval to avoid codegen of the dead branch to improve compile times. let fun: fn(I) -> Vec = const { @@ -247,7 +246,6 @@ where } } -#[track_caller] fn from_iter_in_place(mut iterator: I) -> Vec where I: Iterator + InPlaceCollect, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ebdb86f98a85..81b405253a1b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -515,7 +515,6 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[rustc_diagnostic_item = "vec_with_capacity"] - #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -926,7 +925,6 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - #[track_caller] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } @@ -1335,7 +1333,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] #[rustc_diagnostic_item = "vec_reserve"] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); @@ -1367,7 +1364,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { self.buf.reserve_exact(self.len, additional); } @@ -1471,7 +1467,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] #[inline] pub fn shrink_to_fit(&mut self) { // The capacity is never less than the length, and there's nothing to do when @@ -1502,7 +1497,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "shrink_to", since = "1.56.0")] - #[track_caller] pub fn shrink_to(&mut self, min_capacity: usize) { if self.capacity() > min_capacity { self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); @@ -1536,7 +1530,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - #[track_caller] pub fn into_boxed_slice(mut self) -> Box<[T], A> { unsafe { self.shrink_to_fit(); @@ -2021,7 +2014,6 @@ impl Vec { pub fn swap_remove(&mut self, index: usize) -> T { #[cold] #[cfg_attr(not(panic = "immediate-abort"), inline(never))] - #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { panic!("swap_remove index (is {index}) should be < len (is {len})"); @@ -2540,7 +2532,6 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] - #[track_caller] pub fn push(&mut self, value: T) { let _ = self.push_mut(value); } @@ -2617,7 +2608,6 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "push_mut", issue = "135974")] - #[track_caller] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] pub fn push_mut(&mut self, value: T) -> &mut T { // Inform codegen that the length does not change across grow_one(). @@ -2765,7 +2755,6 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "append", since = "1.4.0")] - #[track_caller] pub fn append(&mut self, other: &mut Self) { unsafe { self.append_elements(other.as_slice() as _); @@ -2776,7 +2765,6 @@ impl Vec { /// Appends elements to `self` from other buffer. #[cfg(not(no_global_oom_handling))] #[inline] - #[track_caller] unsafe fn append_elements(&mut self, other: *const [T]) { let count = other.len(); self.reserve(count); @@ -3011,7 +2999,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize_with", since = "1.33.0")] - #[track_caller] pub fn resize_with(&mut self, new_len: usize, f: F) where F: FnMut() -> T, @@ -3276,7 +3263,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize", since = "1.5.0")] - #[track_caller] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -3307,7 +3293,6 @@ impl Vec { /// [`extend`]: Vec::extend #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] - #[track_caller] pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } @@ -3338,7 +3323,6 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_within", since = "1.53.0")] - #[track_caller] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -3399,7 +3383,6 @@ impl Vec<[T; N], A> { impl Vec { #[cfg(not(no_global_oom_handling))] - #[track_caller] /// Extend the vector by `n` clones of value. fn extend_with(&mut self, n: usize, value: T) { self.reserve(n); @@ -3460,7 +3443,6 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_from_elem"] -#[track_caller] pub fn from_elem(elem: T, n: usize) -> Vec { ::from_elem(elem, n, Global) } @@ -3468,7 +3450,6 @@ pub fn from_elem(elem: T, n: usize) -> Vec { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] -#[track_caller] pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { ::from_elem(elem, n, alloc) } @@ -3559,7 +3540,6 @@ unsafe impl ops::DerefPure for Vec {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { - #[track_caller] fn clone(&self) -> Self { let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) @@ -3587,7 +3567,6 @@ impl Clone for Vec { /// // And no reallocation occurred /// assert_eq!(yp, y.as_ptr()); /// ``` - #[track_caller] fn clone_from(&mut self, source: &Self) { crate::slice::SpecCloneIntoVec::clone_into(source.as_slice(), self); } @@ -3678,7 +3657,6 @@ impl, A: Allocator> IndexMut for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for Vec { #[inline] - #[track_caller] fn from_iter>(iter: I) -> Vec { >::from_iter(iter.into_iter()) } @@ -3747,19 +3725,16 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for Vec { #[inline] - #[track_caller] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) } #[inline] - #[track_caller] fn extend_one(&mut self, item: T) { self.push(item); } #[inline] - #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -3779,7 +3754,6 @@ impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply #[cfg(not(no_global_oom_handling))] - #[track_caller] fn extend_desugared>(&mut self, mut iterator: I) { // This is the case for a general iterator. // @@ -3807,7 +3781,6 @@ impl Vec { // specific extend for `TrustedLen` iterators, called both by the specializations // and internal places where resolving specialization makes compilation slower #[cfg(not(no_global_oom_handling))] - #[track_caller] fn extend_trusted(&mut self, iterator: impl iter::TrustedLen) { let (low, high) = iterator.size_hint(); if let Some(additional) = high { @@ -3985,19 +3958,16 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec { - #[track_caller] fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } #[inline] - #[track_caller] fn extend_one(&mut self, &item: &'a T) { self.push(item); } #[inline] - #[track_caller] fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } @@ -4108,7 +4078,6 @@ impl From<&[T]> for Vec { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[track_caller] fn from(s: &[T]) -> Vec { s.to_vec() } @@ -4124,7 +4093,6 @@ impl From<&mut [T]> for Vec { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[track_caller] fn from(s: &mut [T]) -> Vec { s.to_vec() } @@ -4140,7 +4108,6 @@ impl From<&[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); /// ``` - #[track_caller] fn from(s: &[T; N]) -> Vec { Self::from(s.as_slice()) } @@ -4156,7 +4123,6 @@ impl From<&mut [T; N]> for Vec { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); /// ``` - #[track_caller] fn from(s: &mut [T; N]) -> Vec { Self::from(s.as_mut_slice()) } @@ -4172,7 +4138,6 @@ impl From<[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` - #[track_caller] fn from(s: [T; N]) -> Vec { <[T]>::into_vec(Box::new(s)) } @@ -4197,7 +4162,6 @@ where /// let b: Cow<'_, [i32]> = Cow::Borrowed(&[1, 2, 3]); /// assert_eq!(Vec::from(o), Vec::from(b)); /// ``` - #[track_caller] fn from(s: Cow<'a, [T]>) -> Vec { s.into_owned() } @@ -4244,7 +4208,6 @@ impl From> for Box<[T], A> { /// /// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice()); /// ``` - #[track_caller] fn from(v: Vec) -> Self { v.into_boxed_slice() } @@ -4260,7 +4223,6 @@ impl From<&str> for Vec { /// ``` /// assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']); /// ``` - #[track_caller] fn from(s: &str) -> Vec { From::from(s.as_bytes()) } diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index b98db669059f..7085bceef5ba 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -6,7 +6,6 @@ use crate::alloc::Allocator; // Specialization trait used for Vec::extend pub(super) trait SpecExtend { - #[track_caller] fn spec_extend(&mut self, iter: I); } @@ -14,7 +13,6 @@ impl SpecExtend for Vec where I: Iterator, { - #[track_caller] default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } @@ -24,14 +22,12 @@ impl SpecExtend for Vec where I: TrustedLen, { - #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.extend_trusted(iterator) } } impl SpecExtend> for Vec { - #[track_caller] fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -45,7 +41,6 @@ where I: Iterator, T: Clone, { - #[track_caller] default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) } @@ -55,7 +50,6 @@ impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec) { let slice = iterator.as_slice(); unsafe { self.append_elements(slice) }; diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index 6c7b4d89f2da..96d701e15d48 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -10,7 +10,6 @@ pub(super) trait SpecFromElem: Sized { } impl SpecFromElem for T { - #[track_caller] default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, elem); @@ -20,7 +19,6 @@ impl SpecFromElem for T { impl SpecFromElem for T { #[inline] - #[track_caller] default fn from_elem(elem: T, n: usize, alloc: A) -> Vec { if elem.is_zero() { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; @@ -33,7 +31,6 @@ impl SpecFromElem for T { impl SpecFromElem for i8 { #[inline] - #[track_caller] fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; @@ -49,7 +46,6 @@ impl SpecFromElem for i8 { impl SpecFromElem for u8 { #[inline] - #[track_caller] fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index ad7688e1c59f..e1f0b639bdfd 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -29,14 +29,12 @@ impl SpecFromIter for Vec where I: Iterator, { - #[track_caller] default fn from_iter(iterator: I) -> Self { SpecFromIterNested::from_iter(iterator) } } impl SpecFromIter> for Vec { - #[track_caller] fn from_iter(iterator: IntoIter) -> Self { // A common case is passing a vector into a function which immediately // re-collects into a vector. We can short circuit this if the IntoIter diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs index 22eed238798c..77f7761d22f9 100644 --- a/library/alloc/src/vec/spec_from_iter_nested.rs +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -15,7 +15,6 @@ impl SpecFromIterNested for Vec where I: Iterator, { - #[track_caller] default fn from_iter(mut iterator: I) -> Self { // Unroll the first iteration, as the vector is going to be // expanded on this iteration in every case when the iterable is not @@ -48,7 +47,6 @@ impl SpecFromIterNested for Vec where I: TrustedLen, { - #[track_caller] fn from_iter(iterator: I) -> Self { let mut vector = match iterator.size_hint() { (_, Some(upper)) => Vec::with_capacity(upper), diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index ed1a0dda76d2..d571e35828ae 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -52,7 +52,6 @@ impl ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] impl Drop for Splice<'_, I, A> { - #[track_caller] fn drop(&mut self) { self.drain.by_ref().for_each(drop); // At this point draining is done and the only remaining tasks are splicing @@ -124,7 +123,6 @@ impl Drain<'_, T, A> { } /// Makes room for inserting more elements before the tail. - #[track_caller] unsafe fn move_tail(&mut self, additional: usize) { let vec = unsafe { self.vec.as_mut() }; let len = self.tail_start + self.tail_len; diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index d28ab8641834..bd74e96fd8cc 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,4 +1,4 @@ -thread 'main' ($TID) panicked at $DIR/panic-location.rs:LL:CC: +thread 'main' ($TID) panicked at library/alloc/src/raw_vec/mod.rs:LL:CC: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From c98b3b2da46146956b982e4ae1747c3614a461fd Mon Sep 17 00:00:00 2001 From: Akrm Al-Hakimi Date: Thu, 25 Sep 2025 13:57:59 -0400 Subject: [PATCH 271/537] const_caller_location: edit FIXME to explain use of `DUMMY_SP` Co-authored-by: Ralf Jung --- compiler/rustc_const_eval/src/util/caller_location.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 5249b32eca46..4e7c8310007b 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -61,7 +61,7 @@ pub(crate) fn const_caller_location_provider( trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx_to_read_const_val( tcx, - rustc_span::DUMMY_SP, // FIXME: use a proper span here? + rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant. ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); From b9037f97e38acc698af1260cad5d31ca07ac616a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 13:04:34 -0700 Subject: [PATCH 272/537] rustdoc-search: use the same ID for entry and path to same item This decreases the size of the compiler-doc from 57MiB to 56MiB. --- src/librustdoc/html/render/search_index.rs | 32 ++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 3ffce61f7c61..74cf2b181233 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -241,6 +241,26 @@ impl SerializedSearchIndex { self.alias_pointers.push(alias_pointer); index } + fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize { + let fqp = if let Some(module_path_index) = entry_data.module_path { + let mut fqp = self.path_data[module_path_index].as_ref().unwrap().module_path.clone(); + fqp.push(Symbol::intern(&self.names[module_path_index])); + fqp.push(name); + fqp + } else { + vec![name] + }; + if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp)) + && self.entry_data[other_path].is_none() + && self.descs[other_path].is_empty() + { + self.entry_data[other_path] = Some(entry_data); + self.descs[other_path] = desc; + other_path + } else { + self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None) + } + } fn push_path(&mut self, name: String, path_data: PathData) -> usize { self.push(name, Some(path_data), None, String::new(), None, None, None) } @@ -1516,10 +1536,9 @@ pub(crate) fn build_index( .as_ref() .map(|path| serialized_index.get_id_by_module_path(path)); - let new_entry_id = serialized_index.push( - item.name.as_str().to_string(), - None, - Some(EntryData { + let new_entry_id = serialized_index.add_entry( + item.name, + EntryData { ty: item.ty, parent: item.parent_idx, module_path, @@ -1538,11 +1557,8 @@ pub(crate) fn build_index( None }, krate: crate_idx, - }), + }, item.desc.to_string(), - None, // filled in after all the types have been indexed - None, - None, ); // Aliases From e0f22df8b9376c86496eb7facaadd7b27ef6e4a8 Mon Sep 17 00:00:00 2001 From: Oblarg Date: Thu, 25 Sep 2025 12:11:11 -0400 Subject: [PATCH 273/537] fix transcriber error in declarative macros for negative integer literal const generic params --- .../crates/mbe/src/expander/transcriber.rs | 14 ++- .../rust-analyzer/crates/mbe/src/tests.rs | 97 +++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 2c046df10f5e..3e4ab8bdc1d8 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -401,7 +401,19 @@ fn expand_var( let sub = sub.strip_invisible(); let mut span = id; marker(&mut span); - let wrap_in_parens = !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)]) + + // Check if this is a simple negative literal (MINUS + LITERAL) + // that should not be wrapped in parentheses + let is_negative_literal = matches!( + sub.flat_tokens(), + [ + tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })), + tt::TokenTree::Leaf(tt::Leaf::Literal(_)) + ] + ); + + let wrap_in_parens = !is_negative_literal + && !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)]) && sub.try_into_subtree().is_none_or(|it| { it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible }); diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs index 56034516ef3b..589e169d30a3 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -476,3 +476,100 @@ fn minus_belongs_to_literal() { --"#]], ); } + +#[test] +fn negative_literals_in_const_generics() { + // Test that negative literals work correctly in declarative macros + // when used as const generic arguments. The issue was that expressions + // like -1 would be wrapped in parentheses, creating invalid syntax + // Foo::<(-1)> instead of the correct Foo::<-1>. + let decl = r#" +($val:expr) => { + struct Foo { + pub value: i16, + } + + impl Foo { + pub fn new(value: i16) -> Self { + Self { value } + } + } + + Foo::<$val>::new($val) +}; +"#; + let check = |args, expect| check(Edition::CURRENT, Edition::CURRENT, decl, args, expect); + + // Test negative integer literal - should produce Foo::<-1>, not Foo::<(-1)> + check( + "-1", + expect![[r#" + SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024 + IDENT struct 0:Root[0000, 0]@22..28#ROOT2024 + IDENT Foo 0:Root[0000, 0]@29..32#ROOT2024 + PUNCH < [alone] 0:Root[0000, 0]@32..33#ROOT2024 + IDENT const 0:Root[0000, 0]@33..38#ROOT2024 + IDENT I 0:Root[0000, 0]@39..40#ROOT2024 + PUNCH : [alone] 0:Root[0000, 0]@40..41#ROOT2024 + IDENT i16 0:Root[0000, 0]@42..45#ROOT2024 + PUNCH > [alone] 0:Root[0000, 0]@45..46#ROOT2024 + SUBTREE {} 0:Root[0000, 0]@47..48#ROOT2024 0:Root[0000, 0]@77..78#ROOT2024 + IDENT pub 0:Root[0000, 0]@57..60#ROOT2024 + IDENT value 0:Root[0000, 0]@61..66#ROOT2024 + PUNCH : [alone] 0:Root[0000, 0]@66..67#ROOT2024 + IDENT i16 0:Root[0000, 0]@68..71#ROOT2024 + PUNCH , [alone] 0:Root[0000, 0]@71..72#ROOT2024 + IDENT impl 0:Root[0000, 0]@84..88#ROOT2024 + PUNCH < [alone] 0:Root[0000, 0]@88..89#ROOT2024 + IDENT const 0:Root[0000, 0]@89..94#ROOT2024 + IDENT I 0:Root[0000, 0]@95..96#ROOT2024 + PUNCH : [alone] 0:Root[0000, 0]@96..97#ROOT2024 + IDENT i16 0:Root[0000, 0]@98..101#ROOT2024 + PUNCH > [alone] 0:Root[0000, 0]@101..102#ROOT2024 + IDENT Foo 0:Root[0000, 0]@103..106#ROOT2024 + PUNCH < [alone] 0:Root[0000, 0]@106..107#ROOT2024 + IDENT I 0:Root[0000, 0]@107..108#ROOT2024 + PUNCH > [alone] 0:Root[0000, 0]@108..109#ROOT2024 + SUBTREE {} 0:Root[0000, 0]@110..111#ROOT2024 0:Root[0000, 0]@194..195#ROOT2024 + IDENT pub 0:Root[0000, 0]@120..123#ROOT2024 + IDENT fn 0:Root[0000, 0]@124..126#ROOT2024 + IDENT new 0:Root[0000, 0]@127..130#ROOT2024 + SUBTREE () 0:Root[0000, 0]@130..131#ROOT2024 0:Root[0000, 0]@141..142#ROOT2024 + IDENT value 0:Root[0000, 0]@131..136#ROOT2024 + PUNCH : [alone] 0:Root[0000, 0]@136..137#ROOT2024 + IDENT i16 0:Root[0000, 0]@138..141#ROOT2024 + PUNCH - [joint] 0:Root[0000, 0]@143..144#ROOT2024 + PUNCH > [alone] 0:Root[0000, 0]@144..145#ROOT2024 + IDENT Self 0:Root[0000, 0]@146..150#ROOT2024 + SUBTREE {} 0:Root[0000, 0]@151..152#ROOT2024 0:Root[0000, 0]@188..189#ROOT2024 + IDENT Self 0:Root[0000, 0]@165..169#ROOT2024 + SUBTREE {} 0:Root[0000, 0]@170..171#ROOT2024 0:Root[0000, 0]@178..179#ROOT2024 + IDENT value 0:Root[0000, 0]@172..177#ROOT2024 + IDENT Foo 0:Root[0000, 0]@201..204#ROOT2024 + PUNCH : [joint] 0:Root[0000, 0]@204..205#ROOT2024 + PUNCH : [joint] 0:Root[0000, 0]@205..206#ROOT2024 + PUNCH < [joint] 0:Root[0000, 0]@206..207#ROOT2024 + PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024 + LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024 + PUNCH > [joint] 0:Root[0000, 0]@211..212#ROOT2024 + PUNCH : [joint] 0:Root[0000, 0]@212..213#ROOT2024 + PUNCH : [alone] 0:Root[0000, 0]@213..214#ROOT2024 + IDENT new 0:Root[0000, 0]@214..217#ROOT2024 + SUBTREE () 0:Root[0000, 0]@217..218#ROOT2024 0:Root[0000, 0]@222..223#ROOT2024 + PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024 + LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024 + + struct Foo{ + pub value:i16, + } + impl Foo{ + pub fn new(value:i16) -> Self { + Self { + value + } + } + + } + Foo::<-1>::new(-1)"#]], + ); +} From 8daad494b11ae5d0e5282be485625687bcf27e37 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 14:13:26 -0700 Subject: [PATCH 274/537] rustdoc: put the toolbar on the all item index --- src/librustdoc/html/render/mod.rs | 7 ++++++- src/librustdoc/html/render/write_shared.rs | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6d684449b6d2..bb494de19d9b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -601,7 +601,12 @@ impl AllTypes { } fmt::from_fn(|f| { - f.write_str("

List of all items

")?; + f.write_str( + "
\ +

List of all items

\ + \ +
", + )?; // Note: print_entries does not escape the title, because we know the current set of titles // doesn't require escaping. print_entries(&self.structs, ItemSection::Structs).fmt(f)?; diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e37a5246a768..3a1db805d01c 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -386,8 +386,13 @@ impl CratesIndexPart { let layout = &cx.shared.layout; let style_files = &cx.shared.style_files; const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this - let content = - format!("

List of all crates

    {DELIMITER}
"); + let content = format!( + "
\ +

List of all crates

\ + \ +
\ +
    {DELIMITER}
" + ); let template = layout::render(layout, &page, "", content, style_files); SortedTemplate::from_template(&template, DELIMITER) .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page") From 0ede3fe48c0d373d3673459218e1b9e7eaa667b8 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:34:20 -0500 Subject: [PATCH 275/537] std: fix warning in VEXos stdio module --- library/std/src/sys/stdio/vexos.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs index 1f2251c6421d..9a391feb7a8a 100644 --- a/library/std/src/sys/stdio/vexos.rs +++ b/library/std/src/sys/stdio/vexos.rs @@ -13,7 +13,7 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut count = 0; for out_byte in buf.iter_mut() { From 9dce3e8556022599c1323cdad6a0d87d6991c8b5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 15:16:16 -0700 Subject: [PATCH 276/537] rustdoc-search: add descriptive comment to space-saving hack --- src/librustdoc/html/render/search_index.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 74cf2b181233..7b21c68d2e94 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -241,6 +241,9 @@ impl SerializedSearchIndex { self.alias_pointers.push(alias_pointer); index } + /// Add potential search result to the database and return the row ID. + /// + /// The returned ID can be used to attach more data to the search result. fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize { let fqp = if let Some(module_path_index) = entry_data.module_path { let mut fqp = self.path_data[module_path_index].as_ref().unwrap().module_path.clone(); @@ -250,6 +253,11 @@ impl SerializedSearchIndex { } else { vec![name] }; + // If a path with the same name already exists, but no entry does, + // we can fill in the entry without having to allocate a new row ID. + // + // Because paths and entries both share the same index, using the same + // ID saves space by making the tree smaller. if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp)) && self.entry_data[other_path].is_none() && self.descs[other_path].is_empty() From 7a9b6d94d41720a206d0e52e4827bac45d9a7bc3 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 25 Sep 2025 18:12:33 -0400 Subject: [PATCH 277/537] PassWrapper: update for new PGOOptions args in LLVM 22 This changed in upstream change a5569b4bd7f8. @rustbot label llvm-main --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 013d68fa3e48..136b6e9bf50f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -573,21 +573,37 @@ extern "C" LLVMRustResult LLVMRustOptimize( if (PGOGenPath) { assert(!PGOUsePath && !PGOSampleUsePath); PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + PGOGenPath, "", "", "", PGOOptions::IRInstr, PGOOptions::NoCSAction, +#else PGOGenPath, "", "", "", FS, PGOOptions::IRInstr, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (PGOUsePath) { assert(!PGOSampleUsePath); PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + PGOUsePath, "", "", "", PGOOptions::IRUse, PGOOptions::NoCSAction, +#else PGOUsePath, "", "", "", FS, PGOOptions::IRUse, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (PGOSampleUsePath) { PGOOpt = +#if LLVM_VERSION_GE(22, 0) + PGOOptions(PGOSampleUsePath, "", "", "", PGOOptions::SampleUse, +#else PGOOptions(PGOSampleUsePath, "", "", "", FS, PGOOptions::SampleUse, +#endif PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (DebugInfoForProfiling) { PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + "", "", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, +#else "", "", "", "", FS, PGOOptions::NoAction, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } From 51ae86dec97f4db86f624f609c41f6bf5e620301 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 25 Sep 2025 15:23:49 -0700 Subject: [PATCH 278/537] rustdoc-search: add test case for all/index.html search --- tests/rustdoc-gui/search-title.goml | 12 ++++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/tests/rustdoc-gui/search-title.goml b/tests/rustdoc-gui/search-title.goml index 83321a05f2bb..5808ed845a3b 100644 --- a/tests/rustdoc-gui/search-title.goml +++ b/tests/rustdoc-gui/search-title.goml @@ -20,3 +20,15 @@ assert-document-property: {"title": '"another one" Search - Rust'} press-key: "Escape" assert-document-property: {"title": |title|} + +// check that all.html does it correctly, too. +go-to: "file://" + |DOC_PATH| + "/test_docs/all.html" +assert-document-property: {"title": "List of all items in this crate"} +call-function: ("perform-search", {"query": "verify"}) +assert-document-property: {"title": '"verify" Search - Rust'} + +// check that index.html does it correctly, too. +go-to: "file://" + |DOC_PATH| + "/index.html" +assert-document-property: {"title": "Index of crates"} +call-function: ("perform-search", {"query": "verify"}) +assert-document-property: {"title": '"verify" Search - Rust'} diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 42f2fbd93b1e..08523d0df2f2 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -1,3 +1,4 @@ +//@ compile-flags: --enable-index-page -Z unstable-options //! The point of this crate is to be able to have enough different "kinds" of //! documentation generated so we can test each different features. #![doc(html_playground_url="https://play.rust-lang.org/")] From 1a37374973f2d57c7c1c18a8371aa99607adfad8 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 21 Sep 2025 03:46:07 +0000 Subject: [PATCH 279/537] JumpThreading: Avoid computing dominators to identify loop headers. --- .../rustc_mir_transform/src/jump_threading.rs | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index f9e642e28ebd..c69660108d9a 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { body, arena, map: Map::new(tcx, body, Some(MAX_PLACES)), - loop_headers: loop_headers(body), + maybe_loop_headers: maybe_loop_headers(body), opportunities: Vec::new(), }; @@ -100,7 +100,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { // Verify that we do not thread through a loop header. for to in opportunities.iter() { - assert!(to.chain.iter().all(|&block| !finder.loop_headers.contains(block))); + assert!(to.chain.iter().all(|&block| !finder.maybe_loop_headers.contains(block))); } OpportunitySet::new(body, opportunities).apply(body); } @@ -124,7 +124,7 @@ struct TOFinder<'a, 'tcx> { ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, map: Map<'tcx>, - loop_headers: DenseBitSet, + maybe_loop_headers: DenseBitSet, /// We use an arena to avoid cloning the slices when cloning `state`. arena: &'a DroplessArena, opportunities: Vec, @@ -190,7 +190,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { #[instrument(level = "trace", skip(self))] fn start_from_switch(&mut self, bb: BasicBlock) { let bbdata = &self.body[bb]; - if bbdata.is_cleanup || self.loop_headers.contains(bb) { + if bbdata.is_cleanup || self.maybe_loop_headers.contains(bb) { return; } let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return }; @@ -235,7 +235,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { depth: usize, ) { // Do not thread through loop headers. - if self.loop_headers.contains(bb) { + if self.maybe_loop_headers.contains(bb) { return; } @@ -833,20 +833,26 @@ enum Update { Decr, } -/// Compute the set of loop headers in the given body. We define a loop header as a block which has -/// at least a predecessor which it dominates. This definition is only correct for reducible CFGs. -/// But if the CFG is already irreducible, there is no point in trying much harder. -/// is already irreducible. -fn loop_headers(body: &Body<'_>) -> DenseBitSet { - let mut loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); - let dominators = body.basic_blocks.dominators(); - // Only visit reachable blocks. - for (bb, bbdata) in traversal::preorder(body) { +/// Compute the set of loop headers in the given body. A loop header is usually defined as a block +/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. +/// However, computing dominators is expensive, so we approximate according to the post-order +/// traversal order. A loop header for us is a block which is visited after its predecessor in +/// post-order. This is ok as we mostly need a heuristic. +fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { + let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); + let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); + for (bb, bbdata) in traversal::postorder(body) { + let _new = visited.insert(bb); + debug_assert!(_new); + + // Post-order means we visit successors before the block for acyclic CFGs. + // If the successor is not visited yet, consider it a loop header. for succ in bbdata.terminator().successors() { - if dominators.dominates(succ, bb) { - loop_headers.insert(succ); + if !visited.contains(succ) { + maybe_loop_headers.insert(succ); } } } - loop_headers + + maybe_loop_headers } From 5de617e71f7ab7f70f13381033c09f1c6ad55e0f Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 25 Sep 2025 23:57:59 -0400 Subject: [PATCH 280/537] Rename ui test items --- .../duplicate-bound-err.rs | 18 ++-- .../duplicate-bound-err.stderr | 24 ++--- .../associated-type-bounds/duplicate-bound.rs | 90 +++++++++---------- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 50db5de7ca76..01cc05f2545f 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -5,31 +5,31 @@ use std::iter; -fn frpit1() -> impl Iterator { +fn rpit1() -> impl Iterator { iter::empty() //~^ ERROR type annotations needed } -fn frpit2() -> impl Iterator { +fn rpit2() -> impl Iterator { iter::empty() //~^ ERROR type annotations needed } -fn frpit3() -> impl Iterator { +fn rpit3() -> impl Iterator { iter::empty() //~^ ERROR type annotations needed } -type ETAI1> = impl Copy; +type Tait1> = impl Copy; //~^ ERROR unconstrained opaque type -type ETAI2> = impl Copy; +type Tait2> = impl Copy; //~^ ERROR unconstrained opaque type -type ETAI3> = impl Copy; +type Tait3> = impl Copy; //~^ ERROR unconstrained opaque type -type ETAI4 = impl Iterator; +type Tait4 = impl Iterator; //~^ ERROR unconstrained opaque type -type ETAI5 = impl Iterator; +type Tait5 = impl Iterator; //~^ ERROR unconstrained opaque type -type ETAI6 = impl Iterator; +type Tait6 = impl Iterator; //~^ ERROR unconstrained opaque type fn mismatch() -> impl Iterator { diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 6c1dc03676c7..1737d0dc5a38 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -34,50 +34,50 @@ LL | iter::empty::() error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:21:51 | -LL | type ETAI1> = impl Copy; +LL | type Tait1> = impl Copy; | ^^^^^^^^^ | - = note: `ETAI1` must be used in combination with a concrete type within the same crate + = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:23:51 | -LL | type ETAI2> = impl Copy; +LL | type Tait2> = impl Copy; | ^^^^^^^^^ | - = note: `ETAI2` must be used in combination with a concrete type within the same crate + = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:25:57 | -LL | type ETAI3> = impl Copy; +LL | type Tait3> = impl Copy; | ^^^^^^^^^ | - = note: `ETAI3` must be used in combination with a concrete type within the same crate + = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:28:14 | -LL | type ETAI4 = impl Iterator; +LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `ETAI4` must be used in combination with a concrete type within the same crate + = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:30:14 | -LL | type ETAI5 = impl Iterator; +LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `ETAI5` must be used in combination with a concrete type within the same crate + = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type --> $DIR/duplicate-bound-err.rs:32:14 | -LL | type ETAI6 = impl Iterator; +LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `ETAI6` must be used in combination with a concrete type within the same crate + = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely --> $DIR/duplicate-bound-err.rs:35:18 diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 97b2b3905a55..696710d76f6d 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -7,84 +7,84 @@ use std::iter; use std::mem::ManuallyDrop; -struct SI1> { +struct Si1> { f: T, } -struct SI2> { +struct Si2> { f: T, } -struct SI3> { +struct Si3> { f: T, } -struct SW1 +struct Sw1 where T: Iterator, { f: T, } -struct SW2 +struct Sw2 where T: Iterator, { f: T, } -struct SW3 +struct Sw3 where T: Iterator, { f: T, } -enum EI1> { +enum Ei1> { V(T), } -enum EI2> { +enum Ei2> { V(T), } -enum EI3> { +enum Ei3> { V(T), } -enum EW1 +enum Ew1 where T: Iterator, { V(T), } -enum EW2 +enum Ew2 where T: Iterator, { V(T), } -enum EW3 +enum Ew3 where T: Iterator, { V(T), } -union UI1> { +union Ui1> { f: ManuallyDrop, } -union UI2> { +union Ui2> { f: ManuallyDrop, } -union UI3> { +union Ui3> { f: ManuallyDrop, } -union UW1 +union Uw1 where T: Iterator, { f: ManuallyDrop, } -union UW2 +union Uw2 where T: Iterator, { f: ManuallyDrop, } -union UW3 +union Uw3 where T: Iterator, { @@ -110,78 +110,78 @@ where { } -fn frpit1() -> impl Iterator { +fn rpit1() -> impl Iterator { iter::empty::() } -fn frpit2() -> impl Iterator { +fn rpit2() -> impl Iterator { iter::empty::() } -fn frpit3() -> impl Iterator { +fn rpit3() -> impl Iterator { iter::empty::() } -fn fapit1(_: impl Iterator) {} -fn fapit2(_: impl Iterator) {} -fn fapit3(_: impl Iterator) {} +fn apit1(_: impl Iterator) {} +fn apit2(_: impl Iterator) {} +fn apit3(_: impl Iterator) {} -type TAI1> = T; -type TAI2> = T; -type TAI3> = T; -type TAW1 +type Tait1> = T; +type Tait2> = T; +type Tait3> = T; +type Taw1 where T: Iterator, = T; -type TAW2 +type Taw2 where T: Iterator, = T; -type TAW3 +type Taw3 where T: Iterator, = T; -trait TRI1> {} -trait TRI2> {} -trait TRI3> {} -trait TRS1: Iterator {} -trait TRS2: Iterator {} -trait TRS3: Iterator {} -trait TRW1 +trait Tri1> {} +trait Tri2> {} +trait Tri3> {} +trait Trs1: Iterator {} +trait Trs2: Iterator {} +trait Trs3: Iterator {} +trait Trw1 where T: Iterator, { } -trait TRW2 +trait Trw2 where T: Iterator, { } -trait TRW3 +trait Trw3 where T: Iterator, { } -trait TRSW1 +trait Trsw1 where Self: Iterator, { } -trait TRSW2 +trait Trsw2 where Self: Iterator, { } -trait TRSW3 +trait Trsw3 where Self: Iterator, { } -trait TRA1 { +trait Tra1 { type A: Iterator; } -trait TRA2 { +trait Tra2 { type A: Iterator; } -trait TRA3 { +trait Tra3 { type A: Iterator; } From 68c0e97cc6d084424cd2eb9001d63a0989b03655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Thu, 25 Sep 2025 11:34:08 +0200 Subject: [PATCH 281/537] re-order normalizations in run-make linker-warning test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit otherwise a buildroot containing `libpanic_abort` would be mangled before being replaced by the build root placeholder value.. e.g., running `./x.py test --verbose tests/run-make/linker-warning` with rustc checked out in ~/ext/rustc-libpanic_abort will result in (output slightly shortened): ``` running 1 tests test [run-make] tests/run-make/linker-warning ... FAILED failures: ---- [run-make] tests/run-make/linker-warning stdout ---- ------rustc stdout------------------------------ ------rustc stderr------------------------------ ------------------------------------------ error: rmake recipe failed to complete status: exit status: 101 command: cd "/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/test/run-make/linker-warning/rmake_out" && env -u RUSTFLAGS -u __RUSTC_DEBUG_ASSERTIONS_ENABLED -u __STD_DEBUG_ASSERTIONS_ENABLED AR="ar" BUILD_ROOT="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu" CC="cc" CC_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC -m64" CXX="c++" CXX_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC -m64" HOST_RUSTC_DYLIB_PATH="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/stage1/lib" LD_LIBRARY_PATH="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/bootstrap-tools/x86_64-unknown-linux-gnu/release/deps:/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/stage0/lib/rustlib/x86_64-unknown-linux-gnu/lib" LD_LIB_PATH_ENVVAR="LD_LIBRARY_PATH" LLVM_BIN_DIR="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/ci-llvm/bin" LLVM_COMPONENTS="<...>" LLVM_FILECHECK="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/ci-llvm/bin/FileCheck" NODE="/usr/bin/node" PYTHON="/usr/bin/python3" RUSTC="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/stage1/bin/rustc" RUSTDOC="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/stage1/bin/rustdoc" SOURCE_ROOT="/home/user/ext/rustc-libpanic_abort" TARGET="x86_64-unknown-linux-gnu" TARGET_EXE_DYLIB_PATH="/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/user/ext/rustc-libpanic_abort/build/x86_64-unknown-linux-gnu/test/run-make/linker-warning/rmake" stdout: none --- stderr ------------------------------- thread 'main' panicked at /home/user/ext/rustc-libpanic_abort/tests/run-make/linker-warning/rmake.rs:74:14: test failed: `short-error.txt` is different from `(linker error)` --- short-error.txt +++ (linker error) @@ -1,6 +1,6 @@ error: linking with `./fake-linker` failed: exit status: 1 | - = note: "./fake-linker" "-m64" "/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/build-root/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" + = note: "./fake-linker" "-m64" "/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/home/user/ext/rustc-libpanic_unwind/build/x86_64-unknown-linux-gnu/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/home/user/ext/rustc-libpanic_unwind/build/x86_64-unknown-linux-gnu/test/run-make/linker-warning/rmake_out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" = note: some arguments are omitted. use `--verbose` to show all linker arguments = note: error: baz [..] ``` without this fix. Signed-off-by: Fabian Grünbichler --- tests/run-make/linker-warning/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index b0c40dd171d3..a31b08d6c695 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -61,13 +61,13 @@ fn main() { diff() .expected_file("short-error.txt") .actual_text("(linker error)", out.stderr()) - .normalize("libpanic_abort", "libpanic_unwind") .normalize( regex::escape( run_make_support::build_root().canonicalize().unwrap().to_str().unwrap(), ), "/build-root", ) + .normalize("libpanic_abort", "libpanic_unwind") .normalize(r#""[^"]*\/symbols.o""#, "\"/symbols.o\"") .normalize(r#""[^"]*\/raw-dylibs""#, "\"/raw-dylibs\"") .run(); From 38284d10dc45b3bb2c9aa412dce1e5b1e16c639a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 23 Sep 2025 13:18:33 +0800 Subject: [PATCH 282/537] Fix expand rest pattern in tuple and slice pattern Assist: expand_tuple_rest_pattern Fills fields by replacing rest pattern in tuple patterns. Example --- ``` fn foo(bar: (char, i32, i32)) { let (ch, ..$0) = bar; } ``` -> ``` fn foo(bar: (char, i32, i32)) { let (ch, _1, _2) = bar; } ``` --- Assist: expand_slice_rest_pattern Fills fields by replacing rest pattern in slice patterns. Example --- ``` fn foo(bar: [i32; 3]) { let [first, ..$0] = bar; } ``` -> ``` fn foo(bar: [i32; 3]) { let [first, _1, _2] = bar; } ``` --- .../src/handlers/expand_rest_pattern.rs | 274 ++++++++++++++++-- .../crates/ide-assists/src/tests/generated.rs | 34 +++ 2 files changed, 289 insertions(+), 19 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 932166adb0a0..b746099e7279 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -113,9 +113,7 @@ fn expand_tuple_struct_rest_pattern( }; let rest_pat = rest_pat.into(); - let mut pats = pat.fields(); - let prefix_count = pats.by_ref().position(|p| p == rest_pat)?; - let suffix_count = pats.count(); + let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?; if fields.len().saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 { cov_mark::hit!(no_missing_fields_tuple_struct); @@ -141,19 +139,13 @@ fn expand_tuple_struct_rest_pattern( pat.fields() .take(prefix_count) .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| { - make.ident_pat( - false, - false, - match name_gen.for_type( - &f.ty(ctx.sema.db).to_type(ctx.sema.db), - ctx.sema.db, - ctx.edition(), - ) { - Some(name) => make.name(&name), - None => make.name(&format!("_{}", f.index())), - }, + gen_unnamed_pat( + ctx, + &make, + &mut name_gen, + &f.ty(ctx.db()).to_type(ctx.sema.db), + f.index(), ) - .into() })) .chain(pat.fields().skip(prefix_count + 1)), ); @@ -166,6 +158,134 @@ fn expand_tuple_struct_rest_pattern( ) } +// Assist: expand_tuple_rest_pattern +// +// Fills fields by replacing rest pattern in tuple patterns. +// +// ``` +// fn foo(bar: (char, i32, i32)) { +// let (ch, ..$0) = bar; +// } +// ``` +// -> +// ``` +// fn foo(bar: (char, i32, i32)) { +// let (ch, _1, _2) = bar; +// } +// ``` +fn expand_tuple_rest_pattern( + acc: &mut Assists, + ctx: &AssistContext<'_>, + pat: ast::TuplePat, + rest_pat: ast::RestPat, +) -> Option<()> { + let fields = ctx.sema.type_of_pat(&pat.clone().into())?.original.tuple_fields(ctx.db()); + let len = fields.len(); + + let rest_pat = rest_pat.into(); + let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?; + + if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 { + cov_mark::hit!(no_missing_fields_tuple); + return None; + } + + let old_range = ctx.sema.original_range_opt(pat.syntax())?; + if old_range.file_id != ctx.file_id() { + return None; + } + + acc.add( + AssistId::refactor_rewrite("expand_tuple_rest_pattern"), + "Fill tuple fields", + rest_pat.syntax().text_range(), + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(rest_pat.syntax()); + + let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax())); + let new_pat = make.tuple_pat( + pat.fields() + .take(prefix_count) + .chain(fields[prefix_count..len - suffix_count].iter().enumerate().map( + |(index, ty)| { + gen_unnamed_pat(ctx, &make, &mut name_gen, ty, prefix_count + index) + }, + )) + .chain(pat.fields().skip(prefix_count + 1)), + ); + + editor.replace(pat.syntax(), new_pat.syntax()); + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ) +} + +// Assist: expand_slice_rest_pattern +// +// Fills fields by replacing rest pattern in slice patterns. +// +// ``` +// fn foo(bar: [i32; 3]) { +// let [first, ..$0] = bar; +// } +// ``` +// -> +// ``` +// fn foo(bar: [i32; 3]) { +// let [first, _1, _2] = bar; +// } +// ``` +fn expand_slice_rest_pattern( + acc: &mut Assists, + ctx: &AssistContext<'_>, + pat: ast::SlicePat, + rest_pat: ast::RestPat, +) -> Option<()> { + let (ty, len) = ctx.sema.type_of_pat(&pat.clone().into())?.original.as_array(ctx.db())?; + + let rest_pat = rest_pat.into(); + let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.pats())?; + + if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 { + cov_mark::hit!(no_missing_fields_slice); + return None; + } + + let old_range = ctx.sema.original_range_opt(pat.syntax())?; + if old_range.file_id != ctx.file_id() { + return None; + } + + acc.add( + AssistId::refactor_rewrite("expand_slice_rest_pattern"), + "Fill slice fields", + rest_pat.syntax().text_range(), + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(rest_pat.syntax()); + + let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax())); + let new_pat = make.slice_pat( + pat.pats() + .take(prefix_count) + .chain( + (prefix_count..len - suffix_count) + .map(|index| gen_unnamed_pat(ctx, &make, &mut name_gen, &ty, index)), + ) + .chain(pat.pats().skip(prefix_count + 1)), + ); + + editor.replace(pat.syntax(), new_pat.syntax()); + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ) +} + pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let rest_pat = ctx.find_node_at_offset::()?; let parent = rest_pat.syntax().parent()?; @@ -173,15 +293,40 @@ pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> match parent { ast::RecordPatFieldList(it) => expand_record_rest_pattern(acc, ctx, it.syntax().parent().and_then(ast::RecordPat::cast)?, rest_pat), ast::TupleStructPat(it) => expand_tuple_struct_rest_pattern(acc, ctx, it, rest_pat), - // FIXME - // ast::TuplePat(it) => (), - // FIXME - // ast::SlicePat(it) => (), + ast::TuplePat(it) => expand_tuple_rest_pattern(acc, ctx, it, rest_pat), + ast::SlicePat(it) => expand_slice_rest_pattern(acc, ctx, it, rest_pat), _ => None, } } } +fn gen_unnamed_pat( + ctx: &AssistContext<'_>, + make: &SyntaxFactory, + name_gen: &mut NameGenerator, + ty: &hir::Type<'_>, + index: usize, +) -> ast::Pat { + make.ident_pat( + false, + false, + match name_gen.for_type(ty, ctx.sema.db, ctx.edition()) { + Some(name) => make.name(&name), + None => make.name(&format!("_{index}")), + }, + ) + .into() +} + +fn calculate_counts( + rest_pat: &ast::Pat, + mut pats: ast::AstChildren, +) -> Option<(usize, usize)> { + let prefix_count = pats.by_ref().position(|p| p == *rest_pat)?; + let suffix_count = pats.count(); + Some((prefix_count, suffix_count)) +} + #[cfg(test)] mod tests { use super::*; @@ -351,6 +496,79 @@ fn foo(bar: Bar) { ) } + #[test] + fn fill_tuple_with_fields() { + check_assist( + expand_rest_pattern, + r#" +fn foo(bar: (char, i32, i32)) { + let (ch, ..$0) = bar; +} +"#, + r#" +fn foo(bar: (char, i32, i32)) { + let (ch, _1, _2) = bar; +} +"#, + ); + check_assist( + expand_rest_pattern, + r#" +fn foo(bar: (char, i32, i32)) { + let (ch, ..$0, end) = bar; +} +"#, + r#" +fn foo(bar: (char, i32, i32)) { + let (ch, _1, end) = bar; +} +"#, + ); + } + + #[test] + fn fill_array_with_fields() { + check_assist( + expand_rest_pattern, + r#" +fn foo(bar: [i32; 4]) { + let [first, ..$0] = bar; +} +"#, + r#" +fn foo(bar: [i32; 4]) { + let [first, _1, _2, _3] = bar; +} +"#, + ); + check_assist( + expand_rest_pattern, + r#" +fn foo(bar: [i32; 4]) { + let [first, second, ..$0] = bar; +} +"#, + r#" +fn foo(bar: [i32; 4]) { + let [first, second, _2, _3] = bar; +} +"#, + ); + check_assist( + expand_rest_pattern, + r#" +fn foo(bar: [i32; 4]) { + let [first, second, ..$0, end] = bar; +} +"#, + r#" +fn foo(bar: [i32; 4]) { + let [first, second, _2, end] = bar; +} +"#, + ); + } + #[test] fn fill_fields_struct_generated_by_macro() { check_assist( @@ -486,6 +704,8 @@ fn bar(foo: Foo) { // This is still possible even though it's meaningless cov_mark::check!(no_missing_fields); cov_mark::check!(no_missing_fields_tuple_struct); + cov_mark::check!(no_missing_fields_tuple); + cov_mark::check!(no_missing_fields_slice); check_assist_not_applicable( expand_rest_pattern, r#" @@ -523,6 +743,22 @@ struct Bar(Y, Z) fn foo(bar: Bar) { let Bar(y, ..$0, z) = bar; } +"#, + ); + check_assist_not_applicable( + expand_rest_pattern, + r#" +fn foo(bar: (i32, i32)) { + let (y, ..$0, z) = bar; +} +"#, + ); + check_assist_not_applicable( + expand_rest_pattern, + r#" +fn foo(bar: [i32; 2]) { + let [y, ..$0, z] = bar; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 71ffaa23fc64..e7f91ff3fbc1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1041,6 +1041,40 @@ fn foo(bar: Bar) { ) } +#[test] +fn doctest_expand_slice_rest_pattern() { + check_doc_test( + "expand_slice_rest_pattern", + r#####" +fn foo(bar: [i32; 3]) { + let [first, ..$0] = bar; +} +"#####, + r#####" +fn foo(bar: [i32; 3]) { + let [first, _1, _2] = bar; +} +"#####, + ) +} + +#[test] +fn doctest_expand_tuple_rest_pattern() { + check_doc_test( + "expand_tuple_rest_pattern", + r#####" +fn foo(bar: (char, i32, i32)) { + let (ch, ..$0) = bar; +} +"#####, + r#####" +fn foo(bar: (char, i32, i32)) { + let (ch, _1, _2) = bar; +} +"#####, + ) +} + #[test] fn doctest_expand_tuple_struct_rest_pattern() { check_doc_test( From aa5a21450a070fdea66a07d3cab3b69e6735c328 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Thu, 25 Sep 2025 20:54:54 -0700 Subject: [PATCH 283/537] ProjectionElem::Subtype -> CastKind::Subtype --- .../src/diagnostics/conflict_errors.rs | 1 - .../rustc_borrowck/src/diagnostics/mod.rs | 7 +++--- .../src/diagnostics/mutability_errors.rs | 1 - compiler/rustc_borrowck/src/lib.rs | 4 ---- .../rustc_borrowck/src/places_conflict.rs | 2 -- compiler/rustc_borrowck/src/prefixes.rs | 3 --- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +++---- compiler/rustc_codegen_cranelift/src/base.rs | 4 ++-- .../src/value_and_place.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 4 ---- compiler/rustc_codegen_ssa/src/mir/operand.rs | 5 ---- compiler/rustc_codegen_ssa/src/mir/place.rs | 1 - compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 8 +++++-- .../src/check_consts/qualifs.rs | 1 - .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/projection.rs | 2 -- compiler/rustc_middle/src/mir/pretty.rs | 4 ---- compiler/rustc_middle/src/mir/statement.rs | 8 ++----- compiler/rustc_middle/src/mir/syntax.rs | 24 +++++++++---------- compiler/rustc_middle/src/mir/visit.rs | 6 ----- .../src/builder/expr/as_place.rs | 3 +-- .../src/move_paths/builder.rs | 5 +--- .../src/add_subtyping_projections.rs | 3 +-- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 3 +-- .../src/known_panics_lint.rs | 2 +- .../rustc_mir_transform/src/promote_consts.rs | 1 - compiler/rustc_mir_transform/src/validate.rs | 24 +++++++------------ compiler/rustc_public/src/mir/body.rs | 11 ++------- compiler/rustc_public/src/mir/visit.rs | 2 -- .../src/unstable/convert/internal.rs | 3 --- .../src/unstable/convert/stable/mir.rs | 2 +- 32 files changed, 47 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7e20a5133e07..a5b16b508388 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3974,7 +3974,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) | ProjectionElem::UnwrapUnsafeBinder(_) => kind, }, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5642cdf87fde..e13c1c712d8d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -402,7 +402,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), - ProjectionElem::Subtype(..) => (), ProjectionElem::UnwrapUnsafeBinder(_) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. @@ -484,9 +483,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::Subtype(ty) - | ProjectionElem::OpaqueCast(ty) - | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty), + ProjectionElem::OpaqueCast(ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => { + PlaceTy::from_ty(*ty) + } ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 6d69040c711d..727cf19cd8bb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -192,7 +192,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { [ .., ProjectionElem::Index(_) - | ProjectionElem::Subtype(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4c380ddcf708..cc27b9e5dde6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1989,10 +1989,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }, // `OpaqueCast`: only transmutes the type, so no moves there. // `Downcast` : only changes information about a `Place` without moving. - // `Subtype` : only transmutes the type, so no moves. // So it's safe to skip these. ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) | ProjectionElem::Downcast(_, _) | ProjectionElem::UnwrapUnsafeBinder(_) => (), } @@ -2218,7 +2216,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | - ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -2610,7 +2607,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) | ProjectionElem::UnwrapUnsafeBinder(_) => { diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index cf3e82426e8a..60676ac6b864 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -249,7 +249,6 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _) - | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Downcast { .. }, _, _) | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => { // Recursive case. This can still be disjoint on a @@ -510,7 +509,6 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 83cca38a5c09..9e51264d8edc 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -77,9 +77,6 @@ impl<'tcx> Iterator for Prefixes<'tcx> { | ProjectionElem::Index(_) => { cursor = cursor_base; } - ProjectionElem::Subtype(..) => { - panic!("Subtype projection is not allowed before borrow check") - } ProjectionElem::Deref => { match self.kind { PrefixSet::Shallow => { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 606d3d95d9e6..781fb5ba113a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1558,6 +1558,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), } } + CastKind::Subtype => { + bug!("CastKind::Subtype shouldn't exist in borrowck") + } } } @@ -1882,9 +1885,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) .unwrap(); } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } } } } @@ -2412,9 +2412,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | ProjectionElem::UnwrapUnsafeBinder(_) => { // other field access } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 41e11e1de616..a2f844642f85 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -789,7 +789,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } - Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { + Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, ref operand, _to_ty) => { let operand = codegen_operand(fx, operand); lval.write_cvalue_transmute(fx, operand); } @@ -996,7 +996,7 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), - PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => { + PlaceElem::UnwrapUnsafeBinder(ty) => { cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)); } PlaceElem::Field(field, _ty) => { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4519fa1a270e..25bba48a9e3a 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -660,7 +660,7 @@ impl<'tcx> CPlace<'tcx> { } } - /// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before + /// Used for `ProjectionElem::UnwrapUnsafeBinder`, `ty` has to be monomorphized before /// passed on. pub(crate) fn place_transmute_type( self, diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c2c023af090a..45bc54519468 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -150,10 +150,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> { layout.for_variant(self.fx.cx, vidx) } - mir::PlaceElem::Subtype(subtype_ty) => { - let subtype_ty = self.fx.monomorphize(subtype_ty); - self.fx.cx.layout_of(subtype_ty) - } _ => { self.locals[place_ref.local] = LocalKind::Memory; return; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index d851c3329802..5f7f87fc6920 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -956,11 +956,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = o.layout.for_variant(bx.cx(), vidx); o = OperandRef { val: o.val, layout } } - mir::PlaceElem::Subtype(subtype_ty) => { - let subtype_ty = self.monomorphize(subtype_ty); - let layout = self.cx.layout_of(subtype_ty); - o = OperandRef { val: o.val, layout } - } _ => return None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0090be9fdef0..50f56f913a51 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -347,7 +347,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::OpaqueCast(ty) => { bug!("encountered OpaqueCast({ty}) in codegen") } - mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), mir::ProjectionElem::UnwrapUnsafeBinder(ty) => { cg_base.project_type(bx, self.monomorphize(ty)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2602bf82095c..69478d078cc0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -86,7 +86,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => { + mir::Rvalue::Cast( + mir::CastKind::Transmute | mir::CastKind::Subtype, + ref operand, + _ty, + ) => { let src = self.codegen_operand(bx, operand); self.codegen_transmute(bx, src, dest); } @@ -486,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("Unsupported cast of {operand:?} to {cast:?}"); }) } - mir::CastKind::Transmute => { + mir::CastKind::Transmute | mir::CastKind::Subtype => { self.codegen_transmute_operand(bx, operand, cast) } }; diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 34d1fdd8c869..8a6827bca2bd 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -293,7 +293,6 @@ where ProjectionElem::Index(index) if in_local(index) => return true, ProjectionElem::Deref - | ProjectionElem::Subtype(_) | ProjectionElem::Field(_, _) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 0075740e0317..b058d4b8ad44 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -133,7 +133,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index d05871bfc773..2fd1657f6ba3 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -395,8 +395,6 @@ where span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, - // We don't want anything happening here, this is here as a dummy. - Subtype(_) => base.transmute(base.layout(), self)?, Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, Deref => self.deref_pointer(&base.to_op(self)?)?.into(), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 96148fd5b926..350d75c2ee77 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1274,7 +1274,6 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> for &elem in projection.iter().rev() { match elem { ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { write!(fmt, "(")?; @@ -1300,9 +1299,6 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::OpaqueCast(ty) => { write!(fmt, " as {ty})")?; } - ProjectionElem::Subtype(ty) => { - write!(fmt, " as subtype {ty})")?; - } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {name})")?; } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 28294b47e90f..e009fe05b53e 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -222,7 +222,6 @@ impl<'tcx> PlaceTy<'tcx> { fty, )), ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), - ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. ProjectionElem::UnwrapUnsafeBinder(ty) => { @@ -244,7 +243,6 @@ impl ProjectionElem { Self::Field(_, _) | Self::Index(_) | Self::OpaqueCast(_) - | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) @@ -259,7 +257,6 @@ impl ProjectionElem { Self::Deref | Self::Index(_) => false, Self::Field(_, _) | Self::OpaqueCast(_) - | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) @@ -286,7 +283,6 @@ impl ProjectionElem { | Self::Field(_, _) => true, Self::ConstantIndex { from_end: true, .. } | Self::Index(_) - | Self::Subtype(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, @@ -319,7 +315,6 @@ impl ProjectionElem { ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)), - ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)), ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)), ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?), }) @@ -706,7 +701,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) | CastKind::PointerWithExposedProvenance - | CastKind::Transmute, + | CastKind::Transmute + | CastKind::Subtype, _, _, ) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index e6c8512564ed..a823c365394f 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1275,18 +1275,6 @@ pub enum ProjectionElem { /// A transmute from an unsafe binder to the type that it wraps. This is a projection /// of a place, so it doesn't necessarily constitute a move out of the binder. UnwrapUnsafeBinder(T), - - /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping - /// explicit during optimizations and codegen. - /// - /// This projection doesn't impact the runtime behavior of the program except for potentially changing - /// some type metadata of the interpreter or codegen backend. - /// - /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after - /// borrowchecker, as we only care about subtyping that can affect trait selection and - /// `TypeId`. - Subtype(T), } /// Alias for projections as they appear in places, where the base is a place @@ -1513,6 +1501,18 @@ pub enum CastKind { /// MIR is well-formed if the input and output types have different sizes, /// but running a transmute between differently-sized types is UB. Transmute, + + /// A `Subtype` cast is applied to any `StatementKind::Assign` where + /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping + /// explicit during optimizations and codegen. + /// + /// This cast doesn't impact the runtime behavior of the program except for potentially changing + /// some type metadata of the interpreter or codegen backend. + /// + /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after + /// borrowchecker, as we only care about subtyping that can affect trait selection and + /// `TypeId`. + Subtype, } /// Represents how a [`CastKind::PointerCoercion`] was constructed. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 81df239dee42..f39234778005 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1166,11 +1166,6 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } } - PlaceElem::Subtype(ty) => { - let mut new_ty = ty; - self.visit_ty(&mut new_ty, TyContext::Location(location)); - if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None } - } PlaceElem::UnwrapUnsafeBinder(ty) => { let mut new_ty = ty; self.visit_ty(&mut new_ty, TyContext::Location(location)); @@ -1244,7 +1239,6 @@ macro_rules! visit_place_fns { ) { match elem { ProjectionElem::OpaqueCast(ty) - | ProjectionElem::Subtype(ty) | ProjectionElem::Field(_, ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => { self.visit_ty(ty, TyContext::Location(location)); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 5a6bd2f413c2..5e7a57d51a9c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -103,7 +103,7 @@ fn convert_to_hir_projections_and_truncate_for_capture( } ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder, // These do not affect anything, they just make sure we know the right type. - ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, + ProjectionElem::OpaqueCast(_) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -802,7 +802,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ProjectionElem::Field(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::UnwrapUnsafeBinder(_) => (), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 72d4cd72c2bc..434f106302f5 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -227,11 +227,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { ProjectionElem::UnwrapUnsafeBinder(_) => {} // `OpaqueCast`:Only transmutes the type, so no moves there. // `Downcast` :Only changes information about a `Place` without moving. - // `Subtype` :Only transmutes the type, so moves. // So it's safe to skip these. - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) - | ProjectionElem::Downcast(_, _) => (), + ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (), } let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty; if !(self.filter)(elem_ty) { diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index be4f84d64d03..a6a60fddf909 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -40,8 +40,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span); let new_place = Place::from(temp); self.patcher.add_assign(location, new_place, rvalue.clone()); - let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx); - *rvalue = Rvalue::Use(Operand::Move(subtyped)); + *rvalue = Rvalue::Cast(CastKind::Subtype, Operand::Move(new_place), place_ty); } } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 5c984984d3cc..d250cdea7e80 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, } } - Rvalue::Cast(CastKind::Transmute, operand, _) => { + Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, operand, _) => { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self.wrap_immediate(*op), FlatSet::Bottom => FlatSet::Bottom, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebec3d125003..eb59ae830ae1 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -656,7 +656,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?; res.into() } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { let value = self.evaluated[value].as_ref()?; // `offset` for immediates generally only supports projections that match the // type of the immediate. However, as a HACK, we exploit that it can also do @@ -788,7 +788,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()), - ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()), ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()), }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index aaacc5866a2a..0686dca9962d 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -637,7 +637,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { let value = self.eval_operand(value)?; let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index a0b0c8c990f3..48ddf5a1bcab 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -292,7 +292,6 @@ impl<'tcx> Validator<'_, 'tcx> { match elem { // Recurse directly. ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::Subslice { .. } | ProjectionElem::UnwrapUnsafeBinder(_) => {} diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c8a9a88dc3fe..cbabb982df8b 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -814,22 +814,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - ProjectionElem::Subtype(ty) => { - if !util::sub_types( - self.tcx, - self.typing_env, - ty, - place_ref.ty(&self.body.local_decls, self.tcx).ty, - ) { - self.fail( - location, - format!( - "Failed subtyping {ty} and {}", - place_ref.ty(&self.body.local_decls, self.tcx).ty - ), - ) - } - } ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => { let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx); let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else { @@ -1331,6 +1315,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::Subtype => { + if !util::sub_types(self.tcx, self.typing_env, op_ty, *target_type) { + self.fail( + location, + format!("Failed subtyping {op_ty} and {target_type}"), + ) + } + } } } Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => { diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 276adacd99e0..7bd06fee721c 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -836,14 +836,6 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. OpaqueCast(Ty), - - /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping - /// explicit during optimizations and codegen. - /// - /// This projection doesn't impact the runtime behavior of the program except for potentially changing - /// some type metadata of the interpreter or codegen backend. - Subtype(Ty), } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1028,6 +1020,7 @@ pub enum CastKind { PtrToPtr, FnPtrToPtr, Transmute, + Subtype, } #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] @@ -1089,7 +1082,7 @@ impl ProjectionElem { Self::subslice_ty(ty, *from, *to, *from_end) } ProjectionElem::Downcast(_) => Ok(ty), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), + ProjectionElem::OpaqueCast(ty) => Ok(*ty), } } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index 04c4d4d2a82d..7563c9ca0082 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -471,7 +471,6 @@ macro_rules! visit_place_fns { ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} ProjectionElem::Downcast(_idx) => {} ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } } }; @@ -512,7 +511,6 @@ macro_rules! visit_place_fns { ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} ProjectionElem::Downcast(_idx) => {} ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } } }; diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index dc9abd88614d..064fb6c6803a 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -703,9 +703,6 @@ impl RustcInternal for ProjectionElem { ProjectionElem::OpaqueCast(ty) => { rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx)) } - ProjectionElem::Subtype(ty) => { - rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx)) - } } } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index b10af6526ead..62ab91d17bae 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -356,6 +356,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { PtrToPtr => crate::mir::CastKind::PtrToPtr, FnPtrToPtr => crate::mir::CastKind::FnPtrToPtr, Transmute => crate::mir::CastKind::Transmute, + Subtype => crate::mir::CastKind::Subtype, } } } @@ -453,7 +454,6 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486 Downcast(_, idx) => crate::mir::ProjectionElem::Downcast(idx.stable(tables, cx)), OpaqueCast(ty) => crate::mir::ProjectionElem::OpaqueCast(ty.stable(tables, cx)), - Subtype(ty) => crate::mir::ProjectionElem::Subtype(ty.stable(tables, cx)), UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), } } From 78ff5ddad940c245ba2ace56c8d4aa33e1bb6338 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 20:40:28 +0300 Subject: [PATCH 284/537] Remove usages of `write_str` from `render_assoc_items_inner` --- src/librustdoc/html/format.rs | 4 --- src/librustdoc/html/render/mod.rs | 59 ++++++++++++------------------- 2 files changed, 22 insertions(+), 41 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ecaff4cdf43a..856e637a4587 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -37,10 +37,6 @@ use crate::html::escape::{Escape, EscapeBodyText}; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; -pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) { - s.write_fmt(f).unwrap(); -} - pub(crate) fn print_generic_bounds( bounds: &[clean::GenericBound], cx: &Context<'_>, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 9a14137a6e80..8c9953c469b9 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1472,12 +1472,10 @@ fn render_assoc_items_inner( ) } }; - let mut impls_buf = String::new(); - for i in &non_trait { - write_str( - &mut impls_buf, - format_args!( - "{}", + let impls_buf = fmt::from_fn(|f| { + non_trait + .iter() + .map(|i| { render_impl( cx, i, @@ -1493,9 +1491,11 @@ fn render_assoc_items_inner( toggle_open_by_default: true, }, ) - ), - ); - } + }) + .joined("", f) + }) + .to_string(); + if !impls_buf.is_empty() { write!( w, @@ -1805,27 +1805,19 @@ fn render_impl( document_item_info(cx, it, Some(parent)) .render_into(&mut info_buffer) .unwrap(); - write_str( - &mut doc_buffer, - format_args!("{}", document_full(item, cx, HeadingOffset::H5)), - ); + doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string(); short_documented = false; } else { // In case the item isn't documented, // provide short documentation from the trait. - write_str( - &mut doc_buffer, - format_args!( - "{}", - document_short( - it, - cx, - link, - parent, - rendering_params.show_def_docs, - ) - ), - ); + doc_buffer = document_short( + it, + cx, + link, + parent, + rendering_params.show_def_docs, + ) + .to_string(); } } } else { @@ -1833,21 +1825,14 @@ fn render_impl( .render_into(&mut info_buffer) .unwrap(); if rendering_params.show_def_docs { - write_str( - &mut doc_buffer, - format_args!("{}", document_full(item, cx, HeadingOffset::H5)), - ); + doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string(); short_documented = false; } } } else { - write_str( - &mut doc_buffer, - format_args!( - "{}", - document_short(item, cx, link, parent, rendering_params.show_def_docs) - ), - ); + doc_buffer = + document_short(item, cx, link, parent, rendering_params.show_def_docs) + .to_string(); } } let mut w = if short_documented && trait_.is_some() { From 82fecf0ee3e362bf20b46d7867fe25f9af4e82d8 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 20:40:31 +0300 Subject: [PATCH 285/537] Cleanup `notable_traits_decl` --- src/librustdoc/html/render/mod.rs | 119 ++++++++++++++++-------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8c9953c469b9..878af36e4ff1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -77,7 +77,6 @@ use crate::html::escape::Escape; use crate::html::format::{ Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, - write_str, }; use crate::html::markdown::{ HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, @@ -1647,69 +1646,77 @@ fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option) -> (String, String) { - let mut out = String::new(); - let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this"); let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this"); - for i in impls { - let impl_ = i.inner_impl(); - if impl_.polarity != ty::ImplPolarity::Positive { - continue; - } - - if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { - // Two different types might have the same did, - // without actually being the same. - continue; - } - if let Some(trait_) = &impl_.trait_ { - let trait_did = trait_.def_id(); - - if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) { - if out.is_empty() { - write_str( - &mut out, - format_args!( - "

Notable traits for {}

\ -
",
-                            impl_.for_.print(cx)
-                        ),
-                    );
+    let out = fmt::from_fn(|f| {
+        let mut notable_impls = impls
+            .iter()
+            .map(|impl_| impl_.inner_impl())
+            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
+            .filter(|impl_| {
+                // Two different types might have the same did, without actually being the same.
+                ty.is_doc_subtype_of(&impl_.for_, cx.cache())
+            })
+            .filter_map(|impl_| {
+                if let Some(trait_) = &impl_.trait_
+                    && let trait_did = trait_.def_id()
+                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
+                    && trait_.is_notable_trait(cx.tcx())
+                {
+                    Some((impl_, trait_did))
+                } else {
+                    None
                 }
+            })
+            .peekable();
 
-                write_str(
-                    &mut out,
-                    format_args!("
{}
", impl_.print(false, cx)), - ); - for it in &impl_.items { - if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { - let empty_set = FxIndexSet::default(); - let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); - write_str( - &mut out, - format_args!( - "
{};
", - assoc_type( - it, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(&tydef.type_), - src_link, - 0, - cx, - ) - ), - ); - } - } + let has_notable_impl = if let Some((impl_, _)) = notable_impls.peek() { + write!( + f, + "

Notable traits for {}

\ +
",
+                impl_.for_.print(cx)
+            )?;
+            true
+        } else {
+            false
+        };
+
+        for (impl_, trait_did) in notable_impls {
+            write!(f, "
{}
", impl_.print(false, cx))?; + for it in &impl_.items { + let clean::AssocTypeItem(tydef, ..) = &it.kind else { + continue; + }; + + let empty_set = FxIndexSet::default(); + let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); + + write!( + f, + "
{};
", + assoc_type( + it, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(&tydef.type_), + src_link, + 0, + cx, + ) + )?; } } - } - if out.is_empty() { - out.push_str("
"); - } + + if !has_notable_impl { + f.write_str("
")?; + } + + Ok(()) + }) + .to_string(); (format!("{:#}", ty.print(cx)), out) } From a40032d9e38a9237e61f8b909e5387b388698c15 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 23:17:25 +0300 Subject: [PATCH 286/537] Simplify notable traits map serialization --- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/render/mod.rs | 23 ++++------------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index f37a8d85361f..0988d099eb4f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" -indexmap = "2" +indexmap = { version = "2", features = ["serde"] } itertools = "0.12" minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 878af36e4ff1..d3b35ec727c5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,6 +48,7 @@ use std::path::PathBuf; use std::{fs, str}; use askama::Template; +use indexmap::IndexMap; use itertools::Either; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; @@ -60,8 +61,6 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{Symbol, sym}; use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName}; -use serde::ser::SerializeMap; -use serde::{Serialize, Serializer}; use tracing::{debug, info}; pub(crate) use self::context::*; @@ -1722,23 +1721,9 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { } fn notable_traits_json<'a>(tys: impl Iterator, cx: &Context<'_>) -> String { - let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect(); - mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2)); - struct NotableTraitsMap(Vec<(String, String)>); - impl Serialize for NotableTraitsMap { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut map = serializer.serialize_map(Some(self.0.len()))?; - for item in &self.0 { - map.serialize_entry(&item.0, &item.1)?; - } - map.end() - } - } - serde_json::to_string(&NotableTraitsMap(mp)) - .expect("serialize (string, string) -> json object cannot fail") + let mut mp = tys.map(|ty| notable_traits_decl(ty, cx)).collect::>(); + mp.sort_unstable_keys(); + serde_json::to_string(&mp).expect("serialize (string, string) -> json object cannot fail") } #[derive(Clone, Copy, Debug)] From 93a96bf29c22d05894ca343b624cd09048aa7bb7 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 26 Sep 2025 16:53:45 +0800 Subject: [PATCH 287/537] Migrate `replace_arith_op` assist to use `SyntaxEditor` --- .../src/handlers/replace_arith_op.rs | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs index 94ac1c342d30..a3fb851fb0e2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs @@ -1,7 +1,7 @@ use ide_db::assists::{AssistId, GroupLabel}; use syntax::{ - AstNode, TextRange, - ast::{self, ArithOp, BinaryOp}, + AstNode, + ast::{self, ArithOp, BinaryOp, syntax_factory::SyntaxFactory}, }; use crate::assist_context::{AssistContext, Assists}; @@ -71,28 +71,31 @@ pub(crate) fn replace_arith_with_wrapping( fn replace_arith(acc: &mut Assists, ctx: &AssistContext<'_>, kind: ArithKind) -> Option<()> { let (lhs, op, rhs) = parse_binary_op(ctx)?; + let op_expr = lhs.syntax().parent()?; if !is_primitive_int(ctx, &lhs) || !is_primitive_int(ctx, &rhs) { return None; } - let start = lhs.syntax().text_range().start(); - let end = rhs.syntax().text_range().end(); - let range = TextRange::new(start, end); - acc.add_group( &GroupLabel("Replace arithmetic...".into()), kind.assist_id(), kind.label(), - range, + op_expr.text_range(), |builder| { + let mut edit = builder.make_editor(rhs.syntax()); + let make = SyntaxFactory::with_mappings(); let method_name = kind.method_name(op); - if lhs.precedence().needs_parentheses_in(ast::prec::ExprPrecedence::Postfix) { - builder.replace(range, format!("({lhs}).{method_name}({rhs})")) - } else { - builder.replace(range, format!("{lhs}.{method_name}({rhs})")) - } + let needs_parentheses = + lhs.precedence().needs_parentheses_in(ast::prec::ExprPrecedence::Postfix); + let receiver = if needs_parentheses { make.expr_paren(lhs).into() } else { lhs }; + let arith_expr = + make.expr_method_call(receiver, make.name_ref(&method_name), make.arg_list([rhs])); + edit.replace(op_expr, arith_expr.syntax()); + + edit.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } From fc703ec5c88e678a4931f7bb8ed86efc141775f7 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 25 Sep 2025 09:30:31 +0000 Subject: [PATCH 288/537] fix doc comments to be more standard --- compiler/rustc_mir_build/src/builder/mod.rs | 6 +----- compiler/rustc_privacy/src/lib.rs | 22 ++++----------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index cdb2c5561ce6..7ca94e655fb2 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -395,12 +395,10 @@ enum NeedsTemporary { Maybe, } -/////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a /// produced value (sometimes just unit, of course). The `unpack!` /// macro (and methods below) makes working with `BlockAnd` much more /// convenient. - #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd(BasicBlock, T); @@ -438,9 +436,7 @@ macro_rules! unpack { }}; } -/////////////////////////////////////////////////////////////////////////// -/// the main entry point for building MIR for a function - +/// The main entry point for building MIR for a function. fn construct_fn<'tcx>( tcx: TyCtxt<'tcx>, fn_def: LocalDefId, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1bddbd03cc3d..c9dbb204f61f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -45,7 +45,7 @@ use tracing::debug; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } //////////////////////////////////////////////////////////////////////////////// -/// Generic infrastructure used to implement specific visitors below. +// Generic infrastructure used to implement specific visitors below. //////////////////////////////////////////////////////////////////////////////// struct LazyDefPathStr<'tcx> { @@ -309,10 +309,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } } -//////////////////////////////////////////////////////////////////////////////// /// Visitor used to determine impl visibility and reachability. -//////////////////////////////////////////////////////////////////////////////// - struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, @@ -387,10 +384,7 @@ impl VisibilityLike for EffectiveVisibility { } } -//////////////////////////////////////////////////////////////////////////////// /// The embargo visitor, used to determine the exports of the AST. -//////////////////////////////////////////////////////////////////////////////// - struct EmbargoVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -849,9 +843,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> } } -//////////////////////////////////////////////////////////////////////////////// /// Visitor, used for EffectiveVisibilities table checking -//////////////////////////////////////////////////////////////////////////////// pub struct TestReachabilityVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, @@ -909,13 +901,11 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { } } -////////////////////////////////////////////////////////////////////////////////////// /// Name privacy visitor, checks privacy and reports violations. +/// /// Most of name privacy checks are performed during the main resolution phase, /// or later in type checking when field accesses and associated items are resolved. /// This pass performs remaining checks for fields in struct expressions and patterns. -////////////////////////////////////////////////////////////////////////////////////// - struct NamePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, @@ -1120,12 +1110,10 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } } -//////////////////////////////////////////////////////////////////////////////////////////// /// Type privacy visitor, checks types for privacy and reports violations. +/// /// Both explicitly written types and inferred types of expressions and patterns are checked. /// Checks are performed on "semantic" types regardless of names and their hygiene. -//////////////////////////////////////////////////////////////////////////////////////////// - struct TypePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, module_def_id: LocalModDefId, @@ -1345,13 +1333,11 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { } } -/////////////////////////////////////////////////////////////////////////////// /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and /// finds any private components in it. +/// /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types /// and traits in public interfaces. -/////////////////////////////////////////////////////////////////////////////// - struct SearchInterfaceForPrivateItemsVisitor<'tcx> { tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, From 7a2c1730336e487eed37e97014b7864ebd81962b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 15:25:27 +0200 Subject: [PATCH 289/537] Add new `tyalias` intra-doc link disambiguator --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0da42f38251c..79d74c3c4eb9 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -130,6 +130,7 @@ impl Res { DefKind::Static { .. } => "static", DefKind::Field => "field", DefKind::Variant | DefKind::Ctor(..) => "variant", + DefKind::TyAlias => "tyalias", // Now handle things that don't have a specific disambiguator _ => match kind .ns() @@ -1708,6 +1709,7 @@ impl Disambiguator { "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), "prim" | "primitive" => Primitive, + "tyalias" | "typealias" => Kind(DefKind::TyAlias), _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)), }; From dba45cde68ba25b7fa790e4e36593b6fd55d6d8a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 15:25:51 +0200 Subject: [PATCH 290/537] Add tests for new `tyalias` intra-doc link disambiguator --- .../type-alias-primitive-suggestion.rs | 21 ++++++++++ .../type-alias-primitive-suggestion.stderr | 39 +++++++++++++++++++ .../intra-doc/type-alias-primitive.rs | 14 +++++++ .../rustdoc/intra-doc/type-alias-primitive.rs | 21 ++++++++++ 4 files changed, 95 insertions(+) create mode 100644 tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.rs create mode 100644 tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.stderr create mode 100644 tests/rustdoc-ui/intra-doc/type-alias-primitive.rs create mode 100644 tests/rustdoc/intra-doc/type-alias-primitive.rs diff --git a/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.rs b/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.rs new file mode 100644 index 000000000000..c4527c626d9c --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.rs @@ -0,0 +1,21 @@ +// Ensure that no warning is emitted if the disambiguator is used for type alias. +// Regression test for . + +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct Foo; + +#[allow(non_camel_case_types)] +pub type f32 = Foo; + +/// This function returns [`f32`]. +//~^ ERROR: `f32` is both a type alias and a primitive type +//~| HELP: to link to the type alias, prefix with `tyalias@` +//~| HELP: to link to the primitive type, prefix with `prim@` +pub fn my_fn() -> f32 {} + +/// This function returns [type@f32]. +//~^ ERROR: `f32` is both a type alias and a primitive type +//~| HELP: to link to the type alias, prefix with `tyalias@` +//~| HELP: to link to the primitive type, prefix with `prim@` +pub fn my_fn2() -> f32 {} diff --git a/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.stderr b/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.stderr new file mode 100644 index 000000000000..c99e7d1d1043 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/type-alias-primitive-suggestion.stderr @@ -0,0 +1,39 @@ +error: `f32` is both a type alias and a primitive type + --> $DIR/type-alias-primitive-suggestion.rs:11:29 + | +LL | /// This function returns [`f32`]. + | ^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/type-alias-primitive-suggestion.rs:4:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the type alias, prefix with `tyalias@` + | +LL | /// This function returns [`tyalias@f32`]. + | ++++++++ +help: to link to the primitive type, prefix with `prim@` + | +LL | /// This function returns [`prim@f32`]. + | +++++ + +error: `f32` is both a type alias and a primitive type + --> $DIR/type-alias-primitive-suggestion.rs:17:28 + | +LL | /// This function returns [type@f32]. + | ^^^^^^^^ ambiguous link + | +help: to link to the type alias, prefix with `tyalias@` + | +LL - /// This function returns [type@f32]. +LL + /// This function returns [tyalias@f32]. + | +help: to link to the primitive type, prefix with `prim@` + | +LL - /// This function returns [type@f32]. +LL + /// This function returns [prim@f32]. + | + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc-ui/intra-doc/type-alias-primitive.rs b/tests/rustdoc-ui/intra-doc/type-alias-primitive.rs new file mode 100644 index 000000000000..62b2c83eeca4 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/type-alias-primitive.rs @@ -0,0 +1,14 @@ +// Ensure that no warning is emitted if the disambiguator is used for type alias. +// Regression test for . + +//@ check-pass + +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct Foo; + +#[allow(non_camel_case_types)] +pub type f32 = Foo; + +/// This function returns [`tyalias@f32`] and not [`prim@f32`]. +pub fn my_fn() -> f32 {} diff --git a/tests/rustdoc/intra-doc/type-alias-primitive.rs b/tests/rustdoc/intra-doc/type-alias-primitive.rs new file mode 100644 index 000000000000..7504166cbcce --- /dev/null +++ b/tests/rustdoc/intra-doc/type-alias-primitive.rs @@ -0,0 +1,21 @@ +// Ensure that no warning is emitted if the disambiguator is used for type alias. +// Regression test for . + +#![crate_name = "foo"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct Foo; + +#[allow(non_camel_case_types)] +pub type f32 = Foo; + +/// This function returns [`tyalias@f32`] and not [bla][`prim@f32`]. +//@ has 'foo/fn.my_fn.html' +//@ has - '//a[@href="type.f32.html"]' "f32" +//@ has - '//a[@href="{{channel}}/std/primitive.f32.html"]' "bla" +pub fn my_fn() -> f32 { 0. } + +/// This function returns [`typealias@f32`]. +//@ has 'foo/fn.my_other_fn.html' +//@ has - '//a[@href="type.f32.html"]' "f32" +pub fn my_other_fn() -> f32 { 0. } From 62c457bb02488dc6df95c574f34dd0ce444475dd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 15:27:00 +0200 Subject: [PATCH 291/537] Mention `tyalias` in intra-doc link rustdoc book chapter --- .../rustdoc/src/write-documentation/linking-to-items-by-name.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 5e7854834028..b1495b2575e2 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -90,7 +90,7 @@ fn Foo() {} These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`, `mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`, -`type`, `value`, `macro`, `prim` or `primitive`. +`type`, `value`, `macro`, `tyalias`, `typealias`, `prim` or `primitive`. You can also disambiguate for functions by adding `()` after the function name, or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`, From 4a0c7cc730a5434574c41a6073d9efb92141af1a Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 Sep 2025 13:48:22 +0200 Subject: [PATCH 292/537] fix cycle head usages tracking --- .../src/solve/search_graph.rs | 22 ++- .../rustc_type_ir/src/search_graph/mod.rs | 141 ++++++++++++------ .../ignore-head-usages-provisional-cache.rs | 55 +++++++ 3 files changed, 166 insertions(+), 52 deletions(-) create mode 100644 tests/ui/traits/next-solver/cycles/ignore-head-usages-provisional-cache.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index aa9dfc9a9a26..4ae2af59a703 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -74,13 +74,21 @@ where } } - fn is_initial_provisional_result( - cx: Self::Cx, - kind: PathKind, - input: CanonicalInput, - result: QueryResult, - ) -> bool { - Self::initial_provisional_result(cx, kind, input) == result + fn is_initial_provisional_result(result: QueryResult) -> Option { + match result { + Ok(response) => { + if has_no_inference_or_external_constraints(response) { + if response.value.certainty == Certainty::Yes { + return Some(PathKind::Coinductive); + } else if response.value.certainty == Certainty::overflow(false) { + return Some(PathKind::Unknown); + } + } + + None + } + Err(NoSolution) => Some(PathKind::Inductive), + } } fn on_stack_overflow(cx: I, input: CanonicalInput) -> QueryResult { diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8f8f019510fe..a7902cd02103 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -86,12 +86,7 @@ pub trait Delegate: Sized { kind: PathKind, input: ::Input, ) -> ::Result; - fn is_initial_provisional_result( - cx: Self::Cx, - kind: PathKind, - input: ::Input, - result: ::Result, - ) -> bool; + fn is_initial_provisional_result(result: ::Result) -> Option; fn on_stack_overflow(cx: Self::Cx, input: ::Input) -> ::Result; fn on_fixpoint_overflow( cx: Self::Cx, @@ -215,6 +210,27 @@ impl HeadUsages { let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = self; inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0 } + + fn is_single(self, path_kind: PathKind) -> bool { + match path_kind { + PathKind::Inductive => matches!( + self, + HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 }, + ), + PathKind::Unknown => matches!( + self, + HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 }, + ), + PathKind::Coinductive => matches!( + self, + HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 }, + ), + PathKind::ForcedAmbiguity => matches!( + self, + HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ }, + ), + } + } } #[derive(Debug, Default)] @@ -888,7 +904,29 @@ impl, X: Cx> SearchGraph { !entries.is_empty() }); } +} +/// We need to rebase provisional cache entries when popping one of their cycle +/// 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. +enum RebaseReason { + NoCycleUsages, + Ambiguity, + Overflow, + /// We've actually reached a fixpoint. + /// + /// This either happens in the first evaluation step for the cycle head. + /// In this case the used provisional result depends on the cycle `PathKind`. + /// We store this path kind to check whether the the provisional cache entry + /// we're rebasing relied on the same cycles. + /// + /// In later iterations cycles always return `stack_entry.provisional_result` + /// so we no longer depend on the `PathKind`. We store `None` in that case. + ReachedFixpoint(Option), +} + +impl, X: Cx> SearchGraph { /// A necessary optimization to handle complex solver cycles. A provisional cache entry /// relies on a set of cycle heads and the path towards these heads. When popping a cycle /// head from the stack after we've finished computing it, we can't be sure that the @@ -908,8 +946,9 @@ impl, X: Cx> SearchGraph { /// to me. fn rebase_provisional_cache_entries( &mut self, + cx: X, stack_entry: &StackEntry, - mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result, + rebase_reason: RebaseReason, ) { let popped_head_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] @@ -927,6 +966,10 @@ impl, X: Cx> SearchGraph { return true; }; + let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { + return false; + }; + // We're rebasing an entry `e` over a head `p`. This head // has a number of own heads `h` it depends on. // @@ -977,22 +1020,37 @@ impl, X: Cx> SearchGraph { let eph = ep.extend_with_paths(ph); heads.insert(head_index, eph, head.usages); } - } - let Some(head_index) = heads.opt_highest_cycle_head_index() else { - return false; - }; + // The provisional cache entry does depend on the provisional result + // of the popped cycle head. We need to mutate the result of our + // provisional cache entry in case we did not reach a fixpoint. + match rebase_reason { + // If the cycle head does not actually depend on itself, then + // the provisional result used by the provisional cache entry + // is not actually equal to the final provisional result. We + // need to discard the provisional cache entry in this case. + RebaseReason::NoCycleUsages => return false, + RebaseReason::Ambiguity => { + *result = D::propagate_ambiguity(cx, input, *result); + } + RebaseReason::Overflow => *result = D::on_fixpoint_overflow(cx, input), + RebaseReason::ReachedFixpoint(None) => {} + RebaseReason::ReachedFixpoint(Some(path_kind)) => { + if !popped_head.usages.is_single(path_kind) { + return false; + } + } + }; + } // We now care about the path from the next highest cycle head to the // provisional cache entry. *path_from_head = path_from_head.extend(Self::cycle_path_kind( &self.stack, stack_entry.step_kind_from_parent, - head_index, + new_highest_head_index, )); - // Mutate the result of the provisional cache entry in case we did - // not reach a fixpoint. - *result = mutate_result(input, *result); + true }); !entries.is_empty() @@ -1209,33 +1267,19 @@ impl, X: Cx> SearchGraph { /// Whether we've reached a fixpoint when evaluating a cycle head. fn reached_fixpoint( &mut self, - cx: X, stack_entry: &StackEntry, usages: HeadUsages, result: X::Result, - ) -> bool { + ) -> Result, ()> { let provisional_result = stack_entry.provisional_result; - if usages.is_empty() { - true - } else if let Some(provisional_result) = provisional_result { - provisional_result == result + if let Some(provisional_result) = provisional_result { + if provisional_result == result { Ok(None) } else { Err(()) } + } else if let Some(path_kind) = D::is_initial_provisional_result(result) + .filter(|&path_kind| usages.is_single(path_kind)) + { + Ok(Some(path_kind)) } else { - let check = |k| D::is_initial_provisional_result(cx, k, stack_entry.input, result); - match usages { - HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 } => { - check(PathKind::Inductive) - } - HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 } => { - check(PathKind::Unknown) - } - HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 } => { - check(PathKind::Coinductive) - } - HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ } => { - check(PathKind::ForcedAmbiguity) - } - _ => false, - } + Err(()) } } @@ -1280,8 +1324,19 @@ impl, X: Cx> SearchGraph { // is equal to the provisional result of the previous iteration, or because // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. - if self.reached_fixpoint(cx, &stack_entry, usages, result) { - self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); + if let Ok(fixpoint) = self.reached_fixpoint(&stack_entry, usages, result) { + self.rebase_provisional_cache_entries( + cx, + &stack_entry, + RebaseReason::ReachedFixpoint(fixpoint), + ); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); + } else if usages.is_empty() { + self.rebase_provisional_cache_entries( + cx, + &stack_entry, + RebaseReason::NoCycleUsages, + ); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } @@ -1298,9 +1353,7 @@ impl, X: Cx> SearchGraph { // we also taint all provisional cache entries which depend on the // current goal. if D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries(&stack_entry, |input, _| { - D::propagate_ambiguity(cx, input, result) - }); + self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; @@ -1310,9 +1363,7 @@ impl, X: Cx> SearchGraph { if i >= D::FIXPOINT_STEP_LIMIT { debug!("canonical cycle overflow"); let result = D::on_fixpoint_overflow(cx, input); - self.rebase_provisional_cache_entries(&stack_entry, |input, _| { - D::on_fixpoint_overflow(cx, input) - }); + self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Overflow); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } diff --git a/tests/ui/traits/next-solver/cycles/ignore-head-usages-provisional-cache.rs b/tests/ui/traits/next-solver/cycles/ignore-head-usages-provisional-cache.rs new file mode 100644 index 000000000000..9a33ae536442 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/ignore-head-usages-provisional-cache.rs @@ -0,0 +1,55 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#232. We've +// previously incorrectly rebased provisional cache entries even if +// the cycle head didn't reach a fixpoint as it did not depend on any +// cycles itself. +// +// Just because the result of a goal does not depend on its own provisional +// result, it does not mean its nested goals don't depend on its result. +struct B; +struct C; +struct D; + +pub trait Trait { + type Output; +} +macro_rules! k { + ($t:ty) => { + <$t as Trait>::Output + }; +} + +trait CallB { + type Output; + type Return; +} + +trait CallC { + type Output; + type Return; +} + +trait CallD { + type Output; +} + +fn foo() +where + X: Trait, + Y: Trait, + D: CallD, + C: CallC<>::Output>, + >::Output>>::Output: Trait, + B: CallB< + >::Output>>::Return, + >::Output>>::Output, + >, + >::Output>>::Return, + >::Output>>::Output, + >>::Output: Trait, +{ +} +fn main() {} From 4e44d58bbc199ff7c17a98b283621a6df327d60f Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 Sep 2025 14:51:13 +0200 Subject: [PATCH 293/537] rename `search_graph::Delegate` fns --- .../src/solve/search_graph.rs | 4 ++-- compiler/rustc_type_ir/src/search_graph/mod.rs | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 4ae2af59a703..109c8476ccb1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -91,11 +91,11 @@ where } } - fn on_stack_overflow(cx: I, input: CanonicalInput) -> QueryResult { + fn stack_overflow_result(cx: I, input: CanonicalInput) -> QueryResult { response_no_constraints(cx, input, Certainty::overflow(true)) } - fn on_fixpoint_overflow(cx: I, input: CanonicalInput) -> QueryResult { + fn fixpoint_overflow_result(cx: I, input: CanonicalInput) -> QueryResult { response_no_constraints(cx, input, Certainty::overflow(false)) } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index a7902cd02103..7aa58d096d5c 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -87,8 +87,11 @@ pub trait Delegate: Sized { input: ::Input, ) -> ::Result; fn is_initial_provisional_result(result: ::Result) -> Option; - fn on_stack_overflow(cx: Self::Cx, input: ::Input) -> ::Result; - fn on_fixpoint_overflow( + fn stack_overflow_result( + cx: Self::Cx, + input: ::Input, + ) -> ::Result; + fn fixpoint_overflow_result( cx: Self::Cx, input: ::Input, ) -> ::Result; @@ -885,7 +888,7 @@ impl, X: Cx> SearchGraph { } debug!("encountered stack overflow"); - D::on_stack_overflow(cx, input) + D::stack_overflow_result(cx, input) } /// When reevaluating a goal with a changed provisional result, all provisional cache entry @@ -1033,7 +1036,7 @@ impl, X: Cx> SearchGraph { RebaseReason::Ambiguity => { *result = D::propagate_ambiguity(cx, input, *result); } - RebaseReason::Overflow => *result = D::on_fixpoint_overflow(cx, input), + RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input), RebaseReason::ReachedFixpoint(None) => {} RebaseReason::ReachedFixpoint(Some(path_kind)) => { if !popped_head.usages.is_single(path_kind) { @@ -1362,7 +1365,7 @@ impl, X: Cx> SearchGraph { i += 1; if i >= D::FIXPOINT_STEP_LIMIT { debug!("canonical cycle overflow"); - let result = D::on_fixpoint_overflow(cx, input); + let result = D::fixpoint_overflow_result(cx, input); self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Overflow); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } From a535c7be5444fb6584eecc99f53e6cdb710ff70f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Sep 2025 13:59:06 +0200 Subject: [PATCH 294/537] Ignore more failing ui tests for GCC backend --- .../array-slice-vec/box-of-array-of-drop-1.rs | 1 + .../array-slice-vec/box-of-array-of-drop-2.rs | 1 + tests/ui/array-slice-vec/nested-vec-3.rs | 1 + tests/ui/array-slice-vec/slice-panic-1.rs | 1 + tests/ui/array-slice-vec/slice-panic-2.rs | 1 + .../asm/global-asm-isnt-really-a-mir-body.rs | 1 + tests/ui/asm/x86_64/goto.rs | 1 + tests/ui/asm/x86_64/goto.stderr | 4 +- tests/ui/asm/x86_64/srcloc.rs | 1 + tests/ui/asm/x86_64/srcloc.stderr | 50 ++++----- tests/ui/attributes/fn-align-dyn.rs | 1 + tests/ui/attributes/main-removed-2/main.rs | 1 + .../backtrace/synchronized-panic-handler.rs | 1 + .../synchronized-panic-handler.run.stderr | 4 +- tests/ui/box/unit/unwind-unique.rs | 1 + tests/ui/c-variadic/inherent-method.rs | 1 + tests/ui/c-variadic/trait-method.rs | 1 + tests/ui/c-variadic/valid.rs | 1 + .../assume-incomplete.rs | 1 + .../codegen/issue-82833-slice-miscompile.rs | 1 + tests/ui/codegen/llvm-args-invalid-flag.rs | 1 + tests/ui/codegen/remark-flag-functionality.rs | 1 + .../codegen/virtual-function-elimination.rs | 1 + tests/ui/coroutine/gen_block_panic.rs | 1 + tests/ui/coroutine/gen_block_panic.stderr | 2 +- tests/ui/delegation/fn-header-variadic.rs | 1 + tests/ui/delegation/fn-header-variadic.stderr | 4 +- tests/ui/drop/drop-trait-enum.rs | 1 + tests/ui/drop/terminate-in-initializer.rs | 1 + .../callee_is_track_caller.rs | 1 + .../callee_is_track_caller.stderr | 2 +- .../callee_is_track_caller_polymorphic.rs | 1 + .../callee_is_track_caller_polymorphic.stderr | 2 +- tests/ui/explicit-tail-calls/drop-order.rs | 1 + tests/ui/explicit-tail-calls/indexer.rs | 1 + tests/ui/explicit-tail-calls/recursion-etc.rs | 1 + tests/ui/extern/extern-types-field-offset.rs | 1 + ...llow-unwind-when-calling-panic-directly.rs | 1 + ...sue-64655-extern-rust-must-allow-unwind.rs | 1 + ...at-args-capture-from-pm-first-arg-macro.rs | 1 + ...rgs-capture-from-pm-first-arg-macro.stderr | 2 +- tests/ui/frontmatter/proc-macro-observer.rs | 1 + .../issue-77523-def-site-async-await.rs | 1 + .../precise-capturing/external-macro.rs | 1 + .../invalid-llvm-passes.rs | 1 + tests/ui/issues/issue-25089.rs | 1 + tests/ui/issues/issue-26655.rs | 1 + tests/ui/issues/issue-29485.rs | 1 + tests/ui/issues/issue-30018-panic.rs | 1 + tests/ui/issues/issue-44056.rs | 1 + .../issues/issue-68696-catch-during-unwind.rs | 1 + .../common-linkage-non-zero-init.rs | 1 + .../raw-dylib/elf/glibc-x86_64.rs | 1 + .../ui/linking/no-gc-encapsulation-symbols.rs | 1 + ...nused-qualification-in-derive-expansion.rs | 1 + tests/ui/lto/debuginfo-lto-alloc.rs | 1 + tests/ui/lto/debuginfo-lto.rs | 1 + tests/ui/lto/dwarf-mixed-versions-lto.rs | 1 + tests/ui/lto/fat-lto.rs | 1 + tests/ui/lto/issue-100772.rs | 1 + tests/ui/lto/lto-duplicate-symbols.rs | 1 + tests/ui/lto/lto-many-codegen-units.rs | 1 + tests/ui/lto/lto-rustc-loads-linker-plugin.rs | 1 + tests/ui/lto/lto-still-runs-thread-dtors.rs | 1 + tests/ui/macros/same-sequence-span.rs | 1 + tests/ui/macros/same-sequence-span.stderr | 12 +- .../ui/numbers-arithmetic/int-abs-overflow.rs | 1 + tests/ui/numbers-arithmetic/issue-8460.rs | 1 + tests/ui/panic-runtime/lto-unwind.rs | 1 + tests/ui/panics/oom-panic-unwind.rs | 1 + .../panics/panic-handler-chain-update-hook.rs | 1 + tests/ui/panics/panic-handler-chain.rs | 1 + tests/ui/panics/panic-handler-flail-wildly.rs | 1 + tests/ui/panics/panic-handler-set-twice.rs | 1 + tests/ui/panics/panic-in-dtor-drops-fields.rs | 1 + tests/ui/panics/panic-recover-propagate.rs | 1 + .../panics/rvalue-cleanup-during-box-panic.rs | 1 + .../panics/unwind-force-no-unwind-tables.rs | 1 + ...971-outer-attr-following-inner-attr-ice.rs | 1 + ...outer-attr-following-inner-attr-ice.stderr | 2 +- .../unicode-control-codepoints-macros.rs | 1 + .../unicode-control-codepoints-macros.stderr | 10 +- .../parser/tuple-index-suffix-proc-macro.rs | 1 + .../tuple-index-suffix-proc-macro.stderr | 8 +- tests/ui/proc-macro/add-impl.rs | 1 + .../ambiguous-builtin-attrs-test.rs | 1 + .../ambiguous-builtin-attrs-test.stderr | 2 +- .../ui/proc-macro/ambiguous-builtin-attrs.rs | 1 + .../proc-macro/ambiguous-builtin-attrs.stderr | 30 ++--- tests/ui/proc-macro/append-impl.rs | 1 + tests/ui/proc-macro/attr-args.rs | 1 + tests/ui/proc-macro/attr-invalid-exprs.rs | 1 + tests/ui/proc-macro/attr-invalid-exprs.stderr | 6 +- tests/ui/proc-macro/attr-on-trait.rs | 1 + tests/ui/proc-macro/bang-macro.rs | 1 + tests/ui/proc-macro/call-site.rs | 1 + tests/ui/proc-macro/count_compound_ops.rs | 1 + tests/ui/proc-macro/derive-bad.rs | 1 + tests/ui/proc-macro/derive-bad.stderr | 6 +- .../ui/proc-macro/derive-helper-shadowing.rs | 1 + .../proc-macro/derive-helper-shadowing.stderr | 18 +-- tests/ui/proc-macro/derive-same-struct.rs | 1 + tests/ui/proc-macro/edition-imports-2018.rs | 1 + tests/ui/proc-macro/env.rs | 1 + tests/ui/proc-macro/expand-expr.rs | 3 +- tests/ui/proc-macro/expand-expr.stderr | 14 +-- tests/ui/proc-macro/expand-to-unstable.rs | 1 + tests/ui/proc-macro/expand-to-unstable.stderr | 2 +- tests/ui/proc-macro/expand-with-a-macro.rs | 1 + .../ui/proc-macro/gen-macro-rules-hygiene.rs | 1 + .../proc-macro/gen-macro-rules-hygiene.stderr | 6 +- tests/ui/proc-macro/gen-macro-rules.rs | 1 + tests/ui/proc-macro/generate-mod.rs | 1 + tests/ui/proc-macro/generate-mod.stderr | 28 ++--- tests/ui/proc-macro/hygiene_example.rs | 1 + tests/ui/proc-macro/is-available.rs | 1 + .../issue-104884-trait-impl-sugg-err.rs | 1 + .../issue-104884-trait-impl-sugg-err.stderr | 18 +-- tests/ui/proc-macro/issue-107113-wrap.rs | 1 + tests/ui/proc-macro/issue-107113-wrap.stderr | 2 +- tests/ui/proc-macro/issue-118809.rs | 1 + tests/ui/proc-macro/issue-118809.stderr | 4 +- tests/ui/proc-macro/issue-38586.rs | 1 + tests/ui/proc-macro/issue-38586.stderr | 2 +- .../issue-59191-replace-root-with-fn.rs | 1 + tests/ui/proc-macro/issue-79148.rs | 1 + tests/ui/proc-macro/issue-79148.stderr | 4 +- tests/ui/proc-macro/issue-83510.rs | 1 + tests/ui/proc-macro/issue-83510.stderr | 8 +- tests/ui/proc-macro/issue-91800.rs | 1 + tests/ui/proc-macro/issue-91800.stderr | 14 +-- tests/ui/proc-macro/lifetimes-rpass.rs | 1 + tests/ui/proc-macro/lints_in_proc_macros.rs | 1 + .../ui/proc-macro/lints_in_proc_macros.stderr | 2 +- tests/ui/proc-macro/load-two.rs | 1 + .../proc-macro/macro-crate-multi-decorator.rs | 1 + .../proc-macro/macro_rules_edition_from_pm.rs | 1 + tests/ui/proc-macro/match-expander.rs | 1 + tests/ui/proc-macro/match-expander.stderr | 2 +- tests/ui/proc-macro/mixed-site-span.rs | 1 + tests/ui/proc-macro/mixed-site-span.stderr | 104 +++++++++--------- tests/ui/proc-macro/modify-ast.rs | 1 + tests/ui/proc-macro/parent-source-spans.rs | 1 + .../ui/proc-macro/parent-source-spans.stderr | 42 +++---- tests/ui/proc-macro/quote/basic.rs | 1 + tests/ui/proc-macro/span-api-tests.rs | 1 + tests/ui/proc-macro/span-from-proc-macro.rs | 1 + .../ui/proc-macro/span-from-proc-macro.stderr | 8 +- tests/ui/proc-macro/weird-hygiene.rs | 1 + tests/ui/proc-macro/weird-hygiene.stderr | 4 +- tests/ui/process/multi-panic.rs | 1 + tests/ui/resolve/prelude-order.rs | 1 + tests/ui/resolve/prelude-order.stderr | 10 +- .../edition-spans.rs | 1 + tests/ui/runtime/backtrace-debuginfo.rs | 1 + tests/ui/runtime/out-of-stack.rs | 1 + .../suggestions-not-always-applicable.fixed | 1 + .../suggestions-not-always-applicable.rs | 1 + .../rust-2021/reserved-prefixes-via-macro.rs | 1 + .../reserved-guarded-strings-via-macro.rs | 1 + .../unsafe-attributes-from-pm.rs | 1 + .../sanitizer/cfi/transparent-has-regions.rs | 1 + .../issue-111184-cfi-coroutine-witness.rs | 1 + tests/ui/sepcomp/sepcomp-lib-lto.rs | 1 + tests/ui/sepcomp/sepcomp-unwind.rs | 1 + .../ui/simd/intrinsic/generic-arithmetic-2.rs | 1 + .../intrinsic/generic-arithmetic-2.stderr | 56 +++++----- tests/ui/simd/intrinsic/generic-elements.rs | 1 + .../ui/simd/intrinsic/generic-elements.stderr | 42 +++---- tests/ui/simd/masked-load-store-build-fail.rs | 1 + .../simd/masked-load-store-build-fail.stderr | 16 +-- .../monomorphize-shuffle-index.generic.stderr | 2 +- tests/ui/simd/monomorphize-shuffle-index.rs | 1 + tests/ui/simd/not-out-of-bounds.rs | 1 + tests/ui/simd/not-out-of-bounds.stderr | 18 +-- .../unit-like-struct-drop-run.rs | 1 + tests/ui/suggestions/issue-61963.rs | 1 + tests/ui/suggestions/issue-61963.stderr | 6 +- tests/ui/suggestions/suggest-ref-macro.rs | 1 + tests/ui/suggestions/suggest-ref-macro.stderr | 12 +- .../test-attrs/test-panic-while-printing.rs | 1 + tests/ui/threads-sendsync/task-stderr.rs | 1 + tests/ui/threads-sendsync/unwind-resource.rs | 1 + tests/ui/traits/clone-unwind-rc-cleanup.rs | 1 + ...alid-sugg-for-derive-macro-issue-136343.rs | 1 + ...-sugg-for-derive-macro-issue-136343.stderr | 2 +- 186 files changed, 440 insertions(+), 297 deletions(-) diff --git a/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs b/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs index c7c05946c4ca..5f4e381c983a 100644 --- a/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs +++ b/tests/ui/array-slice-vec/box-of-array-of-drop-1.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc #![allow(overflowing_literals)] diff --git a/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs b/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs index 98175a26ec0d..ea37d3e72126 100644 --- a/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs +++ b/tests/ui/array-slice-vec/box-of-array-of-drop-2.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc #![allow(overflowing_literals)] diff --git a/tests/ui/array-slice-vec/nested-vec-3.rs b/tests/ui/array-slice-vec/nested-vec-3.rs index 51975743742c..e3c04ed6f6bf 100644 --- a/tests/ui/array-slice-vec/nested-vec-3.rs +++ b/tests/ui/array-slice-vec/nested-vec-3.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc #![allow(overflowing_literals)] diff --git a/tests/ui/array-slice-vec/slice-panic-1.rs b/tests/ui/array-slice-vec/slice-panic-1.rs index a745dff96afc..d7c1098fa2bd 100644 --- a/tests/ui/array-slice-vec/slice-panic-1.rs +++ b/tests/ui/array-slice-vec/slice-panic-1.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc // Test that if a slicing expr[..] fails, the correct cleanups happen. diff --git a/tests/ui/array-slice-vec/slice-panic-2.rs b/tests/ui/array-slice-vec/slice-panic-2.rs index 483a4cbe245d..157e716a95d4 100644 --- a/tests/ui/array-slice-vec/slice-panic-2.rs +++ b/tests/ui/array-slice-vec/slice-panic-2.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc // Test that if a slicing expr[..] fails, the correct cleanups happen. diff --git a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs index aef25d057d4b..94dab4235e09 100644 --- a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs +++ b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs @@ -18,6 +18,7 @@ //@ build-pass //@ needs-asm-support +//@ ignore-backends: gcc use std::arch::global_asm; diff --git a/tests/ui/asm/x86_64/goto.rs b/tests/ui/asm/x86_64/goto.rs index 00a8e588f967..c1dbce0d1c91 100644 --- a/tests/ui/asm/x86_64/goto.rs +++ b/tests/ui/asm/x86_64/goto.rs @@ -1,6 +1,7 @@ //@ only-x86_64 //@ run-pass //@ needs-asm-support +//@ ignore-backends: gcc #![deny(unreachable_code)] #![feature(asm_goto_with_outputs)] diff --git a/tests/ui/asm/x86_64/goto.stderr b/tests/ui/asm/x86_64/goto.stderr index 78b726b3f3d3..f8f09f32f6cb 100644 --- a/tests/ui/asm/x86_64/goto.stderr +++ b/tests/ui/asm/x86_64/goto.stderr @@ -1,5 +1,5 @@ warning: unreachable statement - --> $DIR/goto.rs:143:9 + --> $DIR/goto.rs:144:9 | LL | / asm!( LL | | "jmp {}", @@ -13,7 +13,7 @@ LL | unreachable!(); | ^^^^^^^^^^^^^^ unreachable statement | note: the lint level is defined here - --> $DIR/goto.rs:133:8 + --> $DIR/goto.rs:134:8 | LL | #[warn(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index 2938bafe5e70..f4ffa8c5c3b2 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,6 +1,7 @@ //@ only-x86_64 //@ build-fail //@ compile-flags: -Ccodegen-units=1 +//@ ignore-backends: gcc use std::arch::asm; diff --git a/tests/ui/asm/x86_64/srcloc.stderr b/tests/ui/asm/x86_64/srcloc.stderr index bb4e855163d7..b2079120ec06 100644 --- a/tests/ui/asm/x86_64/srcloc.stderr +++ b/tests/ui/asm/x86_64/srcloc.stderr @@ -1,5 +1,5 @@ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:11:15 + --> $DIR/srcloc.rs:12:15 | LL | asm!("invalid_instruction"); | ^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:15:13 + --> $DIR/srcloc.rs:16:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:20:13 + --> $DIR/srcloc.rs:21:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:26:13 + --> $DIR/srcloc.rs:27:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:33:13 + --> $DIR/srcloc.rs:34:13 | LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:38:14 + --> $DIR/srcloc.rs:39:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:41:15 + --> $DIR/srcloc.rs:42:15 | LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2) | ^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:45:14 + --> $DIR/srcloc.rs:46:14 | LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:51:14 + --> $DIR/srcloc.rs:52:14 | LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:58:14 + --> $DIR/srcloc.rs:59:14 | LL | "invalid_instruction", | ^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:65:13 + --> $DIR/srcloc.rs:66:13 | LL | concat!("invalid", "_", "instruction"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:72:13 + --> $DIR/srcloc.rs:73:13 | LL | concat!("invalid", "_", "instruction"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:79:14 + --> $DIR/srcloc.rs:80:14 | LL | "invalid_instruction1", | ^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:80:14 + --> $DIR/srcloc.rs:81:14 | LL | "invalid_instruction2", | ^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:87:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -182,7 +182,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:87:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -197,7 +197,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:96:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -212,7 +212,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:96:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -227,7 +227,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:100:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -242,7 +242,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:100:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -257,7 +257,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:111:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -272,7 +272,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:111:13 | LL | / concat!( LL | | "invalid", "_", "instruction1", "\n", @@ -287,7 +287,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:115:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -302,7 +302,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:115:13 | LL | / concat!( LL | | "invalid", "_", "instruction3", "\n", @@ -317,7 +317,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:127:14 + --> $DIR/srcloc.rs:128:14 | LL | "invalid_instruction" | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/attributes/fn-align-dyn.rs b/tests/ui/attributes/fn-align-dyn.rs index 3778c75a2caa..91e2dab65a3c 100644 --- a/tests/ui/attributes/fn-align-dyn.rs +++ b/tests/ui/attributes/fn-align-dyn.rs @@ -1,5 +1,6 @@ //@ run-pass //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) +//@ ignore-backends: gcc // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity #![feature(rustc_attrs)] diff --git a/tests/ui/attributes/main-removed-2/main.rs b/tests/ui/attributes/main-removed-2/main.rs index 53696d68ced0..21a05dc4b40b 100644 --- a/tests/ui/attributes/main-removed-2/main.rs +++ b/tests/ui/attributes/main-removed-2/main.rs @@ -2,6 +2,7 @@ //@ proc-macro: tokyo.rs //@ compile-flags:--extern tokyo //@ edition:2021 +//@ ignore-backends: gcc use tokyo::main; diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs index 29431ae3c458..ef7cc1faec8d 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.rs +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -4,6 +4,7 @@ //@ exec-env:RUST_BACKTRACE=0 //@ needs-threads //@ needs-unwind +//@ ignore-backends: gcc use std::thread; const PANIC_MESSAGE: &str = "oops oh no woe is me"; diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr index c604d49c193c..5296a0d39ff3 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.run.stderr +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -1,7 +1,7 @@ -thread '' ($TID) panicked at $DIR/synchronized-panic-handler.rs:11:5: +thread '' ($TID) panicked at $DIR/synchronized-panic-handler.rs:12:5: oops oh no woe is me note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread '' ($TID) panicked at $DIR/synchronized-panic-handler.rs:11:5: +thread '' ($TID) panicked at $DIR/synchronized-panic-handler.rs:12:5: oops oh no woe is me diff --git a/tests/ui/box/unit/unwind-unique.rs b/tests/ui/box/unit/unwind-unique.rs index 1da55c45ee96..ed549f50a740 100644 --- a/tests/ui/box/unit/unwind-unique.rs +++ b/tests/ui/box/unit/unwind-unique.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc use std::thread; diff --git a/tests/ui/c-variadic/inherent-method.rs b/tests/ui/c-variadic/inherent-method.rs index 537bae7b3f0f..c5256aaa1fea 100644 --- a/tests/ui/c-variadic/inherent-method.rs +++ b/tests/ui/c-variadic/inherent-method.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(c_variadic)] #[repr(transparent)] diff --git a/tests/ui/c-variadic/trait-method.rs b/tests/ui/c-variadic/trait-method.rs index 97da0706a3a1..876a303f53ba 100644 --- a/tests/ui/c-variadic/trait-method.rs +++ b/tests/ui/c-variadic/trait-method.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(c_variadic)] #[repr(transparent)] diff --git a/tests/ui/c-variadic/valid.rs b/tests/ui/c-variadic/valid.rs index 5a0b32026dc7..8b42eb493290 100644 --- a/tests/ui/c-variadic/valid.rs +++ b/tests/ui/c-variadic/valid.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![feature(c_variadic)] // In rust (and C23 and above) `...` can be the only argument. diff --git a/tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs b/tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs index cafb7389e29f..2ca004d9a906 100644 --- a/tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs +++ b/tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs @@ -2,6 +2,7 @@ //@ proc-macro: ver-cfg-rel.rs //@ revisions: assume no_assume //@ [assume]compile-flags: -Z assume-incomplete-release +//@ ignore-backends: gcc #![feature(cfg_version)] diff --git a/tests/ui/codegen/issue-82833-slice-miscompile.rs b/tests/ui/codegen/issue-82833-slice-miscompile.rs index 32eac923a636..e0cb87166296 100644 --- a/tests/ui/codegen/issue-82833-slice-miscompile.rs +++ b/tests/ui/codegen/issue-82833-slice-miscompile.rs @@ -1,5 +1,6 @@ //@ run-pass //@ compile-flags: -Ccodegen-units=1 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Copt-level=0 -Cdebuginfo=2 +//@ ignore-backends: gcc // Make sure LLVM does not miscompile this. diff --git a/tests/ui/codegen/llvm-args-invalid-flag.rs b/tests/ui/codegen/llvm-args-invalid-flag.rs index a8fa55a220a5..f88a7101abda 100644 --- a/tests/ui/codegen/llvm-args-invalid-flag.rs +++ b/tests/ui/codegen/llvm-args-invalid-flag.rs @@ -1,6 +1,7 @@ //@ compile-flags: -Cllvm-args=-not-a-real-llvm-arg //@ normalize-stderr: "--help" -> "-help" //@ normalize-stderr: "\n(\n|.)*" -> "" +//@ ignore-backends: gcc // I'm seeing "--help" locally, but "-help" in CI, so I'm normalizing it to just "-help". diff --git a/tests/ui/codegen/remark-flag-functionality.rs b/tests/ui/codegen/remark-flag-functionality.rs index 797c55ba830c..4cfc5f5c8ec1 100644 --- a/tests/ui/codegen/remark-flag-functionality.rs +++ b/tests/ui/codegen/remark-flag-functionality.rs @@ -17,6 +17,7 @@ //@ dont-check-compiler-stderr //@ dont-require-annotations: NOTE +//@ ignore-backends: gcc #[no_mangle] #[inline(never)] diff --git a/tests/ui/codegen/virtual-function-elimination.rs b/tests/ui/codegen/virtual-function-elimination.rs index 3cbeb1293e50..90fc86f95c5c 100644 --- a/tests/ui/codegen/virtual-function-elimination.rs +++ b/tests/ui/codegen/virtual-function-elimination.rs @@ -2,6 +2,7 @@ //@ compile-flags: -Zvirtual-function-elimination=true -Clto=true //@ only-x86_64 //@ no-prefer-dynamic +//@ ignore-backends: gcc // issue #123955 pub fn test0() { diff --git a/tests/ui/coroutine/gen_block_panic.rs b/tests/ui/coroutine/gen_block_panic.rs index b6362d5046a3..5417ed583e8c 100644 --- a/tests/ui/coroutine/gen_block_panic.rs +++ b/tests/ui/coroutine/gen_block_panic.rs @@ -1,6 +1,7 @@ //@ edition: 2024 //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![feature(gen_blocks)] fn main() { diff --git a/tests/ui/coroutine/gen_block_panic.stderr b/tests/ui/coroutine/gen_block_panic.stderr index a43c9e03691a..d0a146e7baf9 100644 --- a/tests/ui/coroutine/gen_block_panic.stderr +++ b/tests/ui/coroutine/gen_block_panic.stderr @@ -1,5 +1,5 @@ warning: unreachable statement - --> $DIR/gen_block_panic.rs:10:9 + --> $DIR/gen_block_panic.rs:11:9 | LL | panic!("foo"); | ------------- any code following this expression is unreachable diff --git a/tests/ui/delegation/fn-header-variadic.rs b/tests/ui/delegation/fn-header-variadic.rs index 2c83d64d0b3f..346c49f08e5d 100644 --- a/tests/ui/delegation/fn-header-variadic.rs +++ b/tests/ui/delegation/fn-header-variadic.rs @@ -1,4 +1,5 @@ //@ aux-crate:fn_header_aux=fn-header-aux.rs +//@ ignore-backends: gcc #![feature(c_variadic)] #![feature(fn_delegation)] diff --git a/tests/ui/delegation/fn-header-variadic.stderr b/tests/ui/delegation/fn-header-variadic.stderr index 688a965fb4d5..c2d7672939fc 100644 --- a/tests/ui/delegation/fn-header-variadic.stderr +++ b/tests/ui/delegation/fn-header-variadic.stderr @@ -1,5 +1,5 @@ error: delegation to C-variadic functions is not allowed - --> $DIR/fn-header-variadic.rs:11:17 + --> $DIR/fn-header-variadic.rs:12:17 | LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} | ------------------------------------------------------------- callee defined here @@ -8,7 +8,7 @@ LL | reuse to_reuse::variadic_fn; | ^^^^^^^^^^^ error: delegation to C-variadic functions is not allowed - --> $DIR/fn-header-variadic.rs:13:22 + --> $DIR/fn-header-variadic.rs:14:22 | LL | reuse fn_header_aux::variadic_fn_extern; | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/drop/drop-trait-enum.rs b/tests/ui/drop/drop-trait-enum.rs index 5a88d959ec6f..efb6b2a912ab 100644 --- a/tests/ui/drop/drop-trait-enum.rs +++ b/tests/ui/drop/drop-trait-enum.rs @@ -4,6 +4,7 @@ #![allow(unused_variables)] //@ needs-threads //@ needs-unwind +//@ ignore-backends: gcc use std::thread; use std::sync::mpsc::{channel, Sender}; diff --git a/tests/ui/drop/terminate-in-initializer.rs b/tests/ui/drop/terminate-in-initializer.rs index 24ec39fe0963..5dd8fe43c71e 100644 --- a/tests/ui/drop/terminate-in-initializer.rs +++ b/tests/ui/drop/terminate-in-initializer.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc // Issue #787 // Don't try to clean up uninitialized locals diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller.rs b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs index b85b335844b0..1246a3801fc3 100644 --- a/tests/ui/explicit-tail-calls/callee_is_track_caller.rs +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs @@ -1,5 +1,6 @@ //@ run-pass //@ ignore-pass +//@ ignore-backends: gcc #![expect(incomplete_features)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr b/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr index e1a251d156f7..020a0542a57f 100644 --- a/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr @@ -1,5 +1,5 @@ warning: tail calling a function marked with `#[track_caller]` has no special effect - --> $DIR/callee_is_track_caller.rs:7:12 + --> $DIR/callee_is_track_caller.rs:8:12 | LL | become b(x); | ^^^^ diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs index 33384de83eb7..51688897b400 100644 --- a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs @@ -1,5 +1,6 @@ //@ run-pass //@ ignore-pass +//@ ignore-backends: gcc #![expect(incomplete_features)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr index 5a1c40509ad3..7b4c144acffa 100644 --- a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr @@ -1,5 +1,5 @@ warning: tail calling a function marked with `#[track_caller]` has no special effect - --> $DIR/callee_is_track_caller_polymorphic.rs:7:12 + --> $DIR/callee_is_track_caller_polymorphic.rs:8:12 | LL | become T::f(); | ^^^^^^ diff --git a/tests/ui/explicit-tail-calls/drop-order.rs b/tests/ui/explicit-tail-calls/drop-order.rs index 58e1afbdf0c5..ff6e2f09f57c 100644 --- a/tests/ui/explicit-tail-calls/drop-order.rs +++ b/tests/ui/explicit-tail-calls/drop-order.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![expect(incomplete_features)] #![feature(explicit_tail_calls)] use std::cell::RefCell; diff --git a/tests/ui/explicit-tail-calls/indexer.rs b/tests/ui/explicit-tail-calls/indexer.rs index 5644506b2f58..c26d9774ce78 100644 --- a/tests/ui/explicit-tail-calls/indexer.rs +++ b/tests/ui/explicit-tail-calls/indexer.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc // Indexing taken from // https://github.com/phi-go/rfcs/blob/guaranteed-tco/text%2F0000-explicit-tail-calls.md#tail-call-elimination // no other test has utilized the "function table" diff --git a/tests/ui/explicit-tail-calls/recursion-etc.rs b/tests/ui/explicit-tail-calls/recursion-etc.rs index 8c89ceb7869a..c22401d23799 100644 --- a/tests/ui/explicit-tail-calls/recursion-etc.rs +++ b/tests/ui/explicit-tail-calls/recursion-etc.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ ignore-backends: gcc #![expect(incomplete_features)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs index 035f063cd502..7a5f36da2091 100644 --- a/tests/ui/extern/extern-types-field-offset.rs +++ b/tests/ui/extern/extern-types-field-offset.rs @@ -2,6 +2,7 @@ //@ check-run-results //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL" +//@ ignore-backends: gcc #![feature(extern_types)] extern "C" { diff --git a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs index 1cd52b70315c..4d0afa1cdfa6 100644 --- a/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs +++ b/tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs @@ -21,6 +21,7 @@ //@[no]compile-flags: -C lto=no //@[thin]compile-flags: -C lto=thin //@[fat]compile-flags: -C lto=fat +//@ ignore-backends: gcc #![feature(panic_internals)] diff --git a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs index a44eb3828d0a..1fc3409c1f90 100644 --- a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs +++ b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs @@ -48,6 +48,7 @@ //@[fat1]compile-flags: -C opt-level=1 -C lto=fat //@[fat2]compile-flags: -C opt-level=2 -C lto=fat //@[fat3]compile-flags: -C opt-level=3 -C lto=fat +//@ ignore-backends: gcc fn main() { use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs index 26d483e43ae5..794b51c7a8a2 100644 --- a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs +++ b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.rs @@ -1,4 +1,5 @@ //@ proc-macro: format-string-proc-macro.rs +//@ ignore-backends: gcc extern crate format_string_proc_macro; diff --git a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr index e7ed2a76e6af..c341c6ee4c51 100644 --- a/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr +++ b/tests/ui/fmt/format-args-capture-from-pm-first-arg-macro.stderr @@ -1,5 +1,5 @@ error: there is no argument named `x` - --> $DIR/format-args-capture-from-pm-first-arg-macro.rs:6:5 + --> $DIR/format-args-capture-from-pm-first-arg-macro.rs:7:5 | LL | format_string_proc_macro::bad_format_args_captures!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/proc-macro-observer.rs index 6c4c8c572897..5237a0e982a6 100644 --- a/tests/ui/frontmatter/proc-macro-observer.rs +++ b/tests/ui/frontmatter/proc-macro-observer.rs @@ -1,6 +1,7 @@ //@ check-pass //@ proc-macro: makro.rs //@ edition: 2021 +//@ ignore-backends: gcc // Check that a proc-macro doesn't try to parse frontmatter and instead treats // it as a regular Rust token sequence. See `auxiliary/makro.rs` for details. diff --git a/tests/ui/hygiene/issue-77523-def-site-async-await.rs b/tests/ui/hygiene/issue-77523-def-site-async-await.rs index ad6bd5e0b78b..0a279682b71b 100644 --- a/tests/ui/hygiene/issue-77523-def-site-async-await.rs +++ b/tests/ui/hygiene/issue-77523-def-site-async-await.rs @@ -1,5 +1,6 @@ //@ build-pass //@ aux-build:def-site-async-await.rs +//@ ignore-backends: gcc // Regression test for issue #77523 // Tests that we don't ICE when an unusual combination diff --git a/tests/ui/impl-trait/precise-capturing/external-macro.rs b/tests/ui/impl-trait/precise-capturing/external-macro.rs index 9d4d8a1bb119..1342ecd58dcf 100644 --- a/tests/ui/impl-trait/precise-capturing/external-macro.rs +++ b/tests/ui/impl-trait/precise-capturing/external-macro.rs @@ -6,6 +6,7 @@ //@ aux-crate: no_use_macro=no-use-macro.rs //@ edition: 2024 //@ check-pass +//@ ignore-backends: gcc no_use_pm::pm_rpit!{} diff --git a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs index 832821c9c883..2ed0014f8b0e 100644 --- a/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs +++ b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs @@ -1,5 +1,6 @@ //@ build-fail //@ compile-flags: -Cpasses=unknown-pass +//@ ignore-backends: gcc fn main() {} diff --git a/tests/ui/issues/issue-25089.rs b/tests/ui/issues/issue-25089.rs index 929738c3e794..63fdf64cea94 100644 --- a/tests/ui/issues/issue-25089.rs +++ b/tests/ui/issues/issue-25089.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc use std::thread; diff --git a/tests/ui/issues/issue-26655.rs b/tests/ui/issues/issue-26655.rs index 416472b0b269..32c4b33a8c96 100644 --- a/tests/ui/issues/issue-26655.rs +++ b/tests/ui/issues/issue-26655.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc // Check that the destructors of simple enums are run on unwinding diff --git a/tests/ui/issues/issue-29485.rs b/tests/ui/issues/issue-29485.rs index a44bcd49c6a9..8e6436cb11e3 100644 --- a/tests/ui/issues/issue-29485.rs +++ b/tests/ui/issues/issue-29485.rs @@ -3,6 +3,7 @@ //@ aux-build:issue-29485.rs //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc #[feature(recover)] diff --git a/tests/ui/issues/issue-30018-panic.rs b/tests/ui/issues/issue-30018-panic.rs index 591848b6f7b4..09b832bb59d0 100644 --- a/tests/ui/issues/issue-30018-panic.rs +++ b/tests/ui/issues/issue-30018-panic.rs @@ -6,6 +6,7 @@ //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc struct Foo; diff --git a/tests/ui/issues/issue-44056.rs b/tests/ui/issues/issue-44056.rs index 12e4f018466f..37d7b00cf7f0 100644 --- a/tests/ui/issues/issue-44056.rs +++ b/tests/ui/issues/issue-44056.rs @@ -2,5 +2,6 @@ //@ only-x86_64 //@ no-prefer-dynamic //@ compile-flags: -Ctarget-feature=+avx -Clto +//@ ignore-backends: gcc fn main() {} diff --git a/tests/ui/issues/issue-68696-catch-during-unwind.rs b/tests/ui/issues/issue-68696-catch-during-unwind.rs index 80d63b0cde70..655879e18692 100644 --- a/tests/ui/issues/issue-68696-catch-during-unwind.rs +++ b/tests/ui/issues/issue-68696-catch-during-unwind.rs @@ -4,6 +4,7 @@ // entering the catch_unwind. // //@ run-pass +//@ ignore-backends: gcc use std::panic::catch_unwind; diff --git a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs index e5de08a7a28b..512616251c2f 100644 --- a/tests/ui/linkage-attr/common-linkage-non-zero-init.rs +++ b/tests/ui/linkage-attr/common-linkage-non-zero-init.rs @@ -3,6 +3,7 @@ //@ known-bug: #109681 //@ ignore-wasm32 this appears to SIGABRT on wasm, not fail cleanly //@ compile-flags: -Z verify-llvm-ir +//@ ignore-backends: gcc // This test verifies that we continue to hit the LLVM error for common linkage with non-zero // initializers, since it generates invalid LLVM IR. diff --git a/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs index 57492ed2d0e1..62d352facd17 100644 --- a/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs +++ b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs @@ -3,6 +3,7 @@ //@ run-pass //@ compile-flags: -Cpanic=abort //@ edition: 2024 +//@ ignore-backends: gcc #![allow(incomplete_features)] #![feature(raw_dylib_elf)] diff --git a/tests/ui/linking/no-gc-encapsulation-symbols.rs b/tests/ui/linking/no-gc-encapsulation-symbols.rs index 36d69969199c..c60f35b55eb2 100644 --- a/tests/ui/linking/no-gc-encapsulation-symbols.rs +++ b/tests/ui/linking/no-gc-encapsulation-symbols.rs @@ -5,6 +5,7 @@ // //@ build-pass //@ only-x86_64-unknown-linux-gnu +//@ ignore-backends: gcc unsafe extern "Rust" { // The __start_ section name is magical for the linker, diff --git a/tests/ui/lint/unused-qualification-in-derive-expansion.rs b/tests/ui/lint/unused-qualification-in-derive-expansion.rs index b2067e22c444..bf095c6449d8 100644 --- a/tests/ui/lint/unused-qualification-in-derive-expansion.rs +++ b/tests/ui/lint/unused-qualification-in-derive-expansion.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: add-impl.rs +//@ ignore-backends: gcc #![forbid(unused_qualifications)] diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs index d6855f8760d5..7c82d978a075 100644 --- a/tests/ui/lto/debuginfo-lto-alloc.rs +++ b/tests/ui/lto/debuginfo-lto-alloc.rs @@ -12,6 +12,7 @@ //@ compile-flags: --test -C debuginfo=2 -C lto=fat //@ no-prefer-dynamic //@ incremental +//@ ignore-backends: gcc extern crate alloc; diff --git a/tests/ui/lto/debuginfo-lto.rs b/tests/ui/lto/debuginfo-lto.rs index f189a1df0567..6d8b836235cc 100644 --- a/tests/ui/lto/debuginfo-lto.rs +++ b/tests/ui/lto/debuginfo-lto.rs @@ -7,6 +7,7 @@ //@ aux-build:debuginfo-lto-aux.rs //@ compile-flags: -C lto -g //@ no-prefer-dynamic +//@ ignore-backends: gcc extern crate debuginfo_lto_aux; diff --git a/tests/ui/lto/dwarf-mixed-versions-lto.rs b/tests/ui/lto/dwarf-mixed-versions-lto.rs index 900274eb22f4..8ed3afa5e33a 100644 --- a/tests/ui/lto/dwarf-mixed-versions-lto.rs +++ b/tests/ui/lto/dwarf-mixed-versions-lto.rs @@ -7,6 +7,7 @@ //@ compile-flags: -C lto -g -Cdwarf-version=5 //@ no-prefer-dynamic //@ build-pass +//@ ignore-backends: gcc extern crate dwarf_mixed_versions_lto_aux; diff --git a/tests/ui/lto/fat-lto.rs b/tests/ui/lto/fat-lto.rs index 73d6801a25ac..fe00d7feb377 100644 --- a/tests/ui/lto/fat-lto.rs +++ b/tests/ui/lto/fat-lto.rs @@ -1,6 +1,7 @@ //@ run-pass //@ compile-flags: -Clto=fat //@ no-prefer-dynamic +//@ ignore-backends: gcc fn main() { println!("hello!"); diff --git a/tests/ui/lto/issue-100772.rs b/tests/ui/lto/issue-100772.rs index 9468e20894ac..e07d44e3be88 100644 --- a/tests/ui/lto/issue-100772.rs +++ b/tests/ui/lto/issue-100772.rs @@ -3,6 +3,7 @@ //@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu +//@ ignore-backends: gcc #![feature(allocator_api)] diff --git a/tests/ui/lto/lto-duplicate-symbols.rs b/tests/ui/lto/lto-duplicate-symbols.rs index a62ab2e22172..08465eb0fb27 100644 --- a/tests/ui/lto/lto-duplicate-symbols.rs +++ b/tests/ui/lto/lto-duplicate-symbols.rs @@ -4,6 +4,7 @@ //@ compile-flags: -C lto //@ no-prefer-dynamic //@ normalize-stderr: "lto-duplicate-symbols2\.lto_duplicate_symbols2\.[0-9a-zA-Z]+-cgu" -> "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu" +//@ ignore-backends: gcc extern crate lto_duplicate_symbols1; extern crate lto_duplicate_symbols2; diff --git a/tests/ui/lto/lto-many-codegen-units.rs b/tests/ui/lto/lto-many-codegen-units.rs index fb6636fb8151..6761510e4274 100644 --- a/tests/ui/lto/lto-many-codegen-units.rs +++ b/tests/ui/lto/lto-many-codegen-units.rs @@ -1,6 +1,7 @@ //@ run-pass //@ compile-flags: -C lto -C codegen-units=8 //@ no-prefer-dynamic +//@ ignore-backends: gcc fn main() { } diff --git a/tests/ui/lto/lto-rustc-loads-linker-plugin.rs b/tests/ui/lto/lto-rustc-loads-linker-plugin.rs index 18e937cb29a6..2be320f0bffc 100644 --- a/tests/ui/lto/lto-rustc-loads-linker-plugin.rs +++ b/tests/ui/lto/lto-rustc-loads-linker-plugin.rs @@ -2,6 +2,7 @@ //@ aux-build:lto-rustc-loads-linker-plugin.rs //@ run-pass //@ no-prefer-dynamic +//@ ignore-backends: gcc // This test ensures that if a dependency was compiled with // `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against diff --git a/tests/ui/lto/lto-still-runs-thread-dtors.rs b/tests/ui/lto/lto-still-runs-thread-dtors.rs index 900368496ebd..9a97677773cc 100644 --- a/tests/ui/lto/lto-still-runs-thread-dtors.rs +++ b/tests/ui/lto/lto-still-runs-thread-dtors.rs @@ -2,6 +2,7 @@ //@ compile-flags: -C lto //@ no-prefer-dynamic //@ needs-threads +//@ ignore-backends: gcc // FIXME(static_mut_refs): this could use an atomic #![allow(static_mut_refs)] diff --git a/tests/ui/macros/same-sequence-span.rs b/tests/ui/macros/same-sequence-span.rs index dfaf669a769a..9fae847a4e2f 100644 --- a/tests/ui/macros/same-sequence-span.rs +++ b/tests/ui/macros/same-sequence-span.rs @@ -1,4 +1,5 @@ //@ proc-macro: proc_macro_sequence.rs +//@ ignore-backends: gcc // Regression test for issue #62831: Check that multiple sequences with the same span in the // left-hand side of a macro definition behave as if they had unique spans, and in particular that diff --git a/tests/ui/macros/same-sequence-span.stderr b/tests/ui/macros/same-sequence-span.stderr index 34df201f5a5c..1ca89b6b595c 100644 --- a/tests/ui/macros/same-sequence-span.stderr +++ b/tests/ui/macros/same-sequence-span.stderr @@ -1,5 +1,5 @@ error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments - --> $DIR/same-sequence-span.rs:14:18 + --> $DIR/same-sequence-span.rs:15:18 | LL | (1 $x:expr $($y:tt,)* | ^^^^^ not allowed after `expr` fragments @@ -7,7 +7,7 @@ LL | (1 $x:expr $($y:tt,)* = note: allowed there are: `=>`, `,` or `;` error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments - --> $DIR/same-sequence-span.rs:15:18 + --> $DIR/same-sequence-span.rs:16:18 | LL | $(= $z:tt)* | ^ not allowed after `expr` fragments @@ -15,10 +15,10 @@ LL | $(= $z:tt)* = note: allowed there are: `=>`, `,` or `;` error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments - --> $DIR/same-sequence-span.rs:19:1 + --> $DIR/same-sequence-span.rs:20:1 | -LL | | macro_rules! manual_foo { - | |__________________________^not allowed after `expr` fragments +LL | | // `proc_macro_sequence.rs`. + | |_____________________________^not allowed after `expr` fragments ... LL | proc_macro_sequence::make_foo!(); | ^------------------------------- @@ -30,7 +30,7 @@ LL | proc_macro_sequence::make_foo!(); = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info) error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments - --> $DIR/same-sequence-span.rs:19:1 + --> $DIR/same-sequence-span.rs:20:1 | LL | proc_macro_sequence::make_foo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments diff --git a/tests/ui/numbers-arithmetic/int-abs-overflow.rs b/tests/ui/numbers-arithmetic/int-abs-overflow.rs index 6397f62d0655..fd4a5a6052b8 100644 --- a/tests/ui/numbers-arithmetic/int-abs-overflow.rs +++ b/tests/ui/numbers-arithmetic/int-abs-overflow.rs @@ -2,6 +2,7 @@ //@ compile-flags: -C overflow-checks=on //@ needs-threads //@ needs-unwind +//@ ignore-backends: gcc use std::thread; diff --git a/tests/ui/numbers-arithmetic/issue-8460.rs b/tests/ui/numbers-arithmetic/issue-8460.rs index 87867fdc93e4..52df432669f1 100644 --- a/tests/ui/numbers-arithmetic/issue-8460.rs +++ b/tests/ui/numbers-arithmetic/issue-8460.rs @@ -2,6 +2,7 @@ #![allow(unused_must_use)] //@ needs-threads //@ needs-unwind +//@ ignore-backends: gcc #![feature(rustc_attrs)] use std::thread; diff --git a/tests/ui/panic-runtime/lto-unwind.rs b/tests/ui/panic-runtime/lto-unwind.rs index 93275052f852..bafc6d5aaa5c 100644 --- a/tests/ui/panic-runtime/lto-unwind.rs +++ b/tests/ui/panic-runtime/lto-unwind.rs @@ -3,6 +3,7 @@ //@ needs-unwind //@ no-prefer-dynamic //@ needs-subprocess +//@ ignore-backends: gcc use std::process::Command; use std::env; diff --git a/tests/ui/panics/oom-panic-unwind.rs b/tests/ui/panics/oom-panic-unwind.rs index 5974ad91406f..4f7939ce60b2 100644 --- a/tests/ui/panics/oom-panic-unwind.rs +++ b/tests/ui/panics/oom-panic-unwind.rs @@ -5,6 +5,7 @@ //@ no-prefer-dynamic //@ needs-unwind //@ only-linux +//@ ignore-backends: gcc use std::hint::black_box; use std::mem::forget; diff --git a/tests/ui/panics/panic-handler-chain-update-hook.rs b/tests/ui/panics/panic-handler-chain-update-hook.rs index 662ea9e978f7..2ae79ad236ef 100644 --- a/tests/ui/panics/panic-handler-chain-update-hook.rs +++ b/tests/ui/panics/panic-handler-chain-update-hook.rs @@ -3,6 +3,7 @@ #![allow(stable_features)] //@ needs-threads +//@ ignore-backends: gcc #![feature(std_panic)] #![feature(panic_update_hook)] diff --git a/tests/ui/panics/panic-handler-chain.rs b/tests/ui/panics/panic-handler-chain.rs index fea71ad9ec4e..cc591c1d9992 100644 --- a/tests/ui/panics/panic-handler-chain.rs +++ b/tests/ui/panics/panic-handler-chain.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc #![allow(stable_features)] #![feature(std_panic)] diff --git a/tests/ui/panics/panic-handler-flail-wildly.rs b/tests/ui/panics/panic-handler-flail-wildly.rs index d42dfd68d9cf..d5f5195d3812 100644 --- a/tests/ui/panics/panic-handler-flail-wildly.rs +++ b/tests/ui/panics/panic-handler-flail-wildly.rs @@ -5,6 +5,7 @@ #![allow(unused_must_use)] //@ needs-threads +//@ ignore-backends: gcc #![feature(std_panic)] diff --git a/tests/ui/panics/panic-handler-set-twice.rs b/tests/ui/panics/panic-handler-set-twice.rs index 5f670d5f4929..ca4ed65f5683 100644 --- a/tests/ui/panics/panic-handler-set-twice.rs +++ b/tests/ui/panics/panic-handler-set-twice.rs @@ -6,6 +6,7 @@ #![feature(std_panic)] //@ needs-threads +//@ ignore-backends: gcc use std::sync::atomic::{AtomicUsize, Ordering}; use std::panic; diff --git a/tests/ui/panics/panic-in-dtor-drops-fields.rs b/tests/ui/panics/panic-in-dtor-drops-fields.rs index 38eb6d0acfb8..db0792343375 100644 --- a/tests/ui/panics/panic-in-dtor-drops-fields.rs +++ b/tests/ui/panics/panic-in-dtor-drops-fields.rs @@ -4,6 +4,7 @@ #![allow(non_upper_case_globals)] //@ needs-threads +//@ ignore-backends: gcc use std::thread; diff --git a/tests/ui/panics/panic-recover-propagate.rs b/tests/ui/panics/panic-recover-propagate.rs index ef6ae4fd7887..36ca279bdbd2 100644 --- a/tests/ui/panics/panic-recover-propagate.rs +++ b/tests/ui/panics/panic-recover-propagate.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc use std::sync::atomic::{AtomicUsize, Ordering}; use std::panic; diff --git a/tests/ui/panics/rvalue-cleanup-during-box-panic.rs b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs index 84c5d85d7e09..03571f111aac 100644 --- a/tests/ui/panics/rvalue-cleanup-during-box-panic.rs +++ b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs @@ -21,6 +21,7 @@ // scenario worth testing. //@ needs-threads +//@ ignore-backends: gcc use std::thread; diff --git a/tests/ui/panics/unwind-force-no-unwind-tables.rs b/tests/ui/panics/unwind-force-no-unwind-tables.rs index 2226e4dd03eb..715f288fff10 100644 --- a/tests/ui/panics/unwind-force-no-unwind-tables.rs +++ b/tests/ui/panics/unwind-force-no-unwind-tables.rs @@ -6,6 +6,7 @@ //@ needs-unwind //@ ignore-windows target requires uwtable //@ compile-flags: -C panic=unwind -C force-unwind-tables=n +//@ ignore-backends: gcc use std::panic::{self, AssertUnwindSafe}; diff --git a/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs b/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs index 461890e63e37..c82efe79e4d0 100644 --- a/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs +++ b/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-89971-outer-attr-following-inner-attr-ice.rs +//@ ignore-backends: gcc #[macro_use] extern crate issue_89971_outer_attr_following_inner_attr_ice; diff --git a/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.stderr b/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.stderr index 51df17c7cc67..392e7d0321f0 100644 --- a/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.stderr +++ b/tests/ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.stderr @@ -1,5 +1,5 @@ error: an inner attribute is not permitted in this context - --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:11:1 + --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:12:1 | LL | #![deny(missing_docs)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/macro/unicode-control-codepoints-macros.rs b/tests/ui/parser/macro/unicode-control-codepoints-macros.rs index 775c50779760..701e7dfa30a3 100644 --- a/tests/ui/parser/macro/unicode-control-codepoints-macros.rs +++ b/tests/ui/parser/macro/unicode-control-codepoints-macros.rs @@ -1,6 +1,7 @@ // Regression test for #140281 //@ edition: 2021 //@ proc-macro: unicode-control.rs +//@ ignore-backends: gcc extern crate unicode_control; use unicode_control::*; diff --git a/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr b/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr index ca813399eac2..22fb1b945c65 100644 --- a/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr +++ b/tests/ui/parser/macro/unicode-control-codepoints-macros.stderr @@ -1,5 +1,5 @@ error: unicode codepoint changing visible direction of text present in doc comment - --> $DIR/unicode-control-codepoints-macros.rs:20:9 + --> $DIR/unicode-control-codepoints-macros.rs:21:9 | LL | /// �test� RTL in doc in vec | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment contains invisible unicode text flow control codepoints @@ -10,7 +10,7 @@ LL | /// �test� RTL in doc in vec = note: `#[deny(text_direction_codepoint_in_literal)]` on by default error: unicode codepoint changing visible direction of text present in doc comment - --> $DIR/unicode-control-codepoints-macros.rs:25:9 + --> $DIR/unicode-control-codepoints-macros.rs:26:9 | LL | / /** LL | | * �test� RTL in doc in macro @@ -22,7 +22,7 @@ LL | | */ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment - --> $DIR/unicode-control-codepoints-macros.rs:32:9 + --> $DIR/unicode-control-codepoints-macros.rs:33:9 | LL | / /** LL | | * �test� RTL in doc in macro @@ -34,7 +34,7 @@ LL | | */ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment - --> $DIR/unicode-control-codepoints-macros.rs:40:9 + --> $DIR/unicode-control-codepoints-macros.rs:41:9 | LL | /// �test� RTL in doc in proc macro | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment contains invisible unicode text flow control codepoints @@ -44,7 +44,7 @@ LL | /// �test� RTL in doc in proc macro = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}', '\u{2066}' error: unicode codepoint changing visible direction of text present in doc comment - --> $DIR/unicode-control-codepoints-macros.rs:45:9 + --> $DIR/unicode-control-codepoints-macros.rs:46:9 | LL | /// �test� RTL in doc in proc macro | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment contains invisible unicode text flow control codepoints diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs index 557c67738d30..2463897381ec 100644 --- a/tests/ui/parser/tuple-index-suffix-proc-macro.rs +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -3,6 +3,7 @@ //! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction. //@ proc-macro: tuple-index-suffix-proc-macro-aux.rs +//@ ignore-backends: gcc extern crate tuple_index_suffix_proc_macro_aux; use tuple_index_suffix_proc_macro_aux as aux; diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr index 47d179d35551..a242af5a789f 100644 --- a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -1,23 +1,23 @@ error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:17:28 + --> $DIR/tuple-index-suffix-proc-macro.rs:18:28 | LL | aux::bad_tup_indexing!(0usize); | ^^^^^^ invalid suffix `usize` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:19:47 + --> $DIR/tuple-index-suffix-proc-macro.rs:20:47 | LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); | ^^^^^^ invalid suffix `isize` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:24:28 + --> $DIR/tuple-index-suffix-proc-macro.rs:25:28 | LL | aux::bad_tup_indexing!(0u8); | ^^^ invalid suffix `u8` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:26:47 + --> $DIR/tuple-index-suffix-proc-macro.rs:27:47 | LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); | ^^^^ invalid suffix `u64` diff --git a/tests/ui/proc-macro/add-impl.rs b/tests/ui/proc-macro/add-impl.rs index 2299f05c2e7f..645e9321bba0 100644 --- a/tests/ui/proc-macro/add-impl.rs +++ b/tests/ui/proc-macro/add-impl.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: add-impl.rs +//@ ignore-backends: gcc #[macro_use] extern crate add_impl; diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs-test.rs b/tests/ui/proc-macro/ambiguous-builtin-attrs-test.rs index 8ee2223822a3..e580e0784b34 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs-test.rs +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs-test.rs @@ -1,5 +1,6 @@ //@ proc-macro: builtin-attrs.rs //@ compile-flags:--test +//@ ignore-backends: gcc #![feature(decl_macro, test)] diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs-test.stderr b/tests/ui/proc-macro/ambiguous-builtin-attrs-test.stderr index 346cebf639d1..e5de873cf31f 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs-test.stderr +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs-test.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `NonExistent` in this scope - --> $DIR/ambiguous-builtin-attrs-test.rs:19:5 + --> $DIR/ambiguous-builtin-attrs-test.rs:20:5 | LL | NonExistent; | ^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs index edc7748eff3d..63d3c79055ca 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -1,5 +1,6 @@ //@ edition:2018 //@ proc-macro: builtin-attrs.rs +//@ ignore-backends: gcc #![feature(decl_macro)] //~ ERROR `feature` is ambiguous extern crate builtin_attrs; diff --git a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr index 0f4ddc065a74..ff7894a41eab 100644 --- a/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/tests/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `NonExistent` in this scope - --> $DIR/ambiguous-builtin-attrs.rs:34:5 + --> $DIR/ambiguous-builtin-attrs.rs:35:5 | LL | NonExistent; | ^^^^^^^^^^^ not found in this scope error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:9:3 + --> $DIR/ambiguous-builtin-attrs.rs:10:3 | LL | #[repr(C)] | ^^^^ ambiguous name @@ -13,14 +13,14 @@ LL | #[repr(C)] = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute note: `repr` could also refer to the attribute macro imported here - --> $DIR/ambiguous-builtin-attrs.rs:6:5 + --> $DIR/ambiguous-builtin-attrs.rs:7:5 | LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:11:19 + --> $DIR/ambiguous-builtin-attrs.rs:12:19 | LL | #[cfg_attr(all(), repr(C))] | ^^^^ ambiguous name @@ -28,14 +28,14 @@ LL | #[cfg_attr(all(), repr(C))] = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute note: `repr` could also refer to the attribute macro imported here - --> $DIR/ambiguous-builtin-attrs.rs:6:5 + --> $DIR/ambiguous-builtin-attrs.rs:7:5 | LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:20:34 + --> $DIR/ambiguous-builtin-attrs.rs:21:34 | LL | fn non_macro_expanded_location<#[repr(C)] T>() { | ^^^^ ambiguous name @@ -43,14 +43,14 @@ LL | fn non_macro_expanded_location<#[repr(C)] T>() { = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute note: `repr` could also refer to the attribute macro imported here - --> $DIR/ambiguous-builtin-attrs.rs:6:5 + --> $DIR/ambiguous-builtin-attrs.rs:7:5 | LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `repr` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:24:11 + --> $DIR/ambiguous-builtin-attrs.rs:25:11 | LL | #[repr(C)] | ^^^^ ambiguous name @@ -58,14 +58,14 @@ LL | #[repr(C)] = note: ambiguous because of a name conflict with a builtin attribute = note: `repr` could refer to a built-in attribute note: `repr` could also refer to the attribute macro imported here - --> $DIR/ambiguous-builtin-attrs.rs:6:5 + --> $DIR/ambiguous-builtin-attrs.rs:7:5 | LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::repr` to refer to this attribute macro unambiguously error[E0659]: `allow` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:38:3 + --> $DIR/ambiguous-builtin-attrs.rs:39:3 | LL | #[allow(unused)] | ^^^^^ ambiguous name @@ -73,14 +73,14 @@ LL | #[allow(unused)] = note: ambiguous because of a name conflict with a builtin attribute = note: `allow` could refer to a built-in attribute note: `allow` could also refer to the built-in attribute imported here - --> $DIR/ambiguous-builtin-attrs.rs:37:5 + --> $DIR/ambiguous-builtin-attrs.rs:38:5 | LL | use deny as allow; | ^^^^^^^^^^^^^ = help: use `crate::allow` to refer to this built-in attribute unambiguously error[E0659]: `feature` is ambiguous - --> $DIR/ambiguous-builtin-attrs.rs:3:4 + --> $DIR/ambiguous-builtin-attrs.rs:4:4 | LL | #![feature(decl_macro)] | ^^^^^^^ ambiguous name @@ -88,20 +88,20 @@ LL | #![feature(decl_macro)] = note: ambiguous because of a name conflict with a builtin attribute = note: `feature` could refer to a built-in attribute note: `feature` could also refer to the attribute macro imported here - --> $DIR/ambiguous-builtin-attrs.rs:6:5 + --> $DIR/ambiguous-builtin-attrs.rs:7:5 | LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::feature` to refer to this attribute macro unambiguously error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/ambiguous-builtin-attrs.rs:20:39 + --> $DIR/ambiguous-builtin-attrs.rs:21:39 | LL | fn non_macro_expanded_location<#[repr(C)] T>() { | ^ - not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/ambiguous-builtin-attrs.rs:24:16 + --> $DIR/ambiguous-builtin-attrs.rs:25:16 | LL | #[repr(C)] | ^ diff --git a/tests/ui/proc-macro/append-impl.rs b/tests/ui/proc-macro/append-impl.rs index c0f208460b29..48d21968de0c 100644 --- a/tests/ui/proc-macro/append-impl.rs +++ b/tests/ui/proc-macro/append-impl.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: append-impl.rs +//@ ignore-backends: gcc #![allow(warnings)] diff --git a/tests/ui/proc-macro/attr-args.rs b/tests/ui/proc-macro/attr-args.rs index 1d3e0f725d25..4109b450a8ab 100644 --- a/tests/ui/proc-macro/attr-args.rs +++ b/tests/ui/proc-macro/attr-args.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: attr-args.rs +//@ ignore-backends: gcc #![allow(warnings)] diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs index f476858a32ba..bdfc0587b3b0 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.rs +++ b/tests/ui/proc-macro/attr-invalid-exprs.rs @@ -1,6 +1,7 @@ //! Attributes producing expressions in invalid locations //@ proc-macro: attr-stmt-expr.rs +//@ ignore-backends: gcc #![feature(proc_macro_hygiene)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr index 0d500c871453..43241e1e6fd5 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.stderr +++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr @@ -1,11 +1,11 @@ error: expected expression, found end of macro arguments - --> $DIR/attr-invalid-exprs.rs:12:13 + --> $DIR/attr-invalid-exprs.rs:13:13 | LL | let _ = #[no_output] "Hello, world!"; | ^^^^^^^^^^^^ error: macro expansion ignores `,` and any tokens following - --> $DIR/attr-invalid-exprs.rs:15:13 + --> $DIR/attr-invalid-exprs.rs:16:13 | LL | let _ = #[duplicate] "Hello, world!"; | ^^^^^^^^^^^^ caused by the macro expansion here @@ -17,7 +17,7 @@ LL | let _ = #[duplicate]; "Hello, world!"; | + error: macro expansion ignores `,` and any tokens following - --> $DIR/attr-invalid-exprs.rs:24:9 + --> $DIR/attr-invalid-exprs.rs:25:9 | LL | #[duplicate] | ^^^^^^^^^^^^ caused by the macro expansion here diff --git a/tests/ui/proc-macro/attr-on-trait.rs b/tests/ui/proc-macro/attr-on-trait.rs index e95760a837c0..345653864f84 100644 --- a/tests/ui/proc-macro/attr-on-trait.rs +++ b/tests/ui/proc-macro/attr-on-trait.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: attr-on-trait.rs +//@ ignore-backends: gcc extern crate attr_on_trait; diff --git a/tests/ui/proc-macro/bang-macro.rs b/tests/ui/proc-macro/bang-macro.rs index 2287e34c5dda..75f40de242ec 100644 --- a/tests/ui/proc-macro/bang-macro.rs +++ b/tests/ui/proc-macro/bang-macro.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: bang-macro.rs +//@ ignore-backends: gcc extern crate bang_macro; use bang_macro::rewrite; diff --git a/tests/ui/proc-macro/call-site.rs b/tests/ui/proc-macro/call-site.rs index 9c285e1ed117..5de4061b2a94 100644 --- a/tests/ui/proc-macro/call-site.rs +++ b/tests/ui/proc-macro/call-site.rs @@ -1,5 +1,6 @@ //@ check-pass //@ proc-macro: call-site.rs +//@ ignore-backends: gcc extern crate call_site; diff --git a/tests/ui/proc-macro/count_compound_ops.rs b/tests/ui/proc-macro/count_compound_ops.rs index 20b0b87817e2..fe90e7bfbe49 100644 --- a/tests/ui/proc-macro/count_compound_ops.rs +++ b/tests/ui/proc-macro/count_compound_ops.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: count_compound_ops.rs +//@ ignore-backends: gcc extern crate count_compound_ops; use count_compound_ops::count_compound_ops; diff --git a/tests/ui/proc-macro/derive-bad.rs b/tests/ui/proc-macro/derive-bad.rs index 9b237c731dbe..9b9a2bc33c94 100644 --- a/tests/ui/proc-macro/derive-bad.rs +++ b/tests/ui/proc-macro/derive-bad.rs @@ -1,4 +1,5 @@ //@ proc-macro: derive-bad.rs +//@ ignore-backends: gcc #[macro_use] extern crate derive_bad; diff --git a/tests/ui/proc-macro/derive-bad.stderr b/tests/ui/proc-macro/derive-bad.stderr index 43e97f40ba88..8a252e826eff 100644 --- a/tests/ui/proc-macro/derive-bad.stderr +++ b/tests/ui/proc-macro/derive-bad.stderr @@ -1,5 +1,5 @@ error: expected `:`, found `}` - --> $DIR/derive-bad.rs:6:10 + --> $DIR/derive-bad.rs:7:10 | LL | #[derive(A)] | ^ @@ -10,13 +10,13 @@ LL | #[derive(A)] = note: this error originates in the derive macro `A` (in Nightly builds, run with -Z macro-backtrace for more info) error: proc-macro derive produced unparsable tokens - --> $DIR/derive-bad.rs:6:10 + --> $DIR/derive-bad.rs:7:10 | LL | #[derive(A)] | ^ error[E0428]: the name `A` is defined multiple times - --> $DIR/derive-bad.rs:9:1 + --> $DIR/derive-bad.rs:10:1 | LL | #[derive(A)] | - previous definition of the type `A` here diff --git a/tests/ui/proc-macro/derive-helper-shadowing.rs b/tests/ui/proc-macro/derive-helper-shadowing.rs index ee883be33526..5ddd914d1026 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.rs +++ b/tests/ui/proc-macro/derive-helper-shadowing.rs @@ -1,6 +1,7 @@ //@ edition:2018 //@ proc-macro: test-macros.rs //@ proc-macro: derive-helper-shadowing.rs +//@ ignore-backends: gcc #[macro_use] extern crate test_macros; diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index 2e4ddd19b7e1..90b42e8d6e22 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -1,17 +1,17 @@ error: cannot use a derive helper attribute through an import - --> $DIR/derive-helper-shadowing.rs:42:15 + --> $DIR/derive-helper-shadowing.rs:43:15 | LL | #[renamed] | ^^^^^^^ | note: the derive helper attribute imported here - --> $DIR/derive-helper-shadowing.rs:41:17 + --> $DIR/derive-helper-shadowing.rs:42:17 | LL | use empty_helper as renamed; | ^^^^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `empty_helper` in this scope - --> $DIR/derive-helper-shadowing.rs:38:22 + --> $DIR/derive-helper-shadowing.rs:39:22 | LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + use empty_helper; | error: cannot find attribute `empty_helper` in this scope - --> $DIR/derive-helper-shadowing.rs:14:11 + --> $DIR/derive-helper-shadowing.rs:15:11 | LL | #[empty_helper] | ^^^^^^^^^^^^ @@ -40,26 +40,26 @@ LL + use crate::empty_helper; | error[E0659]: `empty_helper` is ambiguous - --> $DIR/derive-helper-shadowing.rs:19:3 + --> $DIR/derive-helper-shadowing.rs:20:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ ambiguous name | = note: ambiguous because of a name conflict with a derive helper attribute note: `empty_helper` could refer to the derive helper attribute defined here - --> $DIR/derive-helper-shadowing.rs:22:10 + --> $DIR/derive-helper-shadowing.rs:23:10 | LL | #[derive(Empty)] | ^^^^^ note: `empty_helper` could also refer to the attribute macro imported here - --> $DIR/derive-helper-shadowing.rs:10:5 + --> $DIR/derive-helper-shadowing.rs:11:5 | LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously error: derive helper attribute is used before it is introduced - --> $DIR/derive-helper-shadowing.rs:19:3 + --> $DIR/derive-helper-shadowing.rs:20:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ @@ -76,7 +76,7 @@ error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0659`. Future incompatibility report: Future breakage diagnostic: error: derive helper attribute is used before it is introduced - --> $DIR/derive-helper-shadowing.rs:19:3 + --> $DIR/derive-helper-shadowing.rs:20:3 | LL | #[empty_helper] | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/derive-same-struct.rs b/tests/ui/proc-macro/derive-same-struct.rs index f7669ba1480b..04ab08dc76e5 100644 --- a/tests/ui/proc-macro/derive-same-struct.rs +++ b/tests/ui/proc-macro/derive-same-struct.rs @@ -3,6 +3,7 @@ #![allow(path_statements)] #![allow(dead_code)] //@ proc-macro: derive-same-struct.rs +//@ ignore-backends: gcc #[macro_use] extern crate derive_same_struct; diff --git a/tests/ui/proc-macro/edition-imports-2018.rs b/tests/ui/proc-macro/edition-imports-2018.rs index a3808d9dce82..af9eed74adb9 100644 --- a/tests/ui/proc-macro/edition-imports-2018.rs +++ b/tests/ui/proc-macro/edition-imports-2018.rs @@ -1,6 +1,7 @@ //@ check-pass //@ edition:2018 //@ proc-macro: edition-imports-2015.rs +//@ ignore-backends: gcc #[macro_use] extern crate edition_imports_2015; diff --git a/tests/ui/proc-macro/env.rs b/tests/ui/proc-macro/env.rs index 94e3b09e5269..fc248f883596 100644 --- a/tests/ui/proc-macro/env.rs +++ b/tests/ui/proc-macro/env.rs @@ -2,6 +2,7 @@ //@ run-pass //@ rustc-env: THE_CONST=1 //@ compile-flags: -Zunstable-options --env-set THE_CONST=12 --env-set ANOTHER=4 +//@ ignore-backends: gcc #![crate_name = "foo"] diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 8a4ed9768d53..1e058abe3bc1 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -1,4 +1,5 @@ //@ proc-macro: expand-expr.rs +//@ ignore-backends: gcc // no-remap-src-base: check_expand_expr_file!() fails when enabled. #![feature(concat_bytes)] @@ -10,7 +11,7 @@ use expand_expr::{ // Check builtin macros can be expanded. -expand_expr_is!(13u32, line!()); +expand_expr_is!(14u32, line!()); expand_expr_is!(24u32, column!()); expand_expr_is!("Hello, World!", concat!("Hello, ", "World", "!")); diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr index 8b1df177cfa6..fd5f672adf5c 100644 --- a/tests/ui/proc-macro/expand-expr.stderr +++ b/tests/ui/proc-macro/expand-expr.stderr @@ -1,29 +1,29 @@ error: expected one of `.`, `?`, or an operator, found `;` - --> $DIR/expand-expr.rs:108:27 + --> $DIR/expand-expr.rs:109:27 | LL | expand_expr_fail!("string"; hello); | ^ expected one of `.`, `?`, or an operator error: expected expression, found `$` - --> $DIR/expand-expr.rs:111:19 + --> $DIR/expand-expr.rs:112:19 | LL | expand_expr_fail!($); | ^ expected expression error: expected expression, found `$` - --> $DIR/expand-expr.rs:112:29 + --> $DIR/expand-expr.rs:113:29 | LL | expand_expr_fail!(echo_tts!($)); | ^ expected expression error: expected expression, found `$` - --> $DIR/expand-expr.rs:113:28 + --> $DIR/expand-expr.rs:114:28 | LL | expand_expr_fail!(echo_pm!($)); | ^ expected expression error: macro expansion ignores `hello` and any tokens following - --> $DIR/expand-expr.rs:117:47 + --> $DIR/expand-expr.rs:118:47 | LL | expand_expr_is!("string", echo_tts!("string"; hello)); | --------------------^^^^^- caused by the macro expansion here @@ -35,7 +35,7 @@ LL | expand_expr_is!("string", echo_tts!("string"; hello);); | + error: macro expansion ignores `;` and any tokens following - --> $DIR/expand-expr.rs:118:44 + --> $DIR/expand-expr.rs:119:44 | LL | expand_expr_is!("string", echo_pm!("string"; hello)); | -----------------^------- caused by the macro expansion here @@ -47,7 +47,7 @@ LL | expand_expr_is!("string", echo_pm!("string"; hello);); | + error: recursion limit reached while expanding `recursive_expand!` - --> $DIR/expand-expr.rs:126:16 + --> $DIR/expand-expr.rs:127:16 | LL | const _: u32 = recursive_expand!(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/expand-to-unstable.rs b/tests/ui/proc-macro/expand-to-unstable.rs index 8968471ebd87..37bfeab1fe71 100644 --- a/tests/ui/proc-macro/expand-to-unstable.rs +++ b/tests/ui/proc-macro/expand-to-unstable.rs @@ -1,4 +1,5 @@ //@ proc-macro: derive-unstable.rs +//@ ignore-backends: gcc #![allow(warnings)] diff --git a/tests/ui/proc-macro/expand-to-unstable.stderr b/tests/ui/proc-macro/expand-to-unstable.stderr index 563c7ae8f956..255f80501ea7 100644 --- a/tests/ui/proc-macro/expand-to-unstable.stderr +++ b/tests/ui/proc-macro/expand-to-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `core_intrinsics`: intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library - --> $DIR/expand-to-unstable.rs:8:10 + --> $DIR/expand-to-unstable.rs:9:10 | LL | #[derive(Unstable)] | ^^^^^^^^ diff --git a/tests/ui/proc-macro/expand-with-a-macro.rs b/tests/ui/proc-macro/expand-with-a-macro.rs index e5baf3601db0..aa02cefbec68 100644 --- a/tests/ui/proc-macro/expand-with-a-macro.rs +++ b/tests/ui/proc-macro/expand-with-a-macro.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ proc-macro: expand-with-a-macro.rs +//@ ignore-backends: gcc #![deny(warnings)] diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.rs b/tests/ui/proc-macro/gen-macro-rules-hygiene.rs index 3deec94fa341..fb7c830c2edf 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.rs +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.rs @@ -3,6 +3,7 @@ // `$crate` refers to the crate that defines `macro_rules` and not the outer transparent macro. //@ proc-macro: gen-macro-rules-hygiene.rs +//@ ignore-backends: gcc #[macro_use] extern crate gen_macro_rules_hygiene; diff --git a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr index df7c4f72eb0b..e904b43aaae0 100644 --- a/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr +++ b/tests/ui/proc-macro/gen-macro-rules-hygiene.stderr @@ -1,5 +1,5 @@ error[E0426]: use of undeclared label `'label_use` - --> $DIR/gen-macro-rules-hygiene.rs:12:1 + --> $DIR/gen-macro-rules-hygiene.rs:13:1 | LL | gen_macro_rules!(); | ^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` @@ -10,7 +10,7 @@ LL | generated!(); = 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_use` in this scope - --> $DIR/gen-macro-rules-hygiene.rs:12:1 + --> $DIR/gen-macro-rules-hygiene.rs:13:1 | LL | gen_macro_rules!(); | ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` @@ -21,7 +21,7 @@ LL | generated!(); = 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 - --> $DIR/gen-macro-rules-hygiene.rs:21:9 + --> $DIR/gen-macro-rules-hygiene.rs:22:9 | LL | local_def; | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` diff --git a/tests/ui/proc-macro/gen-macro-rules.rs b/tests/ui/proc-macro/gen-macro-rules.rs index 121d029e2e34..8ee38b2cc279 100644 --- a/tests/ui/proc-macro/gen-macro-rules.rs +++ b/tests/ui/proc-macro/gen-macro-rules.rs @@ -2,6 +2,7 @@ //@ check-pass //@ proc-macro: gen-macro-rules.rs +//@ ignore-backends: gcc extern crate gen_macro_rules as repro; diff --git a/tests/ui/proc-macro/generate-mod.rs b/tests/ui/proc-macro/generate-mod.rs index 729bfc1db667..0a1629e75ec1 100644 --- a/tests/ui/proc-macro/generate-mod.rs +++ b/tests/ui/proc-macro/generate-mod.rs @@ -1,6 +1,7 @@ // Modules generated by transparent proc macros still acts as barriers for names (issue #50504). //@ proc-macro: generate-mod.rs +//@ ignore-backends: gcc extern crate generate_mod; diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index 142ff1abeed6..03cf8c35188a 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:9:1 + --> $DIR/generate-mod.rs:10:1 | LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -9,7 +9,7 @@ LL | generate_mod::check!(); = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Outer` in this scope - --> $DIR/generate-mod.rs:9:1 + --> $DIR/generate-mod.rs:10:1 | LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -19,7 +19,7 @@ LL | generate_mod::check!(); = note: this error originates in the macro `generate_mod::check` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:12:1 + --> $DIR/generate-mod.rs:13:1 | LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -29,7 +29,7 @@ LL | #[generate_mod::check_attr] = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `OuterAttr` in this scope - --> $DIR/generate-mod.rs:12:1 + --> $DIR/generate-mod.rs:13:1 | LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -39,7 +39,7 @@ LL | #[generate_mod::check_attr] = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:16:10 + --> $DIR/generate-mod.rs:17:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -50,7 +50,7 @@ LL | #[derive(generate_mod::CheckDerive)] = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope - --> $DIR/generate-mod.rs:16:10 + --> $DIR/generate-mod.rs:17:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -60,7 +60,7 @@ LL | #[derive(generate_mod::CheckDerive)] = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:23:14 + --> $DIR/generate-mod.rs:24:14 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -70,7 +70,7 @@ LL | #[derive(generate_mod::CheckDerive)] = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope - --> $DIR/generate-mod.rs:23:14 + --> $DIR/generate-mod.rs:24:14 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -84,7 +84,7 @@ error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0412`. Future incompatibility report: Future breakage diagnostic: error: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:16:10 + --> $DIR/generate-mod.rs:17:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -96,7 +96,7 @@ LL | #[derive(generate_mod::CheckDerive)] Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope - --> $DIR/generate-mod.rs:16:10 + --> $DIR/generate-mod.rs:17:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -108,7 +108,7 @@ LL | #[derive(generate_mod::CheckDerive)] Future breakage diagnostic: error: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:23:14 + --> $DIR/generate-mod.rs:24:14 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -120,7 +120,7 @@ LL | #[derive(generate_mod::CheckDerive)] Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope - --> $DIR/generate-mod.rs:23:14 + --> $DIR/generate-mod.rs:24:14 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -132,7 +132,7 @@ LL | #[derive(generate_mod::CheckDerive)] Future breakage diagnostic: warning: cannot find type `FromOutside` in this scope - --> $DIR/generate-mod.rs:30:10 + --> $DIR/generate-mod.rs:31:10 | LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import @@ -143,7 +143,7 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed Future breakage diagnostic: warning: cannot find type `OuterDeriveLint` in this scope - --> $DIR/generate-mod.rs:30:10 + --> $DIR/generate-mod.rs:31:10 | LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import diff --git a/tests/ui/proc-macro/hygiene_example.rs b/tests/ui/proc-macro/hygiene_example.rs index 84b5e345608a..f74f22fb3b0e 100644 --- a/tests/ui/proc-macro/hygiene_example.rs +++ b/tests/ui/proc-macro/hygiene_example.rs @@ -1,5 +1,6 @@ //@ check-pass //@ aux-build:hygiene_example.rs +//@ ignore-backends: gcc extern crate hygiene_example; use hygiene_example::hello; diff --git a/tests/ui/proc-macro/is-available.rs b/tests/ui/proc-macro/is-available.rs index faee560d7a97..9e9cf5d11b66 100644 --- a/tests/ui/proc-macro/is-available.rs +++ b/tests/ui/proc-macro/is-available.rs @@ -3,6 +3,7 @@ extern crate proc_macro; //@ proc-macro: is-available.rs +//@ ignore-backends: gcc extern crate is_available; fn main() { diff --git a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.rs b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.rs index abdd6bf136dc..d420f2641daf 100644 --- a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.rs +++ b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-104884.rs +//@ ignore-backends: gcc use std::collections::BinaryHeap; diff --git a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr index f3ed9e5761d6..b7aed4a8485a 100644 --- a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr +++ b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr @@ -1,11 +1,11 @@ error[E0277]: can't compare `PriorityQueue` with `PriorityQueue` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:10 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:10 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^^^^ no implementation for `PriorityQueue == PriorityQueue` | help: the trait `PartialEq` is not implemented for `PriorityQueue` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:20:1 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:21:1 | LL | struct PriorityQueue(BinaryHeap>); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,13 +13,13 @@ note: required by a bound in `PartialOrd` --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0277]: the trait bound `PriorityQueue: Eq` is not satisfied - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:22 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:22 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^ unsatisfied trait bound | help: the trait `Eq` is not implemented for `PriorityQueue` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:20:1 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:21:1 | LL | struct PriorityQueue(BinaryHeap>); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,13 +28,13 @@ note: required by a bound in `Ord` = note: this error originates in the derive macro `AddImpl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `T` with `T` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:22 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:22 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^ no implementation for `T < T` and `T > T` | note: required for `PriorityQueue` to implement `PartialOrd` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:10 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:10 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro @@ -42,7 +42,7 @@ note: required by a bound in `Ord` --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0277]: can't compare `BinaryHeap>` with `_` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:20:25 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:21:25 | LL | #[derive(PartialOrd, AddImpl)] | ---------- in this derive macro expansion @@ -53,7 +53,7 @@ LL | struct PriorityQueue(BinaryHeap>); = help: the trait `PartialOrd<_>` is not implemented for `BinaryHeap>` error[E0599]: no method named `cmp` found for struct `BinaryHeap>` in the current scope - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:22 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:22 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^ `BinaryHeap>` is not an iterator @@ -61,7 +61,7 @@ LL | #[derive(PartialOrd, AddImpl)] = note: this error originates in the derive macro `AddImpl` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0609]: no field `height` on type `&PriorityQueue` - --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:22 + --> $DIR/issue-104884-trait-impl-sugg-err.rs:14:22 | LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^ unknown field diff --git a/tests/ui/proc-macro/issue-107113-wrap.rs b/tests/ui/proc-macro/issue-107113-wrap.rs index 2799e79bb1cb..a46cf893d90e 100644 --- a/tests/ui/proc-macro/issue-107113-wrap.rs +++ b/tests/ui/proc-macro/issue-107113-wrap.rs @@ -1,5 +1,6 @@ //@ edition:2021 //@ proc-macro: issue-107113.rs +//@ ignore-backends: gcc #[macro_use] extern crate issue_107113; diff --git a/tests/ui/proc-macro/issue-107113-wrap.stderr b/tests/ui/proc-macro/issue-107113-wrap.stderr index b541051147d5..9b5b0333256e 100644 --- a/tests/ui/proc-macro/issue-107113-wrap.stderr +++ b/tests/ui/proc-macro/issue-107113-wrap.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-107113-wrap.rs:7:1 + --> $DIR/issue-107113-wrap.rs:8:1 | LL | #[issue_107113::main] | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/issue-118809.rs b/tests/ui/proc-macro/issue-118809.rs index a6a3956981a7..3ceede7e885c 100644 --- a/tests/ui/proc-macro/issue-118809.rs +++ b/tests/ui/proc-macro/issue-118809.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-118809.rs +//@ ignore-backends: gcc #[macro_use] extern crate issue_118809; diff --git a/tests/ui/proc-macro/issue-118809.stderr b/tests/ui/proc-macro/issue-118809.stderr index 30b09fd4006b..98329fea1194 100644 --- a/tests/ui/proc-macro/issue-118809.stderr +++ b/tests/ui/proc-macro/issue-118809.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-118809.rs:6:10 + --> $DIR/issue-118809.rs:7:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[derive(Deserialize)] | arguments to this enum variant are incorrect | help: the type constructed contains `u32` due to the type of the argument passed - --> $DIR/issue-118809.rs:6:10 + --> $DIR/issue-118809.rs:7:10 | LL | #[derive(Deserialize)] | ^^^^^^^^^^^ this argument influences the type of `Some` diff --git a/tests/ui/proc-macro/issue-38586.rs b/tests/ui/proc-macro/issue-38586.rs index 88dbb8037beb..c9623fd383b1 100644 --- a/tests/ui/proc-macro/issue-38586.rs +++ b/tests/ui/proc-macro/issue-38586.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-38586.rs +//@ ignore-backends: gcc #[macro_use] extern crate issue_38586; diff --git a/tests/ui/proc-macro/issue-38586.stderr b/tests/ui/proc-macro/issue-38586.stderr index 004915564507..e49d4c83e273 100644 --- a/tests/ui/proc-macro/issue-38586.stderr +++ b/tests/ui/proc-macro/issue-38586.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `foo` in this scope - --> $DIR/issue-38586.rs:6:10 + --> $DIR/issue-38586.rs:7:10 | LL | #[derive(A)] | ^ not found in this scope diff --git a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs index df236cce6d2a..988641b2b9c4 100644 --- a/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -4,6 +4,7 @@ //@ edition:2018 //@ proc-macro: issue-59191.rs //@ needs-unwind (affects error output) +//@ ignore-backends: gcc #![feature(custom_inner_attributes)] #![issue_59191::no_main] diff --git a/tests/ui/proc-macro/issue-79148.rs b/tests/ui/proc-macro/issue-79148.rs index b2248759b5f8..7ce6216c842a 100644 --- a/tests/ui/proc-macro/issue-79148.rs +++ b/tests/ui/proc-macro/issue-79148.rs @@ -1,5 +1,6 @@ //@ proc-macro: re-export.rs //@ edition:2018 +//@ ignore-backends: gcc extern crate re_export; diff --git a/tests/ui/proc-macro/issue-79148.stderr b/tests/ui/proc-macro/issue-79148.stderr index 8adc4c6e0dbe..80a5b1a0855f 100644 --- a/tests/ui/proc-macro/issue-79148.stderr +++ b/tests/ui/proc-macro/issue-79148.stderr @@ -1,11 +1,11 @@ error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside - --> $DIR/issue-79148.rs:8:1 + --> $DIR/issue-79148.rs:9:1 | LL | cause_ice!(); | ^^^^^^^^^^^^ | note: consider marking `Variant` as `pub` in the imported module - --> $DIR/issue-79148.rs:8:1 + --> $DIR/issue-79148.rs:9:1 | LL | cause_ice!(); | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/issue-83510.rs b/tests/ui/proc-macro/issue-83510.rs index 67469511fc36..d49e1867f1d6 100644 --- a/tests/ui/proc-macro/issue-83510.rs +++ b/tests/ui/proc-macro/issue-83510.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-83510.rs +//@ ignore-backends: gcc extern crate issue_83510; diff --git a/tests/ui/proc-macro/issue-83510.stderr b/tests/ui/proc-macro/issue-83510.stderr index e59b77af3dc3..a7c3f5a1d5b6 100644 --- a/tests/ui/proc-macro/issue-83510.stderr +++ b/tests/ui/proc-macro/issue-83510.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Foo` in this scope - --> $DIR/issue-83510.rs:5:1 + --> $DIR/issue-83510.rs:6:1 | LL | issue_83510::dance_like_you_want_to_ice!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -7,7 +7,7 @@ LL | issue_83510::dance_like_you_want_to_ice!(); = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0404]: expected trait, found struct `Box` - --> $DIR/issue-83510.rs:5:1 + --> $DIR/issue-83510.rs:6:1 | LL | issue_83510::dance_like_you_want_to_ice!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait @@ -15,7 +15,7 @@ LL | issue_83510::dance_like_you_want_to_ice!(); = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0405]: cannot find trait `Baz` in this scope - --> $DIR/issue-83510.rs:5:1 + --> $DIR/issue-83510.rs:6:1 | LL | issue_83510::dance_like_you_want_to_ice!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope @@ -23,7 +23,7 @@ LL | issue_83510::dance_like_you_want_to_ice!(); = note: this error originates in the macro `issue_83510::dance_like_you_want_to_ice` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: inherent associated types are unstable - --> $DIR/issue-83510.rs:5:1 + --> $DIR/issue-83510.rs:6:1 | LL | issue_83510::dance_like_you_want_to_ice!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/issue-91800.rs b/tests/ui/proc-macro/issue-91800.rs index 8cecfad32b55..79cbf8632f00 100644 --- a/tests/ui/proc-macro/issue-91800.rs +++ b/tests/ui/proc-macro/issue-91800.rs @@ -1,4 +1,5 @@ //@ proc-macro: issue-91800-macro.rs +//@ ignore-backends: gcc #[macro_use] extern crate issue_91800_macro; diff --git a/tests/ui/proc-macro/issue-91800.stderr b/tests/ui/proc-macro/issue-91800.stderr index 63ebc0a552e3..be5a8ece3840 100644 --- a/tests/ui/proc-macro/issue-91800.stderr +++ b/tests/ui/proc-macro/issue-91800.stderr @@ -1,5 +1,5 @@ error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:6:10 + --> $DIR/issue-91800.rs:7:10 | LL | #[derive(MyTrait)] | ^^^^^^^ @@ -7,13 +7,13 @@ LL | #[derive(MyTrait)] = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info) error: proc-macro derive produced unparsable tokens - --> $DIR/issue-91800.rs:6:10 + --> $DIR/issue-91800.rs:7:10 | LL | #[derive(MyTrait)] | ^^^^^^^ error: - --> $DIR/issue-91800.rs:6:10 + --> $DIR/issue-91800.rs:7:10 | LL | #[derive(MyTrait)] | ^^^^^^^ @@ -21,7 +21,7 @@ LL | #[derive(MyTrait)] = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:10:1 + --> $DIR/issue-91800.rs:11:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:10:1 + --> $DIR/issue-91800.rs:11:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:15:1 + --> $DIR/issue-91800.rs:16:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn_macro! {} = note: this error originates in the macro `fn_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:15:1 + --> $DIR/issue-91800.rs:16:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/lifetimes-rpass.rs b/tests/ui/proc-macro/lifetimes-rpass.rs index c462b27722f7..9b794e695cd1 100644 --- a/tests/ui/proc-macro/lifetimes-rpass.rs +++ b/tests/ui/proc-macro/lifetimes-rpass.rs @@ -2,6 +2,7 @@ #![allow(unused_variables)] //@ proc-macro: lifetimes-rpass.rs +//@ ignore-backends: gcc extern crate lifetimes_rpass as lifetimes; use lifetimes::*; diff --git a/tests/ui/proc-macro/lints_in_proc_macros.rs b/tests/ui/proc-macro/lints_in_proc_macros.rs index 6714b8b6e1d5..2c22c787982e 100644 --- a/tests/ui/proc-macro/lints_in_proc_macros.rs +++ b/tests/ui/proc-macro/lints_in_proc_macros.rs @@ -1,4 +1,5 @@ //@ proc-macro: bang_proc_macro2.rs +//@ ignore-backends: gcc extern crate bang_proc_macro2; diff --git a/tests/ui/proc-macro/lints_in_proc_macros.stderr b/tests/ui/proc-macro/lints_in_proc_macros.stderr index 244d218608be..016b236bda88 100644 --- a/tests/ui/proc-macro/lints_in_proc_macros.stderr +++ b/tests/ui/proc-macro/lints_in_proc_macros.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `foobar2` in this scope - --> $DIR/lints_in_proc_macros.rs:9:5 + --> $DIR/lints_in_proc_macros.rs:10:5 | LL | bang_proc_macro2!(); | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `foobar` diff --git a/tests/ui/proc-macro/load-two.rs b/tests/ui/proc-macro/load-two.rs index 608379949e66..197e7845db33 100644 --- a/tests/ui/proc-macro/load-two.rs +++ b/tests/ui/proc-macro/load-two.rs @@ -4,6 +4,7 @@ #![allow(dead_code)] //@ proc-macro: derive-atob.rs //@ proc-macro: derive-ctod.rs +//@ ignore-backends: gcc #[macro_use] extern crate derive_atob; diff --git a/tests/ui/proc-macro/macro-crate-multi-decorator.rs b/tests/ui/proc-macro/macro-crate-multi-decorator.rs index c4f02e7adfcb..e247c9526a4c 100644 --- a/tests/ui/proc-macro/macro-crate-multi-decorator.rs +++ b/tests/ui/proc-macro/macro-crate-multi-decorator.rs @@ -2,6 +2,7 @@ //@ check-pass //@ proc-macro: duplicate.rs +//@ ignore-backends: gcc #[macro_use] extern crate duplicate; diff --git a/tests/ui/proc-macro/macro_rules_edition_from_pm.rs b/tests/ui/proc-macro/macro_rules_edition_from_pm.rs index 8fc7d9097493..fc3ae3ef2c81 100644 --- a/tests/ui/proc-macro/macro_rules_edition_from_pm.rs +++ b/tests/ui/proc-macro/macro_rules_edition_from_pm.rs @@ -7,6 +7,7 @@ //@[edition2021] edition:2021 //@[edition2024] edition:2024 //@ check-pass +//@ ignore-backends: gcc // This checks how the expr fragment specifier works. macro_rules_edition_pm::make_edition_macro!{} diff --git a/tests/ui/proc-macro/match-expander.rs b/tests/ui/proc-macro/match-expander.rs index 23e5746c540f..b7245c7e682c 100644 --- a/tests/ui/proc-macro/match-expander.rs +++ b/tests/ui/proc-macro/match-expander.rs @@ -1,4 +1,5 @@ //@ proc-macro: match-expander.rs +//@ ignore-backends: gcc // Ensure that we don't point at macro invocation when providing inference contexts. #[macro_use] diff --git a/tests/ui/proc-macro/match-expander.stderr b/tests/ui/proc-macro/match-expander.stderr index b77468ec60a5..d2423336b1d2 100644 --- a/tests/ui/proc-macro/match-expander.stderr +++ b/tests/ui/proc-macro/match-expander.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/match-expander.rs:8:5 + --> $DIR/match-expander.rs:9:5 | LL | match_expander::matcher!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `S`, found `bool` diff --git a/tests/ui/proc-macro/mixed-site-span.rs b/tests/ui/proc-macro/mixed-site-span.rs index 442b440c1211..98a022632cd5 100644 --- a/tests/ui/proc-macro/mixed-site-span.rs +++ b/tests/ui/proc-macro/mixed-site-span.rs @@ -2,6 +2,7 @@ //@ aux-build: token-site-span.rs //@ proc-macro: mixed-site-span.rs +//@ ignore-backends: gcc extern crate mixed_site_span; extern crate token_site_span; diff --git a/tests/ui/proc-macro/mixed-site-span.stderr b/tests/ui/proc-macro/mixed-site-span.stderr index d62031a853c0..2d2d55fe148d 100644 --- a/tests/ui/proc-macro/mixed-site-span.stderr +++ b/tests/ui/proc-macro/mixed-site-span.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:47:5 + --> $DIR/mixed-site-span.rs:48:5 | LL | invoke_with_crate!{input proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -7,7 +7,7 @@ LL | invoke_with_crate!{input proc_macro_item} = note: this error originates in the macro `invoke_with_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:48:5 + --> $DIR/mixed-site-span.rs:49:5 | LL | invoke_with_ident!{input proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -15,7 +15,7 @@ LL | invoke_with_ident!{input proc_macro_item} = note: this error originates in the macro `invoke_with_ident` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:49:5 + --> $DIR/mixed-site-span.rs:50:5 | LL | invoke_with_crate!{call proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -23,7 +23,7 @@ LL | invoke_with_crate!{call proc_macro_item} = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `invoke_with_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:50:5 + --> $DIR/mixed-site-span.rs:51:5 | LL | invoke_with_ident!{call proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -31,7 +31,7 @@ LL | invoke_with_ident!{call proc_macro_item} = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `invoke_with_ident` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:51:5 + --> $DIR/mixed-site-span.rs:52:5 | LL | invoke_with_ident!{hello call proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -39,7 +39,7 @@ LL | invoke_with_ident!{hello call proc_macro_item} = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `invoke_with_ident` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate::proc_macro_item` - --> $DIR/mixed-site-span.rs:54:5 + --> $DIR/mixed-site-span.rs:55:5 | LL | invoke_with_ident!{krate input proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -50,7 +50,7 @@ LL | invoke_with_ident!{krate input proc_macro_item} = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `invoke_with_ident` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate::proc_macro_item` - --> $DIR/mixed-site-span.rs:55:5 + --> $DIR/mixed-site-span.rs:56:5 | LL | with_crate!{krate input proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -61,7 +61,7 @@ LL | with_crate!{krate input proc_macro_item} = note: this error originates in the macro `with_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:56:5 + --> $DIR/mixed-site-span.rs:57:5 | LL | with_crate!{krate call proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -72,7 +72,7 @@ LL | with_crate!{krate call proc_macro_item} = note: this error originates in the macro `with_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:60:28 + --> $DIR/mixed-site-span.rs:61:28 | LL | invoke_with_ident!{$crate input proc_macro_item} | ^^^^^^ --------------- help: a similar name exists in the module: `proc_macro_rules` @@ -85,7 +85,7 @@ LL | test!(); = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:61:21 + --> $DIR/mixed-site-span.rs:62:21 | LL | with_crate!{$crate input proc_macro_item} | ^^^^^^ --------------- help: a similar name exists in the module: `proc_macro_rules` @@ -98,7 +98,7 @@ LL | test!(); = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:62:9 + --> $DIR/mixed-site-span.rs:63:9 | LL | with_crate!{$crate call proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -112,7 +112,7 @@ LL | test!(); = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:67:5 + --> $DIR/mixed-site-span.rs:68:5 | LL | test!(); | ^^^^^^^ no `proc_macro_item` in the root @@ -120,7 +120,7 @@ LL | test!(); = note: this error originates in the macro `with_crate` which comes from the expansion of the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate::TokenItem` - --> $DIR/mixed-site-span.rs:87:5 + --> $DIR/mixed-site-span.rs:88:5 | LL | invoke_with_ident!{krate input TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -133,7 +133,7 @@ LL | quote!(use $krate::$ident as token_site_span::TokenItem as _;) | +++++++++++++++++++++++++++++ error[E0432]: unresolved import `$crate::TokenItem` - --> $DIR/mixed-site-span.rs:88:5 + --> $DIR/mixed-site-span.rs:89:5 | LL | with_crate!{krate input TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -146,7 +146,7 @@ LL | quote!(use $krate::$ident as token_site_span::TokenItem as _;) | +++++++++++++++++++++++++++++ error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:89:5 + --> $DIR/mixed-site-span.rs:90:5 | LL | with_crate!{krate call TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -159,7 +159,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:92:5 + --> $DIR/mixed-site-span.rs:93:5 | LL | invoke_with_crate!{mixed TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -173,7 +173,7 @@ LL + ($s:ident $i:ident) => { token_site_span::TokenItem as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:93:5 + --> $DIR/mixed-site-span.rs:94:5 | LL | invoke_with_ident!{mixed TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -187,7 +187,7 @@ LL + ($s:ident $i:ident) => { token_site_span::TokenItem as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:94:5 + --> $DIR/mixed-site-span.rs:95:5 | LL | invoke_with_ident!{krate mixed TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -201,7 +201,7 @@ LL + ($m:ident $s:ident $i:ident) => { token_site_span::TokenItem as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:95:5 + --> $DIR/mixed-site-span.rs:96:5 | LL | with_crate!{krate mixed TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -214,7 +214,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:99:28 + --> $DIR/mixed-site-span.rs:100:28 | LL | invoke_with_ident!{$crate input TokenItem} | ^^^^^^ no `TokenItem` in the root @@ -230,7 +230,7 @@ LL + invoke_with_ident!{token_site_span::TokenItem as _ input TokenItem} | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:100:21 + --> $DIR/mixed-site-span.rs:101:21 | LL | with_crate!{$crate input TokenItem} | ^^^^^^ no `TokenItem` in the root @@ -246,7 +246,7 @@ LL + with_crate!{token_site_span::TokenItem as _ input TokenItem} | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:101:9 + --> $DIR/mixed-site-span.rs:102:9 | LL | with_crate!{$crate call TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -262,7 +262,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:108:5 + --> $DIR/mixed-site-span.rs:109:5 | LL | test!(); | ^^^^^^^ no `TokenItem` in the root @@ -276,7 +276,7 @@ LL + ($m:ident $s:ident $i:ident) => { token_site_span::TokenItem as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:105:9 + --> $DIR/mixed-site-span.rs:106:9 | LL | with_crate!{$crate mixed TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -292,7 +292,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:129:5 + --> $DIR/mixed-site-span.rs:130:5 | LL | invoke_with_crate!{input ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -306,7 +306,7 @@ LL + ($s:ident $i:ident) => { with_crate!{ItemUse as _ $s $i} }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:130:5 + --> $DIR/mixed-site-span.rs:131:5 | LL | invoke_with_ident!{input ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -320,7 +320,7 @@ LL + ($s:ident $i:ident) => { with_crate!{ItemUse as _ $s $i} }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:133:5 + --> $DIR/mixed-site-span.rs:134:5 | LL | invoke_with_crate!{mixed ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -334,7 +334,7 @@ LL + ($s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:134:5 + --> $DIR/mixed-site-span.rs:135:5 | LL | invoke_with_ident!{mixed ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -348,7 +348,7 @@ LL + ($s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:135:5 + --> $DIR/mixed-site-span.rs:136:5 | LL | invoke_with_ident!{krate mixed ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -362,7 +362,7 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:136:5 + --> $DIR/mixed-site-span.rs:137:5 | LL | with_crate!{krate mixed ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -375,7 +375,7 @@ LL + ItemUse as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:138:5 + --> $DIR/mixed-site-span.rs:139:5 | LL | invoke_with_crate!{call ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -389,7 +389,7 @@ LL + ($s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:139:5 + --> $DIR/mixed-site-span.rs:140:5 | LL | invoke_with_ident!{call ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -403,7 +403,7 @@ LL + ($s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:140:5 + --> $DIR/mixed-site-span.rs:141:5 | LL | invoke_with_ident!{hello call ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -417,7 +417,7 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:148:5 + --> $DIR/mixed-site-span.rs:149:5 | LL | test!(); | ^^^^^^^ no `ItemUse` in the root @@ -431,7 +431,7 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:144:9 + --> $DIR/mixed-site-span.rs:145:9 | LL | with_crate!{$crate mixed ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -447,7 +447,7 @@ LL + ItemUse as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:148:5 + --> $DIR/mixed-site-span.rs:149:5 | LL | test!(); | ^^^^^^^ no `ItemUse` in the root @@ -461,7 +461,7 @@ LL + ($m:ident $s:ident $i:ident) => { ItemUse as _ }; | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:153:1 + --> $DIR/mixed-site-span.rs:154:1 | LL | use_input_crate!{proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -469,7 +469,7 @@ LL | use_input_crate!{proc_macro_item} = note: this error originates in the macro `use_input_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:154:1 + --> $DIR/mixed-site-span.rs:155:1 | LL | use_input_krate!{proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -477,7 +477,7 @@ LL | use_input_krate!{proc_macro_item} = note: this error originates in the macro `use_input_krate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:157:1 + --> $DIR/mixed-site-span.rs:158:1 | LL | use_call_crate!{proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -485,7 +485,7 @@ LL | use_call_crate!{proc_macro_item} = note: this error originates in the macro `use_call_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:158:1 + --> $DIR/mixed-site-span.rs:159:1 | LL | use_call_krate!{proc_macro_item} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `proc_macro_item` in the root @@ -493,7 +493,7 @@ LL | use_call_krate!{proc_macro_item} = note: this error originates in the macro `use_call_krate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:163:1 + --> $DIR/mixed-site-span.rs:164:1 | LL | use_mixed_crate!{TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -507,7 +507,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:164:1 + --> $DIR/mixed-site-span.rs:165:1 | LL | use_mixed_krate!{TokenItem} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokenItem` in the root @@ -521,7 +521,7 @@ LL + token_site_span::TokenItem as _ | error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:169:1 + --> $DIR/mixed-site-span.rs:170:1 | LL | use_input_crate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -529,7 +529,7 @@ LL | use_input_crate!{ItemUse} = note: this error originates in the macro `use_input_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:170:1 + --> $DIR/mixed-site-span.rs:171:1 | LL | use_input_krate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -537,7 +537,7 @@ LL | use_input_krate!{ItemUse} = note: this error originates in the macro `use_input_krate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:171:1 + --> $DIR/mixed-site-span.rs:172:1 | LL | use_mixed_crate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -545,7 +545,7 @@ LL | use_mixed_crate!{ItemUse} = note: this error originates in the macro `use_mixed_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:172:1 + --> $DIR/mixed-site-span.rs:173:1 | LL | use_mixed_krate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -553,7 +553,7 @@ LL | use_mixed_krate!{ItemUse} = note: this error originates in the macro `use_mixed_krate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:173:1 + --> $DIR/mixed-site-span.rs:174:1 | LL | use_call_crate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -561,7 +561,7 @@ LL | use_call_crate!{ItemUse} = note: this error originates in the macro `use_call_crate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0432]: unresolved import `$crate` - --> $DIR/mixed-site-span.rs:174:1 + --> $DIR/mixed-site-span.rs:175:1 | LL | use_call_krate!{ItemUse} | ^^^^^^^^^^^^^^^^^^^^^^^^ no `ItemUse` in the root @@ -569,7 +569,7 @@ LL | use_call_krate!{ItemUse} = note: this error originates in the macro `use_call_krate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0426]: use of undeclared label `'label_use` - --> $DIR/mixed-site-span.rs:21:9 + --> $DIR/mixed-site-span.rs:22:9 | LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ undeclared label `'label_use` @@ -577,7 +577,7 @@ LL | proc_macro_rules!(); = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `ItemUse` in crate `$crate` - --> $DIR/mixed-site-span.rs:21:9 + --> $DIR/mixed-site-span.rs:22:9 | LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ not found in `$crate` @@ -589,7 +589,7 @@ LL + use ItemUse; | error[E0425]: cannot find value `local_use` in this scope - --> $DIR/mixed-site-span.rs:21:9 + --> $DIR/mixed-site-span.rs:22:9 | LL | proc_macro_rules!(); | ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def` @@ -597,7 +597,7 @@ LL | proc_macro_rules!(); = 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 - --> $DIR/mixed-site-span.rs:26:9 + --> $DIR/mixed-site-span.rs:27:9 | LL | local_def; | ^^^^^^^^^ help: a local variable with a similar name exists: `local_use` diff --git a/tests/ui/proc-macro/modify-ast.rs b/tests/ui/proc-macro/modify-ast.rs index 9e890f3ebaad..75aea597ed57 100644 --- a/tests/ui/proc-macro/modify-ast.rs +++ b/tests/ui/proc-macro/modify-ast.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: modify-ast.rs +//@ ignore-backends: gcc extern crate modify_ast; diff --git a/tests/ui/proc-macro/parent-source-spans.rs b/tests/ui/proc-macro/parent-source-spans.rs index cc3ac795f7f1..f675f6fb6f7d 100644 --- a/tests/ui/proc-macro/parent-source-spans.rs +++ b/tests/ui/proc-macro/parent-source-spans.rs @@ -1,4 +1,5 @@ //@ proc-macro: parent-source-spans.rs +//@ ignore-backends: gcc #![feature(decl_macro)] diff --git a/tests/ui/proc-macro/parent-source-spans.stderr b/tests/ui/proc-macro/parent-source-spans.stderr index db1eed5e4588..28a70eea873d 100644 --- a/tests/ui/proc-macro/parent-source-spans.stderr +++ b/tests/ui/proc-macro/parent-source-spans.stderr @@ -1,5 +1,5 @@ error: first final: "hello" - --> $DIR/parent-source-spans.rs:16:12 + --> $DIR/parent-source-spans.rs:17:12 | LL | three!($a, $b); | ^^ @@ -10,7 +10,7 @@ LL | one!("hello", "world"); = note: this error originates in the macro `two` which comes from the expansion of the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) error: second final: "world" - --> $DIR/parent-source-spans.rs:16:16 + --> $DIR/parent-source-spans.rs:17:16 | LL | three!($a, $b); | ^^ @@ -21,7 +21,7 @@ LL | one!("hello", "world"); = note: this error originates in the macro `two` which comes from the expansion of the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) error: first parent: "hello" - --> $DIR/parent-source-spans.rs:10:5 + --> $DIR/parent-source-spans.rs:11:5 | LL | two!($a, $b); | ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | one!("hello", "world"); = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) error: second parent: "world" - --> $DIR/parent-source-spans.rs:10:5 + --> $DIR/parent-source-spans.rs:11:5 | LL | two!($a, $b); | ^^^^^^^^^^^^ @@ -43,31 +43,31 @@ LL | one!("hello", "world"); = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) error: first grandparent: "hello" - --> $DIR/parent-source-spans.rs:36:5 + --> $DIR/parent-source-spans.rs:37:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ error: second grandparent: "world" - --> $DIR/parent-source-spans.rs:36:5 + --> $DIR/parent-source-spans.rs:37:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ error: first source: "hello" - --> $DIR/parent-source-spans.rs:36:5 + --> $DIR/parent-source-spans.rs:37:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ error: second source: "world" - --> $DIR/parent-source-spans.rs:36:5 + --> $DIR/parent-source-spans.rs:37:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ error: first final: "yay" - --> $DIR/parent-source-spans.rs:16:12 + --> $DIR/parent-source-spans.rs:17:12 | LL | three!($a, $b); | ^^ @@ -78,7 +78,7 @@ LL | two!("yay", "rust"); = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) error: second final: "rust" - --> $DIR/parent-source-spans.rs:16:16 + --> $DIR/parent-source-spans.rs:17:16 | LL | three!($a, $b); | ^^ @@ -89,55 +89,55 @@ LL | two!("yay", "rust"); = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) error: first parent: "yay" - --> $DIR/parent-source-spans.rs:42:5 + --> $DIR/parent-source-spans.rs:43:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ error: second parent: "rust" - --> $DIR/parent-source-spans.rs:42:5 + --> $DIR/parent-source-spans.rs:43:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ error: first source: "yay" - --> $DIR/parent-source-spans.rs:42:5 + --> $DIR/parent-source-spans.rs:43:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ error: second source: "rust" - --> $DIR/parent-source-spans.rs:42:5 + --> $DIR/parent-source-spans.rs:43:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ error: first final: "hip" - --> $DIR/parent-source-spans.rs:48:12 + --> $DIR/parent-source-spans.rs:49:12 | LL | three!("hip", "hop"); | ^^^^^ error: second final: "hop" - --> $DIR/parent-source-spans.rs:48:19 + --> $DIR/parent-source-spans.rs:49:19 | LL | three!("hip", "hop"); | ^^^^^ error: first source: "hip" - --> $DIR/parent-source-spans.rs:48:12 + --> $DIR/parent-source-spans.rs:49:12 | LL | three!("hip", "hop"); | ^^^^^ error: second source: "hop" - --> $DIR/parent-source-spans.rs:48:19 + --> $DIR/parent-source-spans.rs:49:19 | LL | three!("hip", "hop"); | ^^^^^ error[E0425]: cannot find value `ok` in this scope - --> $DIR/parent-source-spans.rs:29:5 + --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` @@ -152,7 +152,7 @@ LL | one!("hello", "world"); = note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `ok` in this scope - --> $DIR/parent-source-spans.rs:29:5 + --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` @@ -167,7 +167,7 @@ LL | two!("yay", "rust"); = note: this error originates in the macro `parent_source_spans` which comes from the expansion of the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `ok` in this scope - --> $DIR/parent-source-spans.rs:29:5 + --> $DIR/parent-source-spans.rs:30:5 | LL | parent_source_spans!($($tokens)*); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok` diff --git a/tests/ui/proc-macro/quote/basic.rs b/tests/ui/proc-macro/quote/basic.rs index 0336dbb78562..4c6fb2408fb4 100644 --- a/tests/ui/proc-macro/quote/basic.rs +++ b/tests/ui/proc-macro/quote/basic.rs @@ -1,5 +1,6 @@ //@ run-pass //@ proc-macro: basic.rs +//@ ignore-backends: gcc extern crate basic; diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs index 792859ed05b1..12832ba11639 100644 --- a/tests/ui/proc-macro/span-api-tests.rs +++ b/tests/ui/proc-macro/span-api-tests.rs @@ -2,6 +2,7 @@ //@ proc-macro: span-api-tests.rs //@ aux-build:span-test-macros.rs //@ compile-flags: -Ztranslate-remapped-path-to-local-path=yes +//@ ignore-backends: gcc #[macro_use] extern crate span_test_macros; diff --git a/tests/ui/proc-macro/span-from-proc-macro.rs b/tests/ui/proc-macro/span-from-proc-macro.rs index 4e12a695a5c0..24a28d53476c 100644 --- a/tests/ui/proc-macro/span-from-proc-macro.rs +++ b/tests/ui/proc-macro/span-from-proc-macro.rs @@ -1,6 +1,7 @@ //@ proc-macro: custom-quote.rs //@ proc-macro: span-from-proc-macro.rs //@ compile-flags: -Z macro-backtrace +//@ ignore-backends: gcc #[macro_use] extern crate span_from_proc_macro; diff --git a/tests/ui/proc-macro/span-from-proc-macro.stderr b/tests/ui/proc-macro/span-from-proc-macro.stderr index c79ab04eadf4..945a5620fac4 100644 --- a/tests/ui/proc-macro/span-from-proc-macro.stderr +++ b/tests/ui/proc-macro/span-from-proc-macro.stderr @@ -7,7 +7,7 @@ LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> Tok LL | field: MissingType | ^^^^^^^^^^^ not found in this scope | - ::: $DIR/span-from-proc-macro.rs:8:1 + ::: $DIR/span-from-proc-macro.rs:9:1 | LL | #[error_from_attribute] | ----------------------- in this attribute macro expansion @@ -21,7 +21,7 @@ LL | pub fn error_from_derive(_input: TokenStream) -> TokenStream { LL | Variant(OtherMissingType) | ^^^^^^^^^^^^^^^^ not found in this scope | - ::: $DIR/span-from-proc-macro.rs:11:10 + ::: $DIR/span-from-proc-macro.rs:12:10 | LL | #[derive(ErrorFromDerive)] | --------------- in this derive macro expansion @@ -35,7 +35,7 @@ LL | custom_quote::custom_quote! { LL | my_ident | ^^^^^^^^ not found in this scope | - ::: $DIR/span-from-proc-macro.rs:16:5 + ::: $DIR/span-from-proc-macro.rs:17:5 | LL | other_error_from_bang!(); | ------------------------ in this macro invocation @@ -51,7 +51,7 @@ LL | let bang_error: bool = 25; LL | pub fn error_from_bang(_input: TokenStream) -> TokenStream { | ---------------------------------------------------------- in this expansion of `error_from_bang!` | - ::: $DIR/span-from-proc-macro.rs:15:5 + ::: $DIR/span-from-proc-macro.rs:16:5 | LL | error_from_bang!(); | ------------------ in this macro invocation diff --git a/tests/ui/proc-macro/weird-hygiene.rs b/tests/ui/proc-macro/weird-hygiene.rs index de55484109ae..8d8427d0e417 100644 --- a/tests/ui/proc-macro/weird-hygiene.rs +++ b/tests/ui/proc-macro/weird-hygiene.rs @@ -1,4 +1,5 @@ //@ proc-macro: weird-hygiene.rs +//@ ignore-backends: gcc #![feature(stmt_expr_attributes)] #![feature(proc_macro_hygiene)] diff --git a/tests/ui/proc-macro/weird-hygiene.stderr b/tests/ui/proc-macro/weird-hygiene.stderr index 256e68e8970e..0cfac3f89a04 100644 --- a/tests/ui/proc-macro/weird-hygiene.stderr +++ b/tests/ui/proc-macro/weird-hygiene.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `hidden_ident` in this scope - --> $DIR/weird-hygiene.rs:23:43 + --> $DIR/weird-hygiene.rs:24:43 | LL | Value = (stringify!($tokens + hidden_ident), 1).1 | ^^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | other!(50); = 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 - --> $DIR/weird-hygiene.rs:34:13 + --> $DIR/weird-hygiene.rs:35:13 | LL | hidden_ident | ^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/process/multi-panic.rs b/tests/ui/process/multi-panic.rs index 1fddffeb770a..67bbd16fba75 100644 --- a/tests/ui/process/multi-panic.rs +++ b/tests/ui/process/multi-panic.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-subprocess //@ needs-unwind +//@ ignore-backends: gcc fn check_for_no_backtrace(test: std::process::Output) { assert!(!test.status.success()); diff --git a/tests/ui/resolve/prelude-order.rs b/tests/ui/resolve/prelude-order.rs index a3f194270d48..c6683bdff22a 100644 --- a/tests/ui/resolve/prelude-order.rs +++ b/tests/ui/resolve/prelude-order.rs @@ -1,5 +1,6 @@ //@ proc-macro:macro_helpers.rs //@ compile-flags: --crate-type=lib +//@ ignore-backends: gcc /* There are 5 preludes and 3 namespaces. Test the order in which they are resolved. * See https://doc.rust-lang.org/nightly/reference/names/preludes.html. diff --git a/tests/ui/resolve/prelude-order.stderr b/tests/ui/resolve/prelude-order.stderr index 1b9cc94285aa..4dad39fb6d24 100644 --- a/tests/ui/resolve/prelude-order.stderr +++ b/tests/ui/resolve/prelude-order.stderr @@ -1,17 +1,17 @@ error[E0433]: failed to resolve: could not find `inner` in `type_ns` - --> $DIR/prelude-order.rs:61:12 + --> $DIR/prelude-order.rs:62:12 | LL | #[type_ns::inner] | ^^^^^ could not find `inner` in `type_ns` error[E0433]: failed to resolve: could not find `inner` in `usize` - --> $DIR/prelude-order.rs:73:10 + --> $DIR/prelude-order.rs:74:10 | LL | #[usize::inner] | ^^^^^ could not find `inner` in `usize` error[E0573]: expected type, found crate `Option` - --> $DIR/prelude-order.rs:79:12 + --> $DIR/prelude-order.rs:80:12 | LL | fn e2() -> Option { None } | ^^^^^^^^^^^ not a type @@ -22,7 +22,7 @@ LL + use std::option::Option; | error[E0308]: mismatched types - --> $DIR/prelude-order.rs:82:1 + --> $DIR/prelude-order.rs:83:1 | LL | #[test] | ^^^^^^^- help: try adding a return type: `-> &'static str` @@ -32,7 +32,7 @@ LL | #[test] = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/prelude-order.rs:86:1 + --> $DIR/prelude-order.rs:87:1 | LL | #[global_allocator] | ^^^^^^^^^^^^^^^^^^^- help: try adding a return type: `-> &'static str` diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs index 414d5518e1fb..2387dfb2bc57 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs @@ -7,6 +7,7 @@ //@ check-pass //@ proc-macro: count.rs +//@ ignore-backends: gcc extern crate count; const _: () = { diff --git a/tests/ui/runtime/backtrace-debuginfo.rs b/tests/ui/runtime/backtrace-debuginfo.rs index 5e91f22aec02..d3b4d057e6d0 100644 --- a/tests/ui/runtime/backtrace-debuginfo.rs +++ b/tests/ui/runtime/backtrace-debuginfo.rs @@ -19,6 +19,7 @@ // FIXME(#117097): backtrace (possibly unwinding mechanism) seems to be different on at least // `i686-mingw` (32-bit windows-gnu)? cc #128911. //@ ignore-windows-gnu +//@ ignore-backends: gcc use std::env; diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index 913d3637c8f2..3e092728f292 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -10,6 +10,7 @@ //@ ignore-tvos stack overflow handlers aren't enabled //@ ignore-watchos stack overflow handlers aren't enabled //@ ignore-visionos stack overflow handlers aren't enabled +//@ ignore-backends: gcc #![feature(rustc_private)] diff --git a/tests/ui/rust-2018/suggestions-not-always-applicable.fixed b/tests/ui/rust-2018/suggestions-not-always-applicable.fixed index e3070ba150b6..3a42434494d8 100644 --- a/tests/ui/rust-2018/suggestions-not-always-applicable.fixed +++ b/tests/ui/rust-2018/suggestions-not-always-applicable.fixed @@ -3,6 +3,7 @@ //@ run-rustfix //@ rustfix-only-machine-applicable //@ check-pass +//@ ignore-backends: gcc #![warn(rust_2018_compatibility)] diff --git a/tests/ui/rust-2018/suggestions-not-always-applicable.rs b/tests/ui/rust-2018/suggestions-not-always-applicable.rs index e3070ba150b6..3a42434494d8 100644 --- a/tests/ui/rust-2018/suggestions-not-always-applicable.rs +++ b/tests/ui/rust-2018/suggestions-not-always-applicable.rs @@ -3,6 +3,7 @@ //@ run-rustfix //@ rustfix-only-machine-applicable //@ check-pass +//@ ignore-backends: gcc #![warn(rust_2018_compatibility)] diff --git a/tests/ui/rust-2021/reserved-prefixes-via-macro.rs b/tests/ui/rust-2021/reserved-prefixes-via-macro.rs index eec1b859c203..456649f23ca6 100644 --- a/tests/ui/rust-2021/reserved-prefixes-via-macro.rs +++ b/tests/ui/rust-2021/reserved-prefixes-via-macro.rs @@ -1,6 +1,7 @@ //@ run-pass //@ edition:2021 //@ proc-macro: reserved-prefixes-macro-2018.rs +//@ ignore-backends: gcc extern crate reserved_prefixes_macro_2018 as m2018; diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs index ead2ab40b77a..ddb32c267173 100644 --- a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs +++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs @@ -1,6 +1,7 @@ //@ run-pass //@ edition:2024 //@ proc-macro: reserved-guarded-strings-macro-2021.rs +//@ ignore-backends: gcc extern crate reserved_guarded_strings_macro_2021 as m2021; diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm.rs index e2c504e708c5..8b7073649b7a 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-from-pm.rs @@ -6,6 +6,7 @@ //@[edition2021] edition:2021 //@[edition2024] edition:2024 //@ proc-macro: unsafe-attributes-pm.rs +//@ ignore-backends: gcc unsafe_attributes_pm::missing_unsafe!(); diff --git a/tests/ui/sanitizer/cfi/transparent-has-regions.rs b/tests/ui/sanitizer/cfi/transparent-has-regions.rs index b82850133c10..3e9893df23c9 100644 --- a/tests/ui/sanitizer/cfi/transparent-has-regions.rs +++ b/tests/ui/sanitizer/cfi/transparent-has-regions.rs @@ -3,6 +3,7 @@ //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ build-pass +//@ ignore-backends: gcc pub trait Trait {} diff --git a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs index be81c7bd0cac..ac2b95b63982 100644 --- a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs +++ b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs @@ -7,6 +7,7 @@ //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ build-pass +//@ ignore-backends: gcc use std::future::Future; diff --git a/tests/ui/sepcomp/sepcomp-lib-lto.rs b/tests/ui/sepcomp/sepcomp-lib-lto.rs index 2166a8fd031f..f47ea25a4fc5 100644 --- a/tests/ui/sepcomp/sepcomp-lib-lto.rs +++ b/tests/ui/sepcomp/sepcomp-lib-lto.rs @@ -5,6 +5,7 @@ //@ aux-build:sepcomp_lib.rs //@ compile-flags: -C lto -g //@ no-prefer-dynamic +//@ ignore-backends: gcc extern crate sepcomp_lib; use sepcomp_lib::a::one; diff --git a/tests/ui/sepcomp/sepcomp-unwind.rs b/tests/ui/sepcomp/sepcomp-unwind.rs index 95591676b5ee..0038e887c4ee 100644 --- a/tests/ui/sepcomp/sepcomp-unwind.rs +++ b/tests/ui/sepcomp/sepcomp-unwind.rs @@ -3,6 +3,7 @@ #![allow(dead_code)] //@ compile-flags: -C codegen-units=3 //@ needs-threads +//@ ignore-backends: gcc // Test unwinding through multiple compilation units. diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs index caec607d6fe7..d67ff6b33b79 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ ignore-backends: gcc #![feature(repr_simd, core_intrinsics)] #![allow(non_camel_case_types)] diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr index a27a8d721fb0..a2646c8e8487 100644 --- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr +++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr @@ -1,167 +1,167 @@ error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:68:9 + --> $DIR/generic-arithmetic-2.rs:69:9 | LL | simd_add(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:70:9 + --> $DIR/generic-arithmetic-2.rs:71:9 | LL | simd_sub(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:72:9 + --> $DIR/generic-arithmetic-2.rs:73:9 | LL | simd_mul(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:74:9 + --> $DIR/generic-arithmetic-2.rs:75:9 | LL | simd_div(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:76:9 + --> $DIR/generic-arithmetic-2.rs:77:9 | LL | simd_shl(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:78:9 + --> $DIR/generic-arithmetic-2.rs:79:9 | LL | simd_shr(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:80:9 + --> $DIR/generic-arithmetic-2.rs:81:9 | LL | simd_funnel_shl(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:82:9 + --> $DIR/generic-arithmetic-2.rs:83:9 | LL | simd_funnel_shr(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:84:9 + --> $DIR/generic-arithmetic-2.rs:85:9 | LL | simd_and(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:86:9 + --> $DIR/generic-arithmetic-2.rs:87:9 | LL | simd_or(0, 0); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:88:9 + --> $DIR/generic-arithmetic-2.rs:89:9 | LL | simd_xor(0, 0); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:91:9 + --> $DIR/generic-arithmetic-2.rs:92:9 | LL | simd_neg(0); | ^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:93:9 + --> $DIR/generic-arithmetic-2.rs:94:9 | LL | simd_bswap(0); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:95:9 + --> $DIR/generic-arithmetic-2.rs:96:9 | LL | simd_bitreverse(0); | ^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:97:9 + --> $DIR/generic-arithmetic-2.rs:98:9 | LL | simd_ctlz(0); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-arithmetic-2.rs:99:9 + --> $DIR/generic-arithmetic-2.rs:100:9 | LL | simd_cttz(0); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:102:9 + --> $DIR/generic-arithmetic-2.rs:103:9 | LL | simd_shl(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:104:9 + --> $DIR/generic-arithmetic-2.rs:105:9 | LL | simd_shr(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_funnel_shl` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:106:9 + --> $DIR/generic-arithmetic-2.rs:107:9 | LL | simd_funnel_shl(z, z, z); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_funnel_shr` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:108:9 + --> $DIR/generic-arithmetic-2.rs:109:9 | LL | simd_funnel_shr(z, z, z); | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:110:9 + --> $DIR/generic-arithmetic-2.rs:111:9 | LL | simd_and(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:112:9 + --> $DIR/generic-arithmetic-2.rs:113:9 | LL | simd_or(z, z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:114:9 + --> $DIR/generic-arithmetic-2.rs:115:9 | LL | simd_xor(z, z); | ^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:116:9 + --> $DIR/generic-arithmetic-2.rs:117:9 | LL | simd_bswap(z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:118:9 + --> $DIR/generic-arithmetic-2.rs:119:9 | LL | simd_bitreverse(z); | ^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:120:9 + --> $DIR/generic-arithmetic-2.rs:121:9 | LL | simd_ctlz(z); | ^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_ctpop` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:122:9 + --> $DIR/generic-arithmetic-2.rs:123:9 | LL | simd_ctpop(z); | ^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32` - --> $DIR/generic-arithmetic-2.rs:124:9 + --> $DIR/generic-arithmetic-2.rs:125:9 | LL | simd_cttz(z); | ^^^^^^^^^^^^ diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index 905299a92897..08d1e3ce944d 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ ignore-backends: gcc #![feature( repr_simd, diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr index 3779aa86cee1..a32a923633b4 100644 --- a/tests/ui/simd/intrinsic/generic-elements.stderr +++ b/tests/ui/simd/intrinsic/generic-elements.stderr @@ -1,125 +1,125 @@ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:51:9 + --> $DIR/generic-elements.rs:52:9 | LL | simd_insert(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/generic-elements.rs:53:9 + --> $DIR/generic-elements.rs:54:9 | LL | simd_insert(x, 0, 1.0); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/generic-elements.rs:55:9 + --> $DIR/generic-elements.rs:56:9 | LL | simd_extract::<_, f32>(x, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:59:9 + --> $DIR/generic-elements.rs:60:9 | LL | simd_shuffle::(0, 0, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:62:9 + --> $DIR/generic-elements.rs:63:9 | LL | simd_shuffle::(0, 0, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:65:9 + --> $DIR/generic-elements.rs:66:9 | LL | simd_shuffle::(0, 0, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:68:9 + --> $DIR/generic-elements.rs:69:9 | LL | simd_shuffle::<_, _, f32x2>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:70:9 + --> $DIR/generic-elements.rs:71:9 | LL | simd_shuffle::<_, _, f32x4>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:72:9 + --> $DIR/generic-elements.rs:73:9 | LL | simd_shuffle::<_, _, f32x8>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:75:9 + --> $DIR/generic-elements.rs:76:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:77:9 + --> $DIR/generic-elements.rs:78:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:79:9 + --> $DIR/generic-elements.rs:80:9 | LL | simd_shuffle::<_, _, i32x2>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:83:9 + --> $DIR/generic-elements.rs:84:9 | LL | simd_shuffle_const_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:86:9 + --> $DIR/generic-elements.rs:87:9 | LL | simd_shuffle_const_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:89:9 + --> $DIR/generic-elements.rs:90:9 | LL | simd_shuffle_const_generic::(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:92:9 + --> $DIR/generic-elements.rs:93:9 | LL | simd_shuffle_const_generic::<_, f32x2, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:94:9 + --> $DIR/generic-elements.rs:95:9 | LL | simd_shuffle_const_generic::<_, f32x4, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:96:9 + --> $DIR/generic-elements.rs:97:9 | LL | simd_shuffle_const_generic::<_, f32x8, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:99:9 + --> $DIR/generic-elements.rs:100:9 | LL | simd_shuffle_const_generic::<_, i32x8, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:101:9 + --> $DIR/generic-elements.rs:102:9 | LL | simd_shuffle_const_generic::<_, i32x8, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:103:9 + --> $DIR/generic-elements.rs:104:9 | LL | simd_shuffle_const_generic::<_, i32x2, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/masked-load-store-build-fail.rs b/tests/ui/simd/masked-load-store-build-fail.rs index 4b6cc17683c2..c711b6dfd977 100644 --- a/tests/ui/simd/masked-load-store-build-fail.rs +++ b/tests/ui/simd/masked-load-store-build-fail.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ ignore-backends: gcc #![feature(repr_simd, core_intrinsics)] use std::intrinsics::simd::{simd_masked_load, simd_masked_store}; diff --git a/tests/ui/simd/masked-load-store-build-fail.stderr b/tests/ui/simd/masked-load-store-build-fail.stderr index 7f09841b5971..b9158f46ea9a 100644 --- a/tests/ui/simd/masked-load-store-build-fail.stderr +++ b/tests/ui/simd/masked-load-store-build-fail.stderr @@ -1,47 +1,47 @@ error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected third argument with length 8 (same as input type `Simd`), found `Simd` with length 4 - --> $DIR/masked-load-store-build-fail.rs:15:9 + --> $DIR/masked-load-store-build-fail.rs:16:9 | LL | simd_masked_load(Simd::([-1, 0, -1, -1, 0, 0, 0, 0]), arr.as_ptr(), default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd`, found `u8` != `*_ u8` - --> $DIR/masked-load-store-build-fail.rs:18:9 + --> $DIR/masked-load-store-build-fail.rs:19:9 | LL | simd_masked_load(Simd::([-1, 0, -1, -1]), arr.as_ptr() as *const i8, default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd`, found `u32` != `*_ u32` - --> $DIR/masked-load-store-build-fail.rs:21:9 + --> $DIR/masked-load-store-build-fail.rs:22:9 | LL | simd_masked_load(Simd::([-1, 0, -1, -1]), arr.as_ptr(), Simd::([9; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected mask element type to be an integer, found `f32` - --> $DIR/masked-load-store-build-fail.rs:24:9 + --> $DIR/masked-load-store-build-fail.rs:25:9 | LL | simd_masked_load(Simd::([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd`, found `u32` != `*mut u32` - --> $DIR/masked-load-store-build-fail.rs:27:9 + --> $DIR/masked-load-store-build-fail.rs:28:9 | LL | simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u32; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd`, found `u8` != `*mut u8` - --> $DIR/masked-load-store-build-fail.rs:30:9 + --> $DIR/masked-load-store-build-fail.rs:31:9 | LL | simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u8; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected third argument with length 4 (same as input type `Simd`), found `Simd` with length 2 - --> $DIR/masked-load-store-build-fail.rs:33:9 + --> $DIR/masked-load-store-build-fail.rs:34:9 | LL | simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected mask element type to be an integer, found `f32` - --> $DIR/masked-load-store-build-fail.rs:36:9 + --> $DIR/masked-load-store-build-fail.rs:37:9 | LL | simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr index b0742bc5ef80..c82adbf8d4c5 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr +++ b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr @@ -1,5 +1,5 @@ error: overly complex generic constant - --> $DIR/monomorphize-shuffle-index.rs:36:51 + --> $DIR/monomorphize-shuffle-index.rs:37:51 | LL | return simd_shuffle_const_generic::<_, _, { &Self::I.0 }>(a, b); | ^^----------^^ diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 1490f8e2319f..ba952cdb0dc6 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -1,6 +1,7 @@ //@ revisions: old generic generic_with_fn //@[old]run-pass //@[generic_with_fn]run-pass +//@ ignore-backends: gcc #![feature( repr_simd, core_intrinsics, diff --git a/tests/ui/simd/not-out-of-bounds.rs b/tests/ui/simd/not-out-of-bounds.rs index 4bd2a69edbf5..c80c90e3ab9b 100644 --- a/tests/ui/simd/not-out-of-bounds.rs +++ b/tests/ui/simd/not-out-of-bounds.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ ignore-backends: gcc #![allow(non_camel_case_types)] #![feature(repr_simd, core_intrinsics)] diff --git a/tests/ui/simd/not-out-of-bounds.stderr b/tests/ui/simd/not-out-of-bounds.stderr index 4b6bda93e456..734c21fbf415 100644 --- a/tests/ui/simd/not-out-of-bounds.stderr +++ b/tests/ui/simd/not-out-of-bounds.stderr @@ -1,5 +1,5 @@ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | test_shuffle_lanes!(2, u8x2, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 8) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | test_shuffle_lanes!(4, u8x4, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 16) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | test_shuffle_lanes!(8, u8x8, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 32) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | test_shuffle_lanes!(16, u8x16, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 64) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | test_shuffle_lanes!(32, u8x32, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 128) - --> $DIR/not-out-of-bounds.rs:52:21 + --> $DIR/not-out-of-bounds.rs:53:21 | LL | $y(vec1, vec2, IDX) | ^^^^^^^^^^^^^^^^^^^ @@ -65,19 +65,19 @@ LL | test_shuffle_lanes!(64, u8x64, simd_shuffle); = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4) - --> $DIR/not-out-of-bounds.rs:77:23 + --> $DIR/not-out-of-bounds.rs:78:23 | LL | let _: u8x2 = simd_shuffle(v, v, I); | ^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: SIMD index #1 is out of bounds (limit 2) - --> $DIR/not-out-of-bounds.rs:83:9 + --> $DIR/not-out-of-bounds.rs:84:9 | LL | simd_insert(v, 2, 0u8); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: SIMD index #1 is out of bounds (limit 2) - --> $DIR/not-out-of-bounds.rs:84:24 + --> $DIR/not-out-of-bounds.rs:85:24 | LL | let _val: u8 = simd_extract(v, 2); | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/structs-enums/unit-like-struct-drop-run.rs b/tests/ui/structs-enums/unit-like-struct-drop-run.rs index 3d00871837cf..5e3fc5931bdc 100644 --- a/tests/ui/structs-enums/unit-like-struct-drop-run.rs +++ b/tests/ui/structs-enums/unit-like-struct-drop-run.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-unwind //@ needs-threads +//@ ignore-backends: gcc // Make sure the destructor is run for unit-like structs. diff --git a/tests/ui/suggestions/issue-61963.rs b/tests/ui/suggestions/issue-61963.rs index 77e4b21f5dbd..bf0680b98603 100644 --- a/tests/ui/suggestions/issue-61963.rs +++ b/tests/ui/suggestions/issue-61963.rs @@ -1,6 +1,7 @@ //@ edition: 2015 //@ proc-macro: issue-61963.rs //@ proc-macro: issue-61963-1.rs +//@ ignore-backends: gcc #![deny(bare_trait_objects)] #[macro_use] diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr index ffdeef12bb7f..f9146a619ec4 100644 --- a/tests/ui/suggestions/issue-61963.stderr +++ b/tests/ui/suggestions/issue-61963.stderr @@ -1,5 +1,5 @@ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-61963.rs:23:14 + --> $DIR/issue-61963.rs:24:14 | LL | bar: Box, | ^^^ @@ -7,7 +7,7 @@ LL | bar: Box, = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see note: the lint level is defined here - --> $DIR/issue-61963.rs:4:9 + --> $DIR/issue-61963.rs:5:9 | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | bar: Box, | +++ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-61963.rs:19:1 + --> $DIR/issue-61963.rs:20:1 | LL | pub struct Foo { | ^^^ diff --git a/tests/ui/suggestions/suggest-ref-macro.rs b/tests/ui/suggestions/suggest-ref-macro.rs index 2f31af33782c..41a2acf90628 100644 --- a/tests/ui/suggestions/suggest-ref-macro.rs +++ b/tests/ui/suggestions/suggest-ref-macro.rs @@ -1,5 +1,6 @@ // run-check //@ proc-macro: proc-macro-type-error.rs +//@ ignore-backends: gcc extern crate proc_macro_type_error; diff --git a/tests/ui/suggestions/suggest-ref-macro.stderr b/tests/ui/suggestions/suggest-ref-macro.stderr index 08bc9e86a50f..2a52c1e24450 100644 --- a/tests/ui/suggestions/suggest-ref-macro.stderr +++ b/tests/ui/suggestions/suggest-ref-macro.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/suggest-ref-macro.rs:8:1 + --> $DIR/suggest-ref-macro.rs:9:1 | LL | #[hello] | ^^^^^^^^ @@ -8,14 +8,14 @@ LL | #[hello] | arguments to this function are incorrect | note: function defined here - --> $DIR/suggest-ref-macro.rs:8:1 + --> $DIR/suggest-ref-macro.rs:9:1 | LL | #[hello] | ^^^^^^^^ = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types - --> $DIR/suggest-ref-macro.rs:15:11 + --> $DIR/suggest-ref-macro.rs:16:11 | LL | x(123); | - ^^^ expected `&mut i32`, found integer @@ -26,7 +26,7 @@ LL | bla!(); | ------ in this macro invocation | note: function defined here - --> $DIR/suggest-ref-macro.rs:11:4 + --> $DIR/suggest-ref-macro.rs:12:4 | LL | fn x(_: &mut i32) {} | ^ ----------- @@ -37,7 +37,7 @@ LL | x(&mut 123); | ++++ error[E0308]: mismatched types - --> $DIR/suggest-ref-macro.rs:26:10 + --> $DIR/suggest-ref-macro.rs:27:10 | LL | x($v) | - arguments to this function are incorrect @@ -46,7 +46,7 @@ LL | bla!(456); | ^^^ expected `&mut i32`, found integer | note: function defined here - --> $DIR/suggest-ref-macro.rs:11:4 + --> $DIR/suggest-ref-macro.rs:12:4 | LL | fn x(_: &mut i32) {} | ^ ----------- diff --git a/tests/ui/test-attrs/test-panic-while-printing.rs b/tests/ui/test-attrs/test-panic-while-printing.rs index a50a15fbe5af..49e8d9c7afdf 100644 --- a/tests/ui/test-attrs/test-panic-while-printing.rs +++ b/tests/ui/test-attrs/test-panic-while-printing.rs @@ -1,6 +1,7 @@ //@ compile-flags:--test //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc use std::fmt; use std::fmt::{Display, Formatter}; diff --git a/tests/ui/threads-sendsync/task-stderr.rs b/tests/ui/threads-sendsync/task-stderr.rs index 3934084e02a0..f54b5a5cc5f6 100644 --- a/tests/ui/threads-sendsync/task-stderr.rs +++ b/tests/ui/threads-sendsync/task-stderr.rs @@ -1,6 +1,7 @@ //@ run-pass //@ needs-threads //@ needs-unwind +//@ ignore-backends: gcc #![feature(internal_output_capture)] diff --git a/tests/ui/threads-sendsync/unwind-resource.rs b/tests/ui/threads-sendsync/unwind-resource.rs index ec27a1846fef..c5fbfc5bf5b0 100644 --- a/tests/ui/threads-sendsync/unwind-resource.rs +++ b/tests/ui/threads-sendsync/unwind-resource.rs @@ -3,6 +3,7 @@ #![allow(non_camel_case_types)] //@ needs-threads +//@ ignore-backends: gcc use std::sync::mpsc::{channel, Sender}; use std::thread; diff --git a/tests/ui/traits/clone-unwind-rc-cleanup.rs b/tests/ui/traits/clone-unwind-rc-cleanup.rs index cd02050ea274..dab48a1b4c6c 100644 --- a/tests/ui/traits/clone-unwind-rc-cleanup.rs +++ b/tests/ui/traits/clone-unwind-rc-cleanup.rs @@ -2,6 +2,7 @@ //@ run-pass //@ needs-unwind +//@ ignore-backends: gcc #![allow(unused_variables)] #![allow(unused_imports)] diff --git a/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.rs b/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.rs index c08030fc5c15..81c2d778b057 100644 --- a/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.rs +++ b/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.rs @@ -1,4 +1,5 @@ //@ proc-macro: derive-demo-issue-136343.rs +//@ ignore-backends: gcc #[macro_use] extern crate derive_demo_issue_136343; diff --git a/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.stderr b/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.stderr index 0b9c1d9123aa..d69eaae53355 100644 --- a/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.stderr +++ b/tests/ui/typeck/invalid-sugg-for-derive-macro-issue-136343.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/invalid-sugg-for-derive-macro-issue-136343.rs:6:10 + --> $DIR/invalid-sugg-for-derive-macro-issue-136343.rs:7:10 | LL | #[derive(Sample)] | ^^^^^^ From 1acd65cd6dffb34a2c8576ebc3874527a9f601e0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 22 Sep 2025 14:09:03 +0200 Subject: [PATCH 295/537] predefined opaques use `List` --- compiler/rustc_middle/src/arena.rs | 1 - compiler/rustc_middle/src/traits/solve.rs | 45 +------------------ compiler/rustc_middle/src/ty/context.rs | 10 ++--- .../rustc_middle/src/ty/structural_impls.rs | 1 + .../src/canonical/mod.rs | 8 ++-- .../src/solve/eval_ctxt/mod.rs | 7 ++- compiler/rustc_type_ir/src/interner.rs | 8 ++-- compiler/rustc_type_ir/src/solve/mod.rs | 13 ------ 8 files changed, 16 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fbe19c9f2d..fa6a2db38ef9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -109,7 +109,6 @@ macro_rules! arena_types { rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, - [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index ef5223de0e82..3343f2703330 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -4,7 +4,7 @@ use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; use crate::ty::{ - self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, try_visit, }; @@ -15,16 +15,7 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource>; pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput, P>; pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData>>); - -impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { - type Target = PredefinedOpaquesData>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>( @@ -93,35 +84,3 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { self.normalization_nested_goals.visit_with(visitor) } } - -// FIXME: Having to clone `region_constraints` for folding feels bad and -// probably isn't great wrt performance. -// -// Not sure how to fix this, maybe we should also intern `opaque_types` and -// `region_constraints` here or something. -impl<'tcx> TypeFoldable> for PredefinedOpaques<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(FallibleTypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, - })) - } - - fn fold_with>>(self, folder: &mut F) -> Self { - TypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { - opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), - }) - } -} - -impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> { - fn visit_with>>(&self, visitor: &mut V) -> V::Result { - self.opaque_types.visit_with(visitor) - } -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7d3e2c9965da..aa3465146451 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -74,8 +74,7 @@ use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ - self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, - PredefinedOpaquesData, QueryResult, inspect, + self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -116,7 +115,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn mk_predefined_opaques_in_body( self, - data: PredefinedOpaquesData, + data: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], ) -> Self::PredefinedOpaques { self.mk_predefined_opaques_in_body(data) } @@ -941,7 +940,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutData>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, - predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData>>, + predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -2748,8 +2747,6 @@ direct_interners! { adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, - predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData>): - PredefinedOpaques -> PredefinedOpaques<'tcx>, } macro_rules! slice_interners { @@ -2786,6 +2783,7 @@ slice_interners!( offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>), + predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 11d109b463d9..8dc4dfd677ba 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -796,6 +796,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, + &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index e3520e238ed3..b036ee6df7ec 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -25,7 +25,7 @@ use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, - NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect, + NestedNormalizationGoals, QueryInput, Response, inspect, }; pub mod canonicalizer; @@ -53,7 +53,7 @@ impl ResponseT for inspect::State { pub(super) fn canonicalize_goal( delegate: &D, goal: Goal, - opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], ) -> (Vec, CanonicalInput) where D: SolverDelegate, @@ -65,9 +65,7 @@ where &mut orig_values, QueryInput { goal, - predefined_opaques_in_body: delegate - .cx() - .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), + predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), }, ); let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() }; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index bb86357a85f8..9b32e4876075 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -357,7 +357,7 @@ where f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, ) -> R { let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input); - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { + for (key, ty) in input.predefined_opaques_in_body.iter() { let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy()); // It may be possible that two entries in the opaque type storage end up // with the same key after resolving contained inference variables. @@ -467,7 +467,7 @@ where let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, &opaque_types); let canonical_result = self.search_graph.evaluate_goal( self.cx(), canonical_goal, @@ -548,7 +548,6 @@ where .canonical .value .predefined_opaques_in_body - .opaque_types .len(), stalled_vars, sub_roots, @@ -1557,7 +1556,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, let opaque_types = delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, &opaque_types); let (canonical_result, final_revision) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cf58aec14a68..886d1a78bcbf 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,9 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; -use crate::solve::{ - CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, inspect, -}; +use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect}; use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; @@ -70,10 +68,10 @@ pub trait Interner: + Hash + Eq + TypeFoldable - + Deref>; + + SliceLike, Self::Ty)>; fn mk_predefined_opaques_in_body( self, - data: PredefinedOpaquesData, + data: &[(ty::OpaqueTypeKey, Self::Ty)], ) -> Self::PredefinedOpaques; type LocalDefIds: Copy diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 1a1606d82685..9d9a8e498478 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -109,19 +109,6 @@ pub struct QueryInput { impl Eq for QueryInput {} -/// Opaques that are defined in the inference context before a query is called. -#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -pub struct PredefinedOpaquesData { - pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, -} - -impl Eq for PredefinedOpaquesData {} - /// Possible ways the given goal can be proven. #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] pub enum CandidateSource { From b70a15f5f62f17f1bea1a0260fe629143cf55316 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 22 Sep 2025 14:26:08 +0200 Subject: [PATCH 296/537] predefined opaques to `method_autoderef_steps` --- compiler/rustc_hir_typeck/src/method/probe.rs | 49 +++++++++++++++---- compiler/rustc_middle/src/query/mod.rs | 6 +-- compiler/rustc_middle/src/traits/query.rs | 12 ++++- compiler/rustc_middle/src/ty/context.rs | 11 ++++- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4185f7f6996c..e0cd1f20080a 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -13,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::traits::{ObligationCauseCode, query}; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -30,7 +30,7 @@ use rustc_span::edit_distance::{ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::query::CanonicalTyGoal; +use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult, @@ -389,10 +389,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result>, { let mut orig_values = OriginalQueryValues::default(); - let query_input = self.canonicalize_query( - ParamEnvAnd { param_env: self.param_env, value: self_ty }, - &mut orig_values, - ); + let predefined_opaques_in_body = if self.next_trait_solver() { + self.tcx.mk_predefined_opaques_in_body_from_iter( + self.inner.borrow_mut().opaque_types().iter_opaque_types().map(|(k, v)| (k, v.ty)), + ) + } else { + ty::List::empty() + }; + let value = query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }; + let query_input = self + .canonicalize_query(ParamEnvAnd { param_env: self.param_env, value }, &mut orig_values); let steps = match mode { Mode::MethodCall => self.tcx.method_autoderef_steps(query_input), @@ -403,8 +409,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // special handling for this "trivial case" is a good idea. let infcx = &self.infcx; - let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) = + let (ParamEnvAnd { param_env: _, value }, var_values) = infcx.instantiate_canonical(span, &query_input.canonical); + let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { @@ -553,12 +560,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn method_autoderef_steps<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalTyGoal<'tcx>, + goal: CanonicalMethodAutoderefStepsGoal<'tcx>, ) -> MethodAutoderefStepsResult<'tcx> { debug!("method_autoderef_steps({:?})", goal); let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); - let ParamEnvAnd { param_env, value: self_ty } = goal; + let ParamEnvAnd { + param_env, + value: query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }, + } = goal; + for (key, ty) in predefined_opaques_in_body { + let prev = + infcx.register_hidden_type_in_storage(key, ty::OpaqueHiddenType { span: DUMMY_SP, ty }); + // It may be possible that two entries in the opaque type storage end up + // with the same key after resolving contained inference variables. + // + // We could put them in the duplicate list but don't have to. The opaques we + // encounter here are already tracked in the caller, so there's no need to + // also store them here. We'd take them out when computing the query response + // and then discard them, as they're already present in the input. + // + // Ideally we'd drop duplicate opaque type definitions when computing + // the canonical input. This is more annoying to implement and may cause a + // perf regression, so we do it inside of the query for now. + if let Some(prev) = prev { + debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); + } + } // If arbitrary self types is not enabled, we follow the chain of // `Deref`. If arbitrary self types is enabled, we instead @@ -655,7 +683,8 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); - + // Need to empty the opaque types storage before it gets dropped. + let _ = infcx.take_opaque_types(); MethodAutoderefStepsResult { steps: tcx.arena.alloc_from_iter(steps), opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0e645a3aae45..326df9239aa0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -124,7 +124,7 @@ use crate::query::plumbing::{ }; use crate::traits::query::{ CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal, - CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound, @@ -2559,9 +2559,9 @@ rustc_queries! { } query method_autoderef_steps( - goal: CanonicalTyGoal<'tcx> + goal: CanonicalMethodAutoderefStepsGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { - desc { "computing autoderef types for `{}`", goal.canonical.value.value } + desc { "computing autoderef types for `{}`", goal.canonical.value.value.self_ty } } /// Used by `-Znext-solver` to compute proof trees. diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 3f6faa1a572d..c1b7c9b9b4e2 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -10,6 +10,7 @@ use rustc_span::Span; use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, CanonicalQueryInput, QueryResponse}; +use crate::traits::solve; pub use crate::traits::solve::NoSolution; use crate::ty::{self, GenericArg, Ty, TyCtxt}; @@ -67,7 +68,16 @@ pub mod type_op { pub type CanonicalAliasGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; -pub type CanonicalTyGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; +pub type CanonicalMethodAutoderefStepsGoal<'tcx> = + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>; +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] +pub struct MethodAutoderefSteps<'tcx> { + /// The list of opaque types currently in the storage. + /// + /// Only used by the new solver for now. + pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, + pub self_ty: Ty<'tcx>, +} pub type CanonicalPredicateGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aa3465146451..a42af7bb3e3f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -74,7 +74,8 @@ use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ - self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, QueryResult, inspect, + self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, + QueryResult, inspect, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -3127,6 +3128,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs)) } + pub fn mk_predefined_opaques_in_body_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>), PredefinedOpaques<'tcx>>, + { + T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) + } + pub fn mk_clauses_from_iter(self, iter: I) -> T::Output where I: Iterator, From 70f6493f261810b07d69ab0ffb661cf4ed8a97a7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 15:25:35 +0200 Subject: [PATCH 297/537] remove unnecessary structurally resolve `autoderef` already resolved and `method_autoderef_steps` makes sure we won't encounter an inference variable --- compiler/rustc_hir_typeck/src/method/confirm.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index a23910a2006c..b23e7ae8e77b 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty); - let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { + let Some((mut target, n)) = autoderef.nth(pick.autoderefs) else { return Ty::new_error_with_message( self.tcx, DUMMY_SP, @@ -182,8 +182,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert_eq!(n, pick.autoderefs); let mut adjustments = self.adjust_steps(&autoderef); - let mut target = self.structurally_resolve_type(autoderef.span(), ty); - match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span)); From 6b379b560df483307958f2a606a1dd514fff36ca Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 15:32:25 +0200 Subject: [PATCH 298/537] use `try_structurally_resolve_type` for method receiver We'll still error due to the `opt_bad_ty` of `method_autoderef_steps`. This slightly worsens the span of `infer_var.method()` which is now the same as for `Box::new(infer_var).method()`. Unlike `structurally_resolve_type`, `probe_op` does not check whether the infcx is already tainted, so this results in 2 previously not emitted errors. --- compiler/rustc_hir_typeck/src/expr.rs | 3 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 2 ++ .../obligation-with-leaking-placeholders.next.stderr | 2 +- .../ui/impl-trait/call_method_ambiguous.next.stderr | 2 +- .../call_method_on_inherent_impl.next.stderr | 2 +- .../call_method_on_inherent_impl_ref.next.stderr | 2 +- .../hidden-type-is-opaque-2.default.stderr | 4 ++-- .../impl-trait/hidden-type-is-opaque-2.next.stderr | 4 ++-- tests/ui/impl-trait/method-resolution4.next.stderr | 4 ++-- tests/ui/impl-trait/recursive-bound-eval.next.stderr | 4 ++-- .../incompat-call-after-qualified-path-0.stderr | 2 +- .../incompat-call-after-qualified-path-1.stderr | 2 +- tests/ui/issues/issue-2151.stderr | 2 +- tests/ui/lazy-type-alias-impl-trait/branches3.stderr | 8 ++++---- tests/ui/proc-macro/quote/not-repeatable.rs | 4 +++- tests/ui/proc-macro/quote/not-repeatable.stderr | 11 +++++++++-- .../copy-inference-side-effects-are-lazy.stderr | 4 ++-- .../ui/span/issue-42234-unknown-receiver-type.stderr | 4 +++- .../closures_in_branches.stderr | 4 ++-- ...d_resolution_trait_method_from_opaque.next.stderr | 4 ++-- .../ui/type-inference/regression-issue-81317.stderr | 2 +- tests/ui/typeck/issue-13853.rs | 2 +- tests/ui/typeck/issue-13853.stderr | 12 +++++++++--- 23 files changed, 54 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7adbee7ff285..d1ce0afddf91 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1633,8 +1633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let rcvr_t = self.check_expr(rcvr); - // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); + let rcvr_t = self.try_structurally_resolve_type(rcvr.span, rcvr_t); match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) { Ok(method) => { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e0cd1f20080a..3311c1410554 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -486,6 +486,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(_)) => { let raw_ptr_call = bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types(); + // FIXME: Ideally we'd use the span of the self-expr here, + // not of the method path. let mut err = self.err_ctxt().emit_inference_failure_err( self.body_id, span, diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr index 3d667f12371a..4bb9047b3035 100644 --- a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr @@ -5,7 +5,7 @@ LL | needs_foo(|x| { | ^ ... LL | x.to_string(); - | - type must be known at this point + | --------- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr index 5251555f5742..0def594daf1c 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -5,7 +5,7 @@ LL | let mut iter = foo(n - 1, m); | ^^^^^^^^ LL | LL | assert_eq!(iter.get(), 1); - | ---- type must be known at this point + | --- type must be known at this point | help: consider giving `iter` an explicit type | diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr index 271051f120ab..7bbf5f5153a5 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr @@ -5,7 +5,7 @@ LL | let x = my_foo(); | ^ LL | LL | x.my_debug(); - | - type must be known at this point + | -------- type must be known at this point | help: consider giving `x` an explicit type | diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr index 7202cb6f90a6..5dea3a715e9b 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr @@ -5,7 +5,7 @@ LL | let x = my_foo(); | ^ LL | LL | x.my_debug(); - | - type must be known at this point + | -------- type must be known at this point | help: consider giving `x` an explicit type | diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr index dca0a7b0a1a9..cb383b2db389 100644 --- a/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr @@ -5,7 +5,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | ---- type must be known at this point + | -------- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -19,7 +19,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | ---- type must be known at this point + | -------- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr index dca0a7b0a1a9..cb383b2db389 100644 --- a/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr @@ -5,7 +5,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | ---- type must be known at this point + | -------- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -19,7 +19,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | ---- type must be known at this point + | -------- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/impl-trait/method-resolution4.next.stderr b/tests/ui/impl-trait/method-resolution4.next.stderr index 0524f49f98e5..47a9aac19ecc 100644 --- a/tests/ui/impl-trait/method-resolution4.next.stderr +++ b/tests/ui/impl-trait/method-resolution4.next.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/method-resolution4.rs:13:9 + --> $DIR/method-resolution4.rs:13:20 | LL | foo(false).next().unwrap(); - | ^^^^^^^^^^ cannot infer type + | ^^^^ cannot infer type error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/recursive-bound-eval.next.stderr b/tests/ui/impl-trait/recursive-bound-eval.next.stderr index 4bab290d71c3..e94f0a59a1d2 100644 --- a/tests/ui/impl-trait/recursive-bound-eval.next.stderr +++ b/tests/ui/impl-trait/recursive-bound-eval.next.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/recursive-bound-eval.rs:20:13 + --> $DIR/recursive-bound-eval.rs:20:28 | LL | move || recursive_fn().parse() - | ^^^^^^^^^^^^^^ cannot infer type + | ^^^^^ cannot infer type error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr index 10056bdf3d4f..ba1c81c4518a 100644 --- a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr +++ b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/incompat-call-after-qualified-path-0.rs:21:6 | LL | f(|a, b| a.cmp(b)); - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr index 632a9b99f84e..93bba3625b54 100644 --- a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr +++ b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/incompat-call-after-qualified-path-1.rs:25:6 | LL | f(|a, b| a.cmp(b)); - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/issues/issue-2151.stderr b/tests/ui/issues/issue-2151.stderr index b130f162414d..59fef42eb5e8 100644 --- a/tests/ui/issues/issue-2151.stderr +++ b/tests/ui/issues/issue-2151.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x = panic!(); | ^ LL | x.clone(); - | - type must be known at this point + | ----- type must be known at this point | help: consider giving `x` an explicit type | diff --git a/tests/ui/lazy-type-alias-impl-trait/branches3.stderr b/tests/ui/lazy-type-alias-impl-trait/branches3.stderr index 117d189867bd..539673bc343c 100644 --- a/tests/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/tests/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:9:10 | LL | |s| s.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -13,7 +13,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:18:10 | LL | |s| s.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -24,7 +24,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:26:10 | LL | |s| s.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -35,7 +35,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:33:10 | LL | |s| s.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/proc-macro/quote/not-repeatable.rs b/tests/ui/proc-macro/quote/not-repeatable.rs index 0291e4ddf88d..373f0e74dbda 100644 --- a/tests/ui/proc-macro/quote/not-repeatable.rs +++ b/tests/ui/proc-macro/quote/not-repeatable.rs @@ -8,5 +8,7 @@ struct Ipv4Addr; fn main() { let ip = Ipv4Addr; - let _ = quote! { $($ip)* }; //~ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied + let _ = quote! { $($ip)* }; + //~^ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied + //~| ERROR type annotations needed } diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr index aeda08d7de68..ff31799abb00 100644 --- a/tests/ui/proc-macro/quote/not-repeatable.stderr +++ b/tests/ui/proc-macro/quote/not-repeatable.stderr @@ -20,6 +20,13 @@ note: the traits `Iterator` and `ToTokens` must be implemented --> $SRC_DIR/proc_macro/src/to_tokens.rs:LL:COL --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error: aborting due to 1 previous error +error[E0282]: type annotations needed + --> $DIR/not-repeatable.rs:11:13 + | +LL | let _ = quote! { $($ip)* }; + | ^^^^^^^^^^^^^^^^^^ cannot infer type -For more information about this error, try `rustc --explain E0599`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0599. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr index ba44beb76dbb..b8a8f927542f 100644 --- a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr +++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr @@ -5,9 +5,9 @@ LL | let x = [Foo(PhantomData); 2]; | ^ LL | LL | extract(x).max(2); - | ---------- type must be known at this point + | --- type must be known at this point | -help: consider giving `x` an explicit type, where the type for type parameter `T` is specified +help: consider giving `x` an explicit type, where the placeholders `_` are specified | LL | let x: [Foo; 2] = [Foo(PhantomData); 2]; | +++++++++++++ diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.stderr index 10308ec07da5..71ac4f53b3f4 100644 --- a/tests/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/tests/ui/span/issue-42234-unknown-receiver-type.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x: Option<_> = None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` LL | x.unwrap().method_that_could_exist_on_some_type(); - | ---------- type must be known at this point + | ------------------------------------ type must be known at this point | help: consider specifying the generic argument | @@ -16,6 +16,8 @@ error[E0282]: type annotations needed | LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the method `sum` +LL | .to_string() + | --------- type must be known at this point | error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/closures_in_branches.stderr b/tests/ui/type-alias-impl-trait/closures_in_branches.stderr index 849ffd214f07..559bc57d9063 100644 --- a/tests/ui/type-alias-impl-trait/closures_in_branches.stderr +++ b/tests/ui/type-alias-impl-trait/closures_in_branches.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:8:10 | LL | |x| x.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -13,7 +13,7 @@ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:22:10 | LL | |x| x.len() - | ^ - type must be known at this point + | ^ --- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr index bbdd3923821f..5aae334ccbd2 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/method_resolution_trait_method_from_opaque.rs:28:9 + --> $DIR/method_resolution_trait_method_from_opaque.rs:28:18 | LL | self.bar.next().unwrap(); - | ^^^^^^^^ cannot infer type + | ^^^^ cannot infer type error: aborting due to 1 previous error diff --git a/tests/ui/type-inference/regression-issue-81317.stderr b/tests/ui/type-inference/regression-issue-81317.stderr index fcd3fca06e18..a070b50e3117 100644 --- a/tests/ui/type-inference/regression-issue-81317.stderr +++ b/tests/ui/type-inference/regression-issue-81317.stderr @@ -5,7 +5,7 @@ LL | let iv = S ^ index.into(); | ^^ LL | LL | &iv.to_bytes_be(); - | -- type must be known at this point + | ----------- type must be known at this point | help: consider giving `iv` an explicit type | diff --git a/tests/ui/typeck/issue-13853.rs b/tests/ui/typeck/issue-13853.rs index ac9886d2e724..ed44d5062614 100644 --- a/tests/ui/typeck/issue-13853.rs +++ b/tests/ui/typeck/issue-13853.rs @@ -25,7 +25,7 @@ impl Node for Stuff { fn iterate>(graph: &G) { for node in graph.iter() { //~ ERROR no method named `iter` found - node.zomg(); + node.zomg(); //~ ERROR type annotations needed } } diff --git a/tests/ui/typeck/issue-13853.stderr b/tests/ui/typeck/issue-13853.stderr index 45363c87d29d..9b8698d6ed2c 100644 --- a/tests/ui/typeck/issue-13853.stderr +++ b/tests/ui/typeck/issue-13853.stderr @@ -17,6 +17,12 @@ error[E0599]: no method named `iter` found for reference `&G` in the current sco LL | for node in graph.iter() { | ^^^^ method not found in `&G` +error[E0282]: type annotations needed + --> $DIR/issue-13853.rs:28:14 + | +LL | node.zomg(); + | ^^^^ cannot infer type + error[E0308]: mismatched types --> $DIR/issue-13853.rs:37:13 | @@ -37,7 +43,7 @@ help: consider borrowing here LL | iterate(&graph); | + -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0599. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308, E0599. +For more information about an error, try `rustc --explain E0282`. From 148fd9ad3c434c26a952e01e37c35aa26cb8315c Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 17:33:24 +0200 Subject: [PATCH 299/537] allow method calls on opaques --- compiler/rustc_hir_typeck/src/method/probe.rs | 209 +++++++++++++++--- .../src/infer/canonical/query_response.rs | 23 +- compiler/rustc_middle/src/traits/query.rs | 1 + .../src/solve/eval_ctxt/mod.rs | 3 +- .../rustc_next_trait_solver/src/solve/mod.rs | 1 + .../src/traits/query/evaluate_obligation.rs | 11 +- .../call_method_ambiguous.next.stderr | 17 -- tests/ui/impl-trait/call_method_ambiguous.rs | 3 +- .../call_method_on_inherent_impl.next.stderr | 17 -- .../call_method_on_inherent_impl.rs | 3 +- ...inherent_impl_on_rigid_type.current.stderr | 2 +- ...on_inherent_impl_on_rigid_type.next.stderr | 18 +- ...l_method_on_inherent_impl_on_rigid_type.rs | 3 +- ...d_on_inherent_impl_ref-err.current.stderr} | 4 +- ...ethod_on_inherent_impl_ref-err.next.stderr | 19 ++ .../call_method_on_inherent_impl_ref-err.rs | 24 ++ ...=> call_method_on_inherent_impl_ref-ok.rs} | 12 +- ...ll_method_on_inherent_impl_ref.next.stderr | 31 --- .../impl-trait/method-resolution4.next.stderr | 9 - tests/ui/impl-trait/method-resolution4.rs | 3 +- ...olution5-deref-no-constrain.current.stderr | 19 ++ .../method-resolution5-deref-no-constrain.rs | 23 ++ .../ui/impl-trait/method-resolution5-deref.rs | 30 +++ .../recursive-bound-eval.next.stderr | 9 - tests/ui/impl-trait/recursive-bound-eval.rs | 6 +- .../recursive-coroutine-boxed.next.stderr | 17 -- .../impl-trait/recursive-coroutine-boxed.rs | 3 +- ...ution_trait_method_from_opaque.next.stderr | 8 +- 28 files changed, 357 insertions(+), 171 deletions(-) delete mode 100644 tests/ui/impl-trait/call_method_ambiguous.next.stderr delete mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr rename tests/ui/impl-trait/{call_method_on_inherent_impl_ref.current.stderr => call_method_on_inherent_impl_ref-err.current.stderr} (84%) create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr create mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs rename tests/ui/impl-trait/{call_method_on_inherent_impl_ref.rs => call_method_on_inherent_impl_ref-ok.rs} (54%) delete mode 100644 tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr delete mode 100644 tests/ui/impl-trait/method-resolution4.next.stderr create mode 100644 tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr create mode 100644 tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs create mode 100644 tests/ui/impl-trait/method-resolution5-deref.rs delete mode 100644 tests/ui/impl-trait/recursive-bound-eval.next.stderr delete mode 100644 tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3311c1410554..e34ee6258b85 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -13,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCauseCode, query}; +use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query}; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -30,6 +30,7 @@ use rustc_span::edit_distance::{ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::solve::Goal; use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::{ @@ -417,6 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { self_ty: self .make_query_response_ignoring_pending_obligations(var_values, self_ty), + self_ty_is_opaque: false, autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -590,6 +592,17 @@ pub(crate) fn method_autoderef_steps<'tcx>( } } + // We accept not-yet-defined opaque types in the autoderef + // chain to support recursive calls. We do error if the final + // infer var is not an opaque. + let self_ty_is_opaque = |ty: Ty<'_>| { + if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + infcx.has_opaques_with_sub_unified_hidden_type(vid) + } else { + false + } + }; + // If arbitrary self types is not enabled, we follow the chain of // `Deref`. If arbitrary self types is enabled, we instead // follow the chain of `Receiver`, but we also record whether @@ -623,6 +636,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( let step = CandidateStep { self_ty: infcx .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -643,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( let step = CandidateStep { self_ty: infcx .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -659,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; let final_ty = autoderef_via_deref.final_ty(); let opt_bad_ty = match final_ty.kind() { - ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { + ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy { + reached_raw_pointer, + ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + }), + ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), }), @@ -670,6 +689,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( inference_vars, Ty::new_slice(infcx.tcx, *elem_ty), ), + self_ty_is_opaque: false, autoderefs, // this could be from an unsafe deref if we had // a *mut/const [T; N] @@ -1234,7 +1254,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { !step.self_ty.value.references_error() && !step.from_unsafe_deref }) .find_map(|step| { - let InferOk { value: self_ty, obligations: _ } = self + let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self .fcx .probe_instantiate_query_response( self.span, @@ -1245,7 +1265,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty) }); - let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints); + let by_value_pick = self.pick_by_value_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ); // Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing) if let Some(by_value_pick) = by_value_pick { @@ -1256,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { by_value_pick, step, self_ty, + &instantiate_self_ty_obligations, mutbl, track_unstable_candidates, ) { @@ -1270,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let autoref_pick = self.pick_autorefd_method( step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Not, pick_diag_hints, None, @@ -1283,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { autoref_pick, step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Mut, track_unstable_candidates, ) { @@ -1319,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.pick_autorefd_method( step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Mut, pick_diag_hints, None, ) - .or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints)) - .or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints)) + .or_else(|| { + self.pick_const_ptr_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ) + }) + .or_else(|| { + self.pick_reborrow_pin_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ) + }) }) } @@ -1348,6 +1391,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { possible_shadower: &Pick<'tcx>, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], mutbl: hir::Mutability, track_unstable_candidates: bool, ) -> Result<(), MethodError<'tcx>> { @@ -1412,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let potentially_shadowed_pick = self.pick_autorefd_method( step, self_ty, + instantiate_self_ty_obligations, mutbl, &mut pick_diag_hints, Some(&pick_constraints), @@ -1438,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option> { if step.unsize { return None; } - self.pick_method(self_ty, pick_diag_hints, None).map(|r| { + self.pick_method(self_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; @@ -1481,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], mutbl: hir::Mutability, pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, @@ -1497,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let region = tcx.lifetimes.re_erased; let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl); - self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| { + self.pick_method( + autoref_ty, + instantiate_self_ty_obligations, + pick_diag_hints, + pick_constraints, + ) + .map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref_or_ptr_adjustment = @@ -1513,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option> { if !self.tcx.features().pin_ergonomics() { @@ -1534,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let region = self.tcx.lifetimes.re_erased; let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not); - self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| { - r.map(|mut pick| { - pick.autoderefs = step.autoderefs; - pick.autoref_or_ptr_adjustment = - Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); - pick - }) - }) + self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map( + |r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); + pick + }) + }, + ) } /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a @@ -1551,6 +1607,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option> { // Don't convert an unsized reference to ptr @@ -1563,18 +1620,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty); - self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| { - r.map(|mut pick| { - pick.autoderefs = step.autoderefs; - pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); - pick - }) - }) + self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map( + |r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); + pick + }) + }, + ) } fn pick_method( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, ) -> Option> { @@ -1584,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] { debug!("searching {} candidates", kind); - let res = - self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints); + let res = self.consider_candidates( + self_ty, + instantiate_self_ty_obligations, + candidates, + pick_diag_hints, + pick_constraints, + ); if let Some(pick) = res { return Some(pick); } @@ -1594,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.private_candidate.get().is_none() { if let Some(Ok(pick)) = self.consider_candidates( self_ty, + instantiate_self_ty_obligations, &self.private_candidates, &mut PickDiagHints { unstable_candidates: None, @@ -1610,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn consider_candidates( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], candidates: &[Candidate<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, @@ -1626,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { probe, self.consider_probe( self_ty, + instantiate_self_ty_obligations, probe, &mut pick_diag_hints.unsatisfied_predicates, ), @@ -1810,10 +1878,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - #[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)] + #[instrument(level = "debug", skip(self, possibly_unsatisfied_predicates), ret)] fn consider_probe( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], probe: &Candidate<'tcx>, possibly_unsatisfied_predicates: &mut Vec<( ty::Predicate<'tcx>, @@ -1821,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Option>, )>, ) -> ProbeResult { - debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); - self.probe(|snapshot| { let outer_universe = self.universe(); @@ -1830,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let cause = &self.misc(self.span); let ocx = ObligationCtxt::new_with_diagnostics(self); + // Subtle: we're not *really* instantiating the current self type while + // probing, but instead fully recompute the autoderef steps once we've got + // a final `Pick`. We can't nicely handle these obligations outside of a probe. + // + // We simply handle them for each candidate here for now. That's kinda scuffed + // and ideally we just put them into the `FnCtxt` right away. We need to consider + // them to deal with defining uses in `method_autoderef_steps`. + if self.next_trait_solver() { + ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned()); + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + unreachable!("unexpected autoderef error {errors:?}"); + } + } + let mut trait_predicate = None; let (mut xform_self_ty, mut xform_ret_ty); @@ -2072,6 +2154,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + if self.infcx.next_trait_solver() { + if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) { + result = ProbeResult::NoMatch; + } + } + // Previously, method probe used `evaluate_predicate` to determine if a predicate // was impossible to satisfy. This did a leak check, so we must also do a leak // check here to prevent backwards-incompatible ambiguity being introduced. See @@ -2085,6 +2173,71 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }) } + /// Trait candidates for not-yet-defined opaque types are a somewhat hacky. + /// + /// We want to only accept trait methods if they were hold even if the + /// opaque types were rigid. To handle this, we both check that for trait + /// candidates the goal were to hold even when treating opaques as rigid, + /// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank). + /// + /// We also check that all opaque types encountered as self types in the + /// autoderef chain don't get constrained when applying the candidate. + /// Importantly, this also handles calling methods taking `&self` on + /// `impl Trait` to reject the "by-self" candidate. + /// + /// This needs to happen at the end of `consider_probe` as we need to take + /// all the constraints from that into account. + #[instrument(level = "debug", skip(self), ret)] + fn should_reject_candidate_due_to_opaque_treated_as_rigid( + &self, + trait_predicate: Option>, + ) -> bool { + // Check whether the trait candidate would not be applicable if the + // opaque type were rigid. + if let Some(predicate) = trait_predicate { + let goal = Goal { param_env: self.param_env, predicate }; + if !self.infcx.goal_may_hold_opaque_types_jank(goal) { + return true; + } + } + + // Check whether any opaque types in the autoderef chain have been + // constrained. + for step in self.steps { + if step.self_ty_is_opaque { + debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); + let constrained_opaque = self.probe(|_| { + // If we fail to instantiate the self type of this + // step, this part of the deref-chain is no longer + // reachable. In this case we don't care about opaque + // types there. + let Ok(ok) = self.fcx.probe_instantiate_query_response( + self.span, + self.orig_steps_var_values, + &step.self_ty, + ) else { + debug!("failed to instantiate self_ty"); + return false; + }; + let ocx = ObligationCtxt::new(self); + let self_ty = ocx.register_infer_ok_obligations(ok); + if !ocx.select_where_possible().is_empty() { + debug!("failed to prove instantiate self_ty obligations"); + return false; + } + + !self.resolve_vars_if_possible(self_ty).is_ty_var() + }); + if constrained_opaque { + debug!("opaque type has been constrained"); + return true; + } + } + } + + false + } + /// Sometimes we get in a situation where we have multiple probes that are all impls of the /// same trait, but we don't know which impl to use. In this case, since in all cases the /// external interface of the method can be determined from the trait, it's ok not to decide. diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5d1b4be9e57b..a20cd31113ab 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -85,11 +85,32 @@ impl<'tcx> InferCtxt<'tcx> { where T: Debug + TypeFoldable>, { + // While we ignore region constraints and pending obligations, + // we do return constrained opaque types to avoid unconstrained + // inference variables in the response. This is still slightly + // insufficient as ambiguous `Projection` obligations have the + // same issue. + // + // FIXME(-Znext-solver): We could alternatively extend the `var_values` + // each time we call `make_query_response_ignoring_pending_obligations` + // and equate inference variables created inside of the query this way. + // This is what we do for `CanonicalState` and is probably a bit nicer. + let opaque_types = if self.next_trait_solver() { + self.inner + .borrow_mut() + .opaque_type_storage + .iter_opaque_types() + .map(|(k, v)| (k, v.ty)) + .collect() + } else { + vec![] + }; + self.canonicalize_response(QueryResponse { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, // Ambiguities are OK! - opaque_types: vec![], + opaque_types, value: answer, }) } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index c1b7c9b9b4e2..c5cd7c54e4e8 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -154,6 +154,7 @@ impl<'tcx> FromIterator> for DropckConstraint<'tcx> { #[derive(Debug, HashStable)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + pub self_ty_is_opaque: bool, pub autoderefs: usize, /// `true` if the type results from a dereference of a raw pointer. /// when assembling candidates, we include these steps, but not when diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 9b32e4876075..85110530ae9b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -194,7 +194,7 @@ where D: SolverDelegate, I: Interner, { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn evaluate_root_goal( &self, goal: Goal, @@ -206,6 +206,7 @@ where }) } + #[instrument(level = "debug", skip(self), ret)] fn root_goal_may_hold_opaque_types_jank( &self, goal: Goal::Predicate>, diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index afb86aaf8ab2..a58caeecc33c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -381,6 +381,7 @@ where } /// The result of evaluating a goal. +#[derive_where(Debug; I: Interner)] pub struct GoalEvaluation { /// The goal we've evaluated. This is the input goal, but potentially with its /// inference variables resolved. This never applies any inference constraints diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index ae731505abfa..34e0176d213f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,6 +1,6 @@ use rustc_infer::traits::solve::Goal; use rustc_macros::extension; -use rustc_middle::span_bug; +use rustc_middle::{span_bug, ty}; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use crate::infer::InferCtxt; @@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> { /// for more details. fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool { if self.next_trait_solver() { - <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new( + self.goal_may_hold_opaque_types_jank(Goal::new( self.tcx, obligation.param_env, obligation.predicate, @@ -32,6 +32,13 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank) + /// for more details. + fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> bool { + assert!(self.next_trait_solver()); + <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(goal) + } + /// Evaluates whether the predicate can be satisfied in the given /// `ParamEnv`, and returns `false` if not certain. However, this is /// not entirely accurate if inference variables are involved. diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr deleted file mode 100644 index 0def594daf1c..000000000000 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/call_method_ambiguous.rs:26:13 - | -LL | let mut iter = foo(n - 1, m); - | ^^^^^^^^ -LL | -LL | assert_eq!(iter.get(), 1); - | --- type must be known at this point - | -help: consider giving `iter` an explicit type - | -LL | let mut iter: /* Type */ = foo(n - 1, m); - | ++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index 6bcafc8ce149..021d6c22f79d 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -1,6 +1,6 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[current] run-pass +//@ run-pass trait Get { fn get(&mut self) -> u32; @@ -24,7 +24,6 @@ where fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> { if n > 0 { let mut iter = foo(n - 1, m); - //[next]~^ ERROR type annotations needed assert_eq!(iter.get(), 1); } m diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr deleted file mode 100644 index 7bbf5f5153a5..000000000000 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/call_method_on_inherent_impl.rs:18:13 - | -LL | let x = my_foo(); - | ^ -LL | -LL | x.my_debug(); - | -------- type must be known at this point - | -help: consider giving `x` an explicit type - | -LL | let x: /* Type */ = my_foo(); - | ++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.rs b/tests/ui/impl-trait/call_method_on_inherent_impl.rs index 0e333c3260a2..1dd38bc67173 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.rs @@ -1,6 +1,6 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[current] check-pass +//@ check-pass trait MyDebug { fn my_debug(&self); @@ -16,7 +16,6 @@ where fn my_foo() -> impl std::fmt::Debug { if false { let x = my_foo(); - //[next]~^ ERROR type annotations needed x.my_debug(); } () diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr index 6ecb2b05fc56..e71046644704 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope - --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11 + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11 | LL | x.my_debug(); | ^^^^^^^^ method not found in `&impl Debug` diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr index 5fb0b8f1d14b..de808259d40d 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr @@ -1,17 +1,15 @@ -error[E0282]: type annotations needed for `&_` - --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13 +error[E0599]: no method named `my_debug` found for reference `&_` in the current scope + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11 | -LL | let x = &my_foo(); - | ^ -LL | LL | x.my_debug(); - | -------- type must be known at this point + | ^^^^^^^^ method not found in `&_` | -help: consider giving `x` an explicit type, where the placeholders `_` are specified + = help: items from traits can only be used if the trait is implemented and in scope +help: trait `MyDebug` which provides `my_debug` is implemented but not in scope; perhaps you want to import it + | +LL + use MyDebug; | -LL | let x: &_ = &my_foo(); - | ++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs index 7fb2ff3b2bcc..0c9909efa1ba 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs @@ -12,9 +12,8 @@ impl MyDebug for &() { fn my_foo() -> impl std::fmt::Debug { if false { let x = &my_foo(); - //[next]~^ ERROR: type annotations needed x.my_debug(); - //[current]~^ ERROR: no method named `my_debug` + //~^ ERROR: no method named `my_debug` } () } diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr similarity index 84% rename from tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr rename to tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr index fb51bb7b4173..71acbd1497d9 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope - --> $DIR/call_method_on_inherent_impl_ref.rs:19:11 + --> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11 | LL | fn my_debug(&self); | -------- the method is available for `&impl Debug` here @@ -9,7 +9,7 @@ LL | x.my_debug(); | = help: items from traits can only be used if the trait is implemented and in scope note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it - --> $DIR/call_method_on_inherent_impl_ref.rs:4:1 + --> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1 | LL | trait MyDebug { | ^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr new file mode 100644 index 000000000000..523505e98022 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr @@ -0,0 +1,19 @@ +error[E0599]: no method named `my_debug` found for type `_` in the current scope + --> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11 + | +LL | fn my_debug(&self); + | -------- the method is available for `&_` here +... +LL | x.my_debug(); + | ^^^^^^^^ method not found in `_` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it + --> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1 + | +LL | trait MyDebug { + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs new file mode 100644 index 000000000000..0ed09bc76a41 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for &T +where + T: std::fmt::Debug, +{ + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + if false { + let x = my_foo(); + x.my_debug(); + //~^ ERROR no method named `my_debug` found + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-ok.rs similarity index 54% rename from tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs rename to tests/ui/impl-trait/call_method_on_inherent_impl_ref-ok.rs index 4e4098b37f93..40739d6a0ce4 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-ok.rs @@ -1,5 +1,6 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver +//@ check-pass trait MyDebug { fn my_debug(&self); @@ -12,20 +13,9 @@ where fn my_debug(&self) {} } -fn my_foo() -> impl std::fmt::Debug { - if false { - let x = my_foo(); - //[next]~^ ERROR type annotations needed - x.my_debug(); - //[current]~^ ERROR no method named `my_debug` found - } - () -} - fn my_bar() -> impl std::fmt::Debug { if false { let x = &my_bar(); - //[next]~^ ERROR type annotations needed x.my_debug(); } () diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr deleted file mode 100644 index 5dea3a715e9b..000000000000 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/call_method_on_inherent_impl_ref.rs:17:13 - | -LL | let x = my_foo(); - | ^ -LL | -LL | x.my_debug(); - | -------- type must be known at this point - | -help: consider giving `x` an explicit type - | -LL | let x: /* Type */ = my_foo(); - | ++++++++++++ - -error[E0282]: type annotations needed for `&_` - --> $DIR/call_method_on_inherent_impl_ref.rs:27:13 - | -LL | let x = &my_bar(); - | ^ -LL | -LL | x.my_debug(); - | -------- type must be known at this point - | -help: consider giving `x` an explicit type, where the placeholders `_` are specified - | -LL | let x: &_ = &my_bar(); - | ++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/method-resolution4.next.stderr b/tests/ui/impl-trait/method-resolution4.next.stderr deleted file mode 100644 index 47a9aac19ecc..000000000000 --- a/tests/ui/impl-trait/method-resolution4.next.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/method-resolution4.rs:13:20 - | -LL | foo(false).next().unwrap(); - | ^^^^ cannot infer type - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs index 90e7850cad51..f90a9309cdab 100644 --- a/tests/ui/impl-trait/method-resolution4.rs +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -6,12 +6,11 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[current] check-pass +//@ check-pass fn foo(b: bool) -> impl Iterator { if b { foo(false).next().unwrap(); - //[next]~^ ERROR type annotations needed } std::iter::empty() } diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr new file mode 100644 index 000000000000..08578de426ad --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/method-resolution5-deref-no-constrain.rs:20:5 + | +LL | fn via_deref() -> impl Deref { + | --- expected `&Foo` because of return type +... +LL | Box::new(Foo) + | ^^^^^^^^^^^^^ expected `&Foo`, found `Box` + | + = note: expected reference `&Foo` + found struct `Box` +help: consider borrowing here + | +LL | &Box::new(Foo) + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs new file mode 100644 index 000000000000..2c41f62b9fda --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs @@ -0,0 +1,23 @@ +//! The recursive method call yields the opaque type. We want +//! to use the impl candidate for `Foo` here without constraining +//! the opaque to `&Foo`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +use std::ops::Deref; +struct Foo; +impl Foo { + fn method(&self) {} +} +fn via_deref() -> impl Deref { + // Currently errors on stable, but should not + if false { + via_deref().method(); + } + + Box::new(Foo) + //[current]~^ ERROR mismatched types +} +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution5-deref.rs b/tests/ui/impl-trait/method-resolution5-deref.rs new file mode 100644 index 000000000000..6133a8efe244 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref.rs @@ -0,0 +1,30 @@ +//! The recursive method call yields the opaque type. We want +//! to use the trait candidate for `impl Foo` here while not +//! applying it for the `impl Deref`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +use std::ops::Deref; +trait Foo { + fn method(&self) {} +} +impl Foo for u32 {} +fn via_deref() -> impl Deref { + if false { + via_deref().method(); + } + + Box::new(1u32) +} + +fn via_deref_nested() -> Box> { + if false { + via_deref_nested().method(); + } + + Box::new(Box::new(1u32)) +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-bound-eval.next.stderr b/tests/ui/impl-trait/recursive-bound-eval.next.stderr deleted file mode 100644 index e94f0a59a1d2..000000000000 --- a/tests/ui/impl-trait/recursive-bound-eval.next.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/recursive-bound-eval.rs:20:28 - | -LL | move || recursive_fn().parse() - | ^^^^^ cannot infer type - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/recursive-bound-eval.rs b/tests/ui/impl-trait/recursive-bound-eval.rs index 7859c8983fc8..058b12e5651e 100644 --- a/tests/ui/impl-trait/recursive-bound-eval.rs +++ b/tests/ui/impl-trait/recursive-bound-eval.rs @@ -1,10 +1,9 @@ //! Test that we can evaluate nested obligations when invoking methods on recursive calls on //! an RPIT. -//@revisions: next current +//@ revisions: next current //@[next] compile-flags: -Znext-solver - -//@[current] check-pass +//@ check-pass pub trait Parser { fn parse(&self) -> E; @@ -18,7 +17,6 @@ impl E> Parser for T { pub fn recursive_fn() -> impl Parser { move || recursive_fn().parse() - //[next]~^ ERROR: type annotations needed } fn main() {} diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr deleted file mode 100644 index 5ce6eb0fc398..000000000000 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:11:23 - | -LL | let mut gen = Box::pin(foo()); - | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` -LL | -LL | let mut r = gen.as_mut().resume(()); - | ------ type must be known at this point - | -help: consider specifying the generic argument - | -LL | let mut gen = Box::::pin(foo()); - | +++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 306edc3591e9..932023d103dc 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -1,7 +1,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] check-pass //@[next] compile-flags: -Znext-solver +//@ check-pass #![feature(coroutines, coroutine_trait)] use std::ops::{Coroutine, CoroutineState}; @@ -9,7 +9,6 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { #[coroutine] || { let mut gen = Box::pin(foo()); - //[next]~^ ERROR type annotations needed let mut r = gen.as_mut().resume(()); while let CoroutineState::Yielded(v) = r { yield v; diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr index 5aae334ccbd2..37bde4b18a45 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr @@ -2,7 +2,13 @@ error[E0282]: type annotations needed --> $DIR/method_resolution_trait_method_from_opaque.rs:28:18 | LL | self.bar.next().unwrap(); - | ^^^^ cannot infer type + | ^^^^ + | +help: try using a fully qualified path to specify the expected types + | +LL - self.bar.next().unwrap(); +LL + <_ as Iterator>::next(&mut self.bar).unwrap(); + | error: aborting due to 1 previous error From eebf871feaca10886f80a76a36b3771e960c047e Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 10:08:00 +0200 Subject: [PATCH 300/537] move tests --- tests/ui/impl-trait/{ => method}/method-resolution.rs | 0 tests/ui/impl-trait/{ => method}/method-resolution2.next.stderr | 0 tests/ui/impl-trait/{ => method}/method-resolution2.rs | 0 .../ui/impl-trait/{ => method}/method-resolution3.current.stderr | 0 tests/ui/impl-trait/{ => method}/method-resolution3.next.stderr | 0 tests/ui/impl-trait/{ => method}/method-resolution3.rs | 0 tests/ui/impl-trait/{ => method}/method-resolution4.rs | 0 .../method-resolution5-deref-no-constrain.current.stderr | 0 .../{ => method}/method-resolution5-deref-no-constrain.rs | 0 tests/ui/impl-trait/{ => method}/method-resolution5-deref.rs | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/impl-trait/{ => method}/method-resolution.rs (100%) rename tests/ui/impl-trait/{ => method}/method-resolution2.next.stderr (100%) rename tests/ui/impl-trait/{ => method}/method-resolution2.rs (100%) rename tests/ui/impl-trait/{ => method}/method-resolution3.current.stderr (100%) rename tests/ui/impl-trait/{ => method}/method-resolution3.next.stderr (100%) rename tests/ui/impl-trait/{ => method}/method-resolution3.rs (100%) rename tests/ui/impl-trait/{ => method}/method-resolution4.rs (100%) rename tests/ui/impl-trait/{ => method}/method-resolution5-deref-no-constrain.current.stderr (100%) rename tests/ui/impl-trait/{ => method}/method-resolution5-deref-no-constrain.rs (100%) rename tests/ui/impl-trait/{ => method}/method-resolution5-deref.rs (100%) diff --git a/tests/ui/impl-trait/method-resolution.rs b/tests/ui/impl-trait/method/method-resolution.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution.rs rename to tests/ui/impl-trait/method/method-resolution.rs diff --git a/tests/ui/impl-trait/method-resolution2.next.stderr b/tests/ui/impl-trait/method/method-resolution2.next.stderr similarity index 100% rename from tests/ui/impl-trait/method-resolution2.next.stderr rename to tests/ui/impl-trait/method/method-resolution2.next.stderr diff --git a/tests/ui/impl-trait/method-resolution2.rs b/tests/ui/impl-trait/method/method-resolution2.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution2.rs rename to tests/ui/impl-trait/method/method-resolution2.rs diff --git a/tests/ui/impl-trait/method-resolution3.current.stderr b/tests/ui/impl-trait/method/method-resolution3.current.stderr similarity index 100% rename from tests/ui/impl-trait/method-resolution3.current.stderr rename to tests/ui/impl-trait/method/method-resolution3.current.stderr diff --git a/tests/ui/impl-trait/method-resolution3.next.stderr b/tests/ui/impl-trait/method/method-resolution3.next.stderr similarity index 100% rename from tests/ui/impl-trait/method-resolution3.next.stderr rename to tests/ui/impl-trait/method/method-resolution3.next.stderr diff --git a/tests/ui/impl-trait/method-resolution3.rs b/tests/ui/impl-trait/method/method-resolution3.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution3.rs rename to tests/ui/impl-trait/method/method-resolution3.rs diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method/method-resolution4.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution4.rs rename to tests/ui/impl-trait/method/method-resolution4.rs diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr b/tests/ui/impl-trait/method/method-resolution5-deref-no-constrain.current.stderr similarity index 100% rename from tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr rename to tests/ui/impl-trait/method/method-resolution5-deref-no-constrain.current.stderr diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs b/tests/ui/impl-trait/method/method-resolution5-deref-no-constrain.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs rename to tests/ui/impl-trait/method/method-resolution5-deref-no-constrain.rs diff --git a/tests/ui/impl-trait/method-resolution5-deref.rs b/tests/ui/impl-trait/method/method-resolution5-deref.rs similarity index 100% rename from tests/ui/impl-trait/method-resolution5-deref.rs rename to tests/ui/impl-trait/method/method-resolution5-deref.rs From d6fe5334185385372d1fe8f1c9df8f5d3e7be788 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 10:28:52 +0200 Subject: [PATCH 301/537] add tests --- .../method/broken-deref-chain.current.stderr | 19 ++++++++ .../impl-trait/method/broken-deref-chain.rs | 47 +++++++++++++++++++ .../would-constrain-opaque.current.stderr | 29 ++++++++++++ .../method/would-constrain-opaque.next.stderr | 27 +++++++++++ .../method/would-constrain-opaque.rs | 39 +++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 tests/ui/impl-trait/method/broken-deref-chain.current.stderr create mode 100644 tests/ui/impl-trait/method/broken-deref-chain.rs create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.current.stderr create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.next.stderr create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.rs diff --git a/tests/ui/impl-trait/method/broken-deref-chain.current.stderr b/tests/ui/impl-trait/method/broken-deref-chain.current.stderr new file mode 100644 index 000000000000..726f076b183b --- /dev/null +++ b/tests/ui/impl-trait/method/broken-deref-chain.current.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/broken-deref-chain.rs:41:30 + | +LL | fn trait_method() -> impl Trait { + | ---------- the found opaque type +... +LL | x.trait_method(); + | - here the type of `x` is inferred to be `Foo` +LL | let _: Foo = x; // Test that we did not apply the deref step + | ----------- ^ expected `Foo`, found `Foo` + | | + | expected due to this + | + = note: expected struct `Foo` + found struct `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/method/broken-deref-chain.rs b/tests/ui/impl-trait/method/broken-deref-chain.rs new file mode 100644 index 000000000000..8b45e044f433 --- /dev/null +++ b/tests/ui/impl-trait/method/broken-deref-chain.rs @@ -0,0 +1,47 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +// An annoying edge case of method selection. While computing the deref-chain +// constrains `T` to `u32`, the final method candidate does not and instead +// constrains to `i32`. In this case, we no longer check that the opaque +// remains unconstrained. Both method calls in this test constrain the opaque +// to `i32`. +use std::ops::Deref; + +struct Foo(T, U); +impl Deref for Foo { + type Target = U; + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl Foo { + fn method(&self) {} +} +fn inherent_method() -> impl Sized { + if false { + let x = Foo(Default::default(), inherent_method()); + x.method(); + let _: Foo = x; // Test that we did not apply the deref step + } + 1i32 +} + +trait Trait { + fn trait_method(&self) {} +} +impl Trait for Foo {} +impl Trait for i32 {} +fn trait_method() -> impl Trait { + if false { + let x = Foo(Default::default(), trait_method()); + x.trait_method(); + let _: Foo = x; // Test that we did not apply the deref step + //[current]~^ ERROR mismatched types + } + 1i32 +} + +fn main() {} diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr new file mode 100644 index 000000000000..60533a39c536 --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr @@ -0,0 +1,29 @@ +error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope + --> $DIR/would-constrain-opaque.rs:28:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&impl Sized` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `method`, perhaps you need to implement it + --> $DIR/would-constrain-opaque.rs:15:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope + --> $DIR/would-constrain-opaque.rs:30:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&impl Sized` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `method`, perhaps you need to implement it + --> $DIR/would-constrain-opaque.rs:15:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr b/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr new file mode 100644 index 000000000000..23a4ceb826a6 --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `method` found for reference `&_` in the current scope + --> $DIR/would-constrain-opaque.rs:28:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&_` + | + = help: items from traits can only be used if the trait is implemented and in scope +help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it + | +LL + use Trait; + | + +error[E0599]: no method named `method` found for reference `&_` in the current scope + --> $DIR/would-constrain-opaque.rs:30:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&_` + | + = help: items from traits can only be used if the trait is implemented and in scope +help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it + | +LL + use Trait; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.rs b/tests/ui/impl-trait/method/would-constrain-opaque.rs new file mode 100644 index 000000000000..8dd322825296 --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.rs @@ -0,0 +1,39 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// If we don't treat `impl Sized` as rigid, the first call would +// resolve to the trait method, constraining the opaque, while the +// second call would resolve to the inherent method. +// +// We avoid cases like this by rejecting candidates which constrain +// opaque types encountered in the autoderef chain. +// +// FIXME(-Znext-solver): ideally we would note that the inference variable +// is an opaque type in the error message and change this to a type annotations +// needed error. + +trait Trait: Sized { + fn method(self) {} +} +impl Trait for &Foo {} + +struct Foo; +impl Foo { + fn method(&self) {} +} + +fn define_opaque(b: bool) -> impl Sized { + if b { + let x = &define_opaque(false); + x.method(); + //~^ ERROR no method named `method` found for reference + x.method(); + //~^ ERROR no method named `method` found for reference + } + + Foo +} + +fn main() { + define_opaque(true); +} From c2e39c2f20c568b96fe89c751e65bbbe9116231c Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 Sep 2025 16:37:03 +0200 Subject: [PATCH 302/537] review --- compiler/rustc_hir_typeck/src/method/probe.rs | 9 +++++++++ .../rustc_infer/src/infer/canonical/query_response.rs | 11 ++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e34ee6258b85..12f80a197b1b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2192,6 +2192,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, trait_predicate: Option>, ) -> bool { + // This function is what hacky and doesn't perfectly do what we want it to. + // It's not soundness critical and we should be able to freely improve this + // in the future. + // + // Some concrete edge cases include the fact that `goal_may_hold_opaque_types_jank` + // also fails if there are any constraints opaques which are never used as a self + // type. We also allow where-bounds which are currently ambiguous but end up + // constraining an opaque later on. + // Check whether the trait candidate would not be applicable if the // opaque type were rigid. if let Some(predicate) = trait_predicate { diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index a20cd31113ab..b3959113d5dc 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -87,14 +87,11 @@ impl<'tcx> InferCtxt<'tcx> { { // While we ignore region constraints and pending obligations, // we do return constrained opaque types to avoid unconstrained - // inference variables in the response. This is still slightly - // insufficient as ambiguous `Projection` obligations have the - // same issue. + // inference variables in the response. This is important as we want + // to check that opaques in deref steps stay unconstrained. // - // FIXME(-Znext-solver): We could alternatively extend the `var_values` - // each time we call `make_query_response_ignoring_pending_obligations` - // and equate inference variables created inside of the query this way. - // This is what we do for `CanonicalState` and is probably a bit nicer. + // This doesn't handle the more general case for non-opaques as + // ambiguous `Projection` obligations have same the issue. let opaque_types = if self.next_trait_solver() { self.inner .borrow_mut() From 07bb89f98d485a888796fabb322af06d222a5cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Fri, 26 Sep 2025 17:48:16 +0200 Subject: [PATCH 303/537] Update memchr to 2.7.6 memchr 2.7.6 contains a bugfix for aarch64_be --- src/tools/rust-analyzer/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9d0f63d2bcec..086f38f06a52 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1334,9 +1334,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" From c0e0d4b68d38a92c19f42d3003074b5b6e7b65c8 Mon Sep 17 00:00:00 2001 From: Li-yao Xia Date: Fri, 26 Sep 2025 18:14:31 +0200 Subject: [PATCH 304/537] Make `def_path_hash_to_def_id` not panic when passed an invalid hash --- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 4 ++-- compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs | 9 +++++---- compiler/rustc_middle/src/hooks/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0c8d1f32e991..b895feb90624 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1555,7 +1555,7 @@ impl<'a> CrateMetadataRef<'a> { } #[inline] - fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex { + fn def_path_hash_to_def_index(self, hash: DefPathHash) -> Option { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 11fef3be5d09..df3add316ec2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -691,8 +691,8 @@ fn provide_cstore_hooks(providers: &mut Providers) { .get(&stable_crate_id) .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")); assert_ne!(cnum, LOCAL_CRATE); - let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash); - DefId { krate: cnum, index: def_index } + let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash)?; + Some(DefId { krate: cnum, index: def_index }) }; providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index f3917b55782b..a17b3e1047d0 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -12,11 +12,12 @@ pub(crate) enum DefPathHashMapRef<'tcx> { impl DefPathHashMapRef<'_> { #[inline] - pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { + pub(crate) fn def_path_hash_to_def_index( + &self, + def_path_hash: &DefPathHash, + ) -> Option { match *self { - DefPathHashMapRef::OwnedFromMetadata(ref map) => { - map.get(&def_path_hash.local_hash()).unwrap() - } + DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(&def_path_hash.local_hash()), DefPathHashMapRef::BorrowedFromTcx(_) => { panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization") } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 9d2f0a452371..dc6a3334a4c8 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -77,7 +77,7 @@ declare_hooks! { /// session, if it still exists. This is used during incremental compilation to /// turn a deserialized `DefPathHash` into its current `DefId`. /// Will fetch a DefId from a DefPathHash for a foreign crate. - hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; + hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> Option; /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7d3e2c9965da..a961e04cf79c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2012,7 +2012,7 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) { Some(self.untracked.definitions.read().local_def_path_hash_to_def_id(hash)?.to_def_id()) } else { - Some(self.def_path_hash_to_def_id_extern(hash, stable_crate_id)) + self.def_path_hash_to_def_id_extern(hash, stable_crate_id) } } From 4c7292aba3c7b61708e49a5ec0061d5d901affad Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 26 Sep 2025 13:27:34 -0400 Subject: [PATCH 305/537] PassWrapper: drop unused variable for LLVM 22+ --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 136b6e9bf50f..b7637b29bca5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -569,7 +569,9 @@ extern "C" LLVMRustResult LLVMRustOptimize( } std::optional PGOOpt; +#if LLVM_VERSION_LE(22, 0) auto FS = vfs::getRealFileSystem(); +#endif if (PGOGenPath) { assert(!PGOUsePath && !PGOSampleUsePath); PGOOpt = PGOOptions( From 99456cc015114874319744a07afc1ba94a32315a Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 26 Sep 2025 13:32:03 -0400 Subject: [PATCH 306/537] tests: use max-llvm-major-version instead of ignore-llvm-version --- .../codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs | 2 +- tests/codegen-llvm/vec_pop_push_noop.rs | 2 +- tests/codegen-llvm/vecdeque_pop_push.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs index 631468d8c217..a0b453fac8e9 100644 --- a/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs +++ b/tests/codegen-llvm/issues/issue-122600-ptr-discriminant-update.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Copt-level=3 //@ revisions: new old -//@ [old] ignore-llvm-version: 22 - 99 +//@ [old] max-llvm-major-version: 21 //@ [new] min-llvm-version: 22 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/vec_pop_push_noop.rs b/tests/codegen-llvm/vec_pop_push_noop.rs index fadc6e99dc7a..977c220b3bae 100644 --- a/tests/codegen-llvm/vec_pop_push_noop.rs +++ b/tests/codegen-llvm/vec_pop_push_noop.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Copt-level=3 //@ revisions: new old -//@ [old] ignore-llvm-version: 22 - 99 +//@ [old] max-llvm-major-version: 21 //@ [new] min-llvm-version: 22 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/vecdeque_pop_push.rs b/tests/codegen-llvm/vecdeque_pop_push.rs index 7886db3fedeb..6f9ad6674d6c 100644 --- a/tests/codegen-llvm/vecdeque_pop_push.rs +++ b/tests/codegen-llvm/vecdeque_pop_push.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Copt-level=3 //@ revisions: new old -//@ [old] ignore-llvm-version: 22 - 99 +//@ [old] max-llvm-major-version: 21 //@ [new] min-llvm-version: 22 #![crate_type = "lib"] From 77c6acc74ecd44ba7eb5a73c934dffdff7340133 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 6 Mar 2025 22:10:42 -0500 Subject: [PATCH 307/537] debuginfo: add an unstable flag to write split DWARF to an explicit directory Bazel requires knowledge of outputs from actions at analysis time, including file or directory name. In order to work around the lack of predictable output name for dwo files, we group the dwo files in a subdirectory of --out-dir as a post-processing step before returning control to bazel. Unfortunately some debugging workflows rely on directly opening the dwo file rather than loading the merged dwp file, and our trick of moving the files breaks those users. We can't just hardlink the file or copy it, because with remote build execution we wouldn't end up with the un-moved file copied back to the developer's workstation. As a fix, we add this unstable flag that causes dwo files to be written to a build-system-controllable location, which then lets bazel hoover up the dwo files, but the objects also have the correct path for the dwo files. --- compiler/rustc_interface/src/util.rs | 2 ++ compiler/rustc_session/src/config.rs | 12 +++++++++++- compiler/rustc_session/src/options.rs | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 76ccd12797e5..58ec72b5b45b 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -542,6 +542,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu stem, None, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -571,6 +572,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu out_filestem, ofile, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ebb6a93b1dd1..93be50f0a26c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1193,6 +1193,7 @@ pub struct OutputFilenames { filestem: String, pub single_output_file: Option, temps_directory: Option, + explicit_dwo_out_directory: Option, pub outputs: OutputTypes, } @@ -1225,6 +1226,7 @@ impl OutputFilenames { out_filestem: String, single_output_file: Option, temps_directory: Option, + explicit_dwo_out_directory: Option, extra: String, outputs: OutputTypes, ) -> Self { @@ -1232,6 +1234,7 @@ impl OutputFilenames { out_directory, single_output_file, temps_directory, + explicit_dwo_out_directory, outputs, crate_stem: format!("{out_crate_name}{extra}"), filestem: format!("{out_filestem}{extra}"), @@ -1281,7 +1284,14 @@ impl OutputFilenames { codegen_unit_name: &str, invocation_temp: Option<&str>, ) -> PathBuf { - self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp) + let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp); + if let Some(dwo_out) = &self.explicit_dwo_out_directory { + let mut o = dwo_out.clone(); + o.push(p.file_name().unwrap()); + o + } else { + p + } } /// Like `temp_path`, but also supports things where there is no corresponding diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b2cc169f12cb..9287e032dc4c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2633,6 +2633,8 @@ written to standard error output)"), file which is ignored by the linker `single`: sections which do not require relocation are written into object file but ignored by the linker"), + split_dwarf_out_dir : Option = (None, parse_opt_pathbuf, [TRACKED], + "location for writing split DWARF objects (`.dwo`) if enabled"), split_lto_unit: Option = (None, parse_opt_bool, [TRACKED], "enable LTO unit splitting (default: no)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], From 2e904c4d078967abff213637a45386e2676c3757 Mon Sep 17 00:00:00 2001 From: Joshua Rayton Date: Fri, 26 Sep 2025 18:17:31 +0100 Subject: [PATCH 308/537] update issue number for more_float_constants --- library/core/src/num/f128.rs | 12 ++++++------ library/core/src/num/f16.rs | 12 ++++++------ library/core/src/num/f32.rs | 12 ++++++------ library/core/src/num/f64.rs | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 73ca3fbb142c..4fe4735e304c 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -33,12 +33,12 @@ pub mod consts { /// The golden ratio (φ) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const PHI: f128 = 1.61803398874989484820458683436563811772030917980576286213545_f128; /// The Euler-Mascheroni constant (γ) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const EGAMMA: f128 = 0.577215664901532860606512090082402431042159335939923598805767_f128; /// π/2 @@ -67,14 +67,14 @@ pub mod consts { /// 1/sqrt(π) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_PI: f128 = 0.564189583547756286948079451560772585844050629328998856844086_f128; /// 1/sqrt(2π) #[doc(alias = "FRAC_1_SQRT_TAU")] #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_2PI: f128 = 0.398942280401432677939946059934381868475858631164934657665926_f128; @@ -98,12 +98,12 @@ pub mod consts { /// sqrt(3) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const SQRT_3: f128 = 1.73205080756887729352744634150587236694280525381038062805581_f128; /// 1/sqrt(3) #[unstable(feature = "f128", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f128 = 0.577350269189625764509148780501957455647601751270126876018602_f128; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index a9dbade0e659..0bea6bc8801d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -35,12 +35,12 @@ pub mod consts { /// The golden ratio (φ) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const PHI: f16 = 1.618033988749894848204586834365638118_f16; /// The Euler-Mascheroni constant (γ) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const EGAMMA: f16 = 0.577215664901532860606512090082402431_f16; /// π/2 @@ -69,13 +69,13 @@ pub mod consts { /// 1/sqrt(π) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_PI: f16 = 0.564189583547756286948079451560772586_f16; /// 1/sqrt(2π) #[doc(alias = "FRAC_1_SQRT_TAU")] #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_2PI: f16 = 0.398942280401432677939946059934381868_f16; /// 2/π @@ -96,12 +96,12 @@ pub mod consts { /// sqrt(3) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const SQRT_3: f16 = 1.732050807568877293527446341505872367_f16; /// 1/sqrt(3) #[unstable(feature = "f16", issue = "116909")] - // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f16 = 0.577350269189625764509148780501957456_f16; /// Euler's number (e) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 53474cd3e905..e380cc698f57 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -291,11 +291,11 @@ pub mod consts { pub const TAU: f32 = 6.28318530717958647692528676655900577_f32; /// The golden ratio (φ) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const PHI: f32 = 1.618033988749894848204586834365638118_f32; /// The Euler-Mascheroni constant (γ) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const EGAMMA: f32 = 0.577215664901532860606512090082402431_f32; /// π/2 @@ -323,12 +323,12 @@ pub mod consts { pub const FRAC_1_PI: f32 = 0.318309886183790671537767526745028724_f32; /// 1/sqrt(π) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_PI: f32 = 0.564189583547756286948079451560772586_f32; /// 1/sqrt(2π) #[doc(alias = "FRAC_1_SQRT_TAU")] - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_2PI: f32 = 0.398942280401432677939946059934381868_f32; /// 2/π @@ -348,11 +348,11 @@ pub mod consts { pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32; /// sqrt(3) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const SQRT_3: f32 = 1.732050807568877293527446341505872367_f32; /// 1/sqrt(3) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f32 = 0.577350269189625764509148780501957456_f32; /// Euler's number (e) diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 78113a60bbc2..ff7449fd996c 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -291,11 +291,11 @@ pub mod consts { pub const TAU: f64 = 6.28318530717958647692528676655900577_f64; /// The golden ratio (φ) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const PHI: f64 = 1.618033988749894848204586834365638118_f64; /// The Euler-Mascheroni constant (γ) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const EGAMMA: f64 = 0.577215664901532860606512090082402431_f64; /// π/2 @@ -323,12 +323,12 @@ pub mod consts { pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64; /// 1/sqrt(π) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; /// 1/sqrt(2π) #[doc(alias = "FRAC_1_SQRT_TAU")] - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_2PI: f64 = 0.398942280401432677939946059934381868_f64; /// 2/π @@ -348,11 +348,11 @@ pub mod consts { pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; /// sqrt(3) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const SQRT_3: f64 = 1.732050807568877293527446341505872367_f64; /// 1/sqrt(3) - #[unstable(feature = "more_float_constants", issue = "103883")] + #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64; /// Euler's number (e) From c0de794949f652b368fa107c3b52d0515f1f3859 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 29 Apr 2025 19:01:08 +0100 Subject: [PATCH 309/537] std::net: update tcp deferaccept delay type to Duration. --- library/std/src/os/net/linux_ext/tcp.rs | 23 +++++++++++-------- library/std/src/os/net/linux_ext/tests.rs | 11 +++++---- .../std/src/sys/net/connection/socket/unix.rs | 9 ++++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index fde53ec4257b..dbefc91a979a 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -4,6 +4,7 @@ use crate::sealed::Sealed; use crate::sys_common::AsInner; +use crate::time::Duration; use crate::{io, net}; /// Os-specific extensions for [`TcpStream`] @@ -59,11 +60,13 @@ pub trait TcpStreamExt: Sealed { /// A socket listener will be awakened solely when data arrives. /// - /// The `accept` argument set the delay in seconds until the + /// The `accept` argument set the maximum delay until the /// data is available to read, reducing the number of short lived /// connections without data to process. /// Contrary to other platforms `SO_ACCEPTFILTER` feature equivalent, there is /// no necessity to set it after the `listen` call. + /// Note that the delay is expressed as Duration from user's perspective + /// the call rounds it down to the nearest second expressible as a `c_int`. /// /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) /// @@ -73,16 +76,17 @@ pub trait TcpStreamExt: Sealed { /// #![feature(tcp_deferaccept)] /// use std::net::TcpStream; /// use std::os::linux::net::TcpStreamExt; + /// use std::time::Duration; /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); - /// stream.set_deferaccept(1).expect("set_deferaccept call failed"); + /// stream.set_deferaccept(Duration::from_secs(1u64)).expect("set_deferaccept call failed"); /// ``` #[unstable(feature = "tcp_deferaccept", issue = "119639")] #[cfg(target_os = "linux")] - fn set_deferaccept(&self, accept: u32) -> io::Result<()>; + fn set_deferaccept(&self, accept: Duration) -> io::Result<()>; - /// Gets the accept delay value (in seconds) of the `TCP_DEFER_ACCEPT` option. + /// Gets the accept delay value of the `TCP_DEFER_ACCEPT` option. /// /// For more information about this option, see [`TcpStreamExt::set_deferaccept`]. /// @@ -92,15 +96,16 @@ pub trait TcpStreamExt: Sealed { /// #![feature(tcp_deferaccept)] /// use std::net::TcpStream; /// use std::os::linux::net::TcpStreamExt; + /// use std::time::Duration; /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); - /// stream.set_deferaccept(1).expect("set_deferaccept call failed"); - /// assert_eq!(stream.deferaccept().unwrap_or(0), 1); + /// stream.set_deferaccept(Duration::from_secs(1u64)).expect("set_deferaccept call failed"); + /// assert_eq!(stream.deferaccept().unwrap(), Duration::from_secs(1u64)); /// ``` #[unstable(feature = "tcp_deferaccept", issue = "119639")] #[cfg(target_os = "linux")] - fn deferaccept(&self) -> io::Result; + fn deferaccept(&self) -> io::Result; } #[stable(feature = "tcp_quickack", since = "1.89.0")] @@ -117,12 +122,12 @@ impl TcpStreamExt for net::TcpStream { } #[cfg(target_os = "linux")] - fn set_deferaccept(&self, accept: u32) -> io::Result<()> { + fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { self.as_inner().as_inner().set_deferaccept(accept) } #[cfg(target_os = "linux")] - fn deferaccept(&self) -> io::Result { + fn deferaccept(&self) -> io::Result { self.as_inner().as_inner().deferaccept() } } diff --git a/library/std/src/os/net/linux_ext/tests.rs b/library/std/src/os/net/linux_ext/tests.rs index 12f35696abc5..0758b426ccc5 100644 --- a/library/std/src/os/net/linux_ext/tests.rs +++ b/library/std/src/os/net/linux_ext/tests.rs @@ -32,6 +32,7 @@ fn deferaccept() { use crate::net::test::next_test_ip4; use crate::net::{TcpListener, TcpStream}; use crate::os::net::linux_ext::tcp::TcpStreamExt; + use crate::time::Duration; macro_rules! t { ($e:expr) => { @@ -43,10 +44,12 @@ fn deferaccept() { } let addr = next_test_ip4(); + let one = Duration::from_secs(1u64); + let zero = Duration::from_secs(0u64); let _listener = t!(TcpListener::bind(&addr)); let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - stream.set_deferaccept(1).expect("set_deferaccept failed"); - assert_eq!(stream.deferaccept().unwrap(), 1); - stream.set_deferaccept(0).expect("set_deferaccept failed"); - assert_eq!(stream.deferaccept().unwrap(), 0); + stream.set_deferaccept(one).expect("set_deferaccept failed"); + assert_eq!(stream.deferaccept().unwrap(), one); + stream.set_deferaccept(zero).expect("set_deferaccept failed"); + assert_eq!(stream.deferaccept().unwrap(), zero); } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 8b5970d1494e..86b966242bf3 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -485,14 +485,15 @@ impl Socket { // bionic libc makes no use of this flag #[cfg(target_os = "linux")] - pub fn set_deferaccept(&self, accept: u32) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, accept as c_int) + pub fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { + let val = cmp::min(accept.as_secs(), c_int::MAX as u64) as c_int; + setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) } #[cfg(target_os = "linux")] - pub fn deferaccept(&self) -> io::Result { + pub fn deferaccept(&self) -> io::Result { let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?; - Ok(raw as u32) + Ok(Duration::from_secs(raw as _)) } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] From a4e87e940620bc0e61caa7c42b1edc53c0aee7cb Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 10 Sep 2025 17:11:47 -0400 Subject: [PATCH 310/537] Support `#[rustc_align_static]` inside `thread_local!` --- library/std/src/sys/thread_local/mod.rs | 2 +- .../std/src/sys/thread_local/native/eager.rs | 4 +- .../std/src/sys/thread_local/native/lazy.rs | 4 +- .../std/src/sys/thread_local/native/mod.rs | 12 +- .../std/src/sys/thread_local/no_threads.rs | 72 +++-- library/std/src/sys/thread_local/os.rs | 127 +++++++-- library/std/src/thread/local.rs | 229 +++++++++++++-- library/std/src/thread/mod.rs | 1 + library/std/tests/thread.rs | 2 + src/tools/miri/tests/pass/static_align.rs | 60 ++++ .../feature-gate-static_align-thread_local.rs | 11 + tests/ui/static/static-align.rs | 84 +++++- tests/ui/thread-local/long-docs.rs | 266 ++++++++++++++++++ tests/ui/thread-local/no-unstable.rs | 17 ++ tests/ui/thread-local/no-unstable.stderr | 57 ++++ 15 files changed, 873 insertions(+), 75 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-static_align-thread_local.rs create mode 100644 tests/ui/thread-local/long-docs.rs create mode 100644 tests/ui/thread-local/no-unstable.rs create mode 100644 tests/ui/thread-local/no-unstable.stderr diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index cff74857c473..970022233cfa 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -41,7 +41,7 @@ cfg_select! { } _ => { mod os; - pub use os::{Storage, thread_local_inner}; + pub use os::{Storage, thread_local_inner, value_align}; pub(crate) use os::{LocalPointer, local_pointer}; } } diff --git a/library/std/src/sys/thread_local/native/eager.rs b/library/std/src/sys/thread_local/native/eager.rs index fd48c4f72021..23abad645c1a 100644 --- a/library/std/src/sys/thread_local/native/eager.rs +++ b/library/std/src/sys/thread_local/native/eager.rs @@ -10,9 +10,11 @@ enum State { } #[allow(missing_debug_implementations)] +#[repr(C)] pub struct Storage { - state: Cell, + // This field must be first, for correctness of `#[rustc_align_static]` val: UnsafeCell, + state: Cell, } impl Storage { diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index b556dd9aa25e..02939a74fc08 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -27,9 +27,11 @@ enum State { } #[allow(missing_debug_implementations)] +#[repr(C)] pub struct Storage { - state: Cell>, + // This field must be first, for correctness of `#[rustc_align_static]` value: UnsafeCell>, + state: Cell>, } impl Storage diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index a5dffe3c4588..9544721b923b 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -54,7 +54,7 @@ pub macro thread_local_inner { // test in `tests/thread.rs` if these types are renamed. // Used to generate the `LocalKey` value for const-initialized thread locals. - (@key $t:ty, const $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ const __INIT: $t = $init; unsafe { @@ -62,6 +62,7 @@ pub macro thread_local_inner { if $crate::mem::needs_drop::<$t>() { |_| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::EagerStorage<$t> = $crate::thread::local_impl::EagerStorage::new(__INIT); VAL.get() @@ -69,6 +70,7 @@ pub macro thread_local_inner { } else { |_| { #[thread_local] + $(#[$align_attr])* static VAL: $t = __INIT; &VAL } @@ -78,7 +80,7 @@ pub macro thread_local_inner { }}, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ #[inline] fn __init() -> $t { $init @@ -89,6 +91,7 @@ pub macro thread_local_inner { if $crate::mem::needs_drop::<$t>() { |init| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::LazyStorage<$t, ()> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) @@ -96,6 +99,7 @@ pub macro thread_local_inner { } else { |init| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::LazyStorage<$t, !> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) @@ -104,9 +108,9 @@ pub macro thread_local_inner { }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { + ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); + $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*); }, } diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 4da01a84acf6..4d6a4464cfa8 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -2,6 +2,7 @@ //! thread locals and we can instead just use plain statics! use crate::cell::{Cell, UnsafeCell}; +use crate::mem::MaybeUninit; use crate::ptr; #[doc(hidden)] @@ -11,12 +12,13 @@ use crate::ptr; #[rustc_macro_transparency = "semitransparent"] pub macro thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals - (@key $t:ty, const $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ const __INIT: $t = $init; // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed. unsafe { $crate::thread::LocalKey::new(|_| { + $(#[$align_attr])* static VAL: $crate::thread::local_impl::EagerStorage<$t> = $crate::thread::local_impl::EagerStorage { value: __INIT }; &VAL.value @@ -25,27 +27,27 @@ pub macro thread_local_inner { }}, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ #[inline] fn __init() -> $t { $init } unsafe { - use $crate::thread::LocalKey; - use $crate::thread::local_impl::LazyStorage; - - LocalKey::new(|init| { - static VAL: LazyStorage<$t> = LazyStorage::new(); + $crate::thread::LocalKey::new(|init| { + $(#[$align_attr])* + static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new(); VAL.get(init, __init) }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { + + ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); + $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*); }, } #[allow(missing_debug_implementations)] +#[repr(transparent)] // Required for correctness of `#[rustc_align_static]` pub struct EagerStorage { pub value: T, } @@ -53,14 +55,27 @@ pub struct EagerStorage { // SAFETY: the target doesn't have threads. unsafe impl Sync for EagerStorage {} +#[derive(Clone, Copy, PartialEq, Eq)] +enum State { + Initial, + Alive, + Destroying, +} + #[allow(missing_debug_implementations)] +#[repr(C)] pub struct LazyStorage { - value: UnsafeCell>, + // This field must be first, for correctness of `#[rustc_align_static]` + value: UnsafeCell>, + state: Cell, } impl LazyStorage { pub const fn new() -> LazyStorage { - LazyStorage { value: UnsafeCell::new(None) } + LazyStorage { + value: UnsafeCell::new(MaybeUninit::uninit()), + state: Cell::new(State::Initial), + } } /// Gets a pointer to the TLS value, potentially initializing it with the @@ -70,24 +85,39 @@ impl LazyStorage { /// has occurred. #[inline] pub fn get(&'static self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - let value = unsafe { &*self.value.get() }; - match value { - Some(v) => v, - None => self.initialize(i, f), + if self.state.get() == State::Alive { + self.value.get() as *const T + } else { + self.initialize(i, f) } } #[cold] fn initialize(&'static self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { let value = i.and_then(Option::take).unwrap_or_else(f); - // Destroy the old value, after updating the TLS variable as the - // destructor might reference it. + + // Destroy the old value if it is initialized // FIXME(#110897): maybe panic on recursive initialization. - unsafe { - self.value.get().replace(Some(value)); + if self.state.get() == State::Alive { + self.state.set(State::Destroying); + // Safety: we check for no initialization during drop below + unsafe { + ptr::drop_in_place(self.value.get() as *mut T); + } + self.state.set(State::Initial); } - // SAFETY: we just set this to `Some`. - unsafe { (*self.value.get()).as_ref().unwrap_unchecked() } + + // Guard against initialization during drop + if self.state.get() == State::Destroying { + panic!("Attempted to initialize thread-local while it is being dropped"); + } + + unsafe { + self.value.get().write(MaybeUninit::new(value)); + } + self.state.set(State::Alive); + + self.value.get() as *const T } } diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index fe6af27db3a1..77746b203a32 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -1,5 +1,6 @@ use super::key::{Key, LazyKey, get, set}; use super::{abort_on_dtor_unwind, guard}; +use crate::alloc::Layout; use crate::cell::Cell; use crate::marker::PhantomData; use crate::ptr; @@ -10,17 +11,12 @@ use crate::ptr; #[unstable(feature = "thread_local_internals", issue = "none")] #[rustc_macro_transparency = "semitransparent"] pub macro thread_local_inner { - // used to generate the `LocalKey` value for const-initialized thread locals - (@key $t:ty, const $init:expr) => { - $crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR }) - }, - // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user // provided type or type alias with a matching name. Please update the shadowing test in // `tests/thread.rs` if these types are renamed. // used to generate the `LocalKey` value for `thread_local!`. - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{ #[inline] fn __init() -> $t { $init } @@ -29,37 +25,99 @@ pub macro thread_local_inner { // in `tests/thread.rs` if these types are renamed. unsafe { $crate::thread::LocalKey::new(|init| { - static VAL: $crate::thread::local_impl::Storage<$t> + static VAL: $crate::thread::local_impl::Storage<$t, { + $({ + // Ensure that attributes have valid syntax + // and that the proper feature gate is enabled + $(#[$($align_attr)*])+ + #[allow(unused)] + static DUMMY: () = (); + })? + + #[allow(unused_mut)] + let mut final_align = $crate::thread::local_impl::value_align::<$t>(); + $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)? + final_align + }> = $crate::thread::local_impl::Storage::new(); VAL.get(init, __init) }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { + + // process a single `rustc_align_static` attribute + (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => { + let new_align: $crate::primitive::usize = $($align)*; + if new_align > $final_align { + $final_align = new_align; + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + // process a single `cfg_attr` attribute + // by translating it into a `cfg`ed block and recursing. + // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate + + (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg(true)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg(false)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg($cfg_pred)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$($align_attr:tt)*])*, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); + $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$($align_attr)*])*, $($init)*); }, } /// Use a regular global static to store this key; the state provided will then be /// thread-local. +/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::`. #[allow(missing_debug_implementations)] -pub struct Storage { +pub struct Storage { key: LazyKey, marker: PhantomData>, } -unsafe impl Sync for Storage {} +unsafe impl Sync for Storage {} +#[repr(C)] struct Value { + // This field must be first, for correctness of `#[rustc_align_static]` value: T, // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`. key: Key, } -impl Storage { - pub const fn new() -> Storage { - Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } +pub const fn value_align() -> usize { + crate::mem::align_of::>() +} + +impl Storage { + pub const fn new() -> Storage { + Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } } /// Gets a pointer to the TLS value, potentially initializing it with the @@ -95,8 +153,15 @@ impl Storage { return ptr::null(); } - let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }); - let ptr = Box::into_raw(value); + // Manually allocate with the requested alignment + let layout = Layout::new::>().align_to(ALIGN).unwrap(); + let ptr: *mut Value = (unsafe { crate::alloc::alloc(layout) }).cast(); + if ptr.is_null() { + crate::alloc::handle_alloc_error(layout); + } + unsafe { + ptr.write(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }); + } // SAFETY: // * key came from a `LazyKey` and is thus correct. @@ -114,7 +179,10 @@ impl Storage { // initializer has already returned and the next scope only starts // after we return the pointer. Therefore, there can be no references // to the old value. - drop(unsafe { Box::from_raw(old) }); + unsafe { + old.drop_in_place(); + crate::alloc::dealloc(old.cast(), layout); + } } // SAFETY: We just created this value above. @@ -122,7 +190,7 @@ impl Storage { } } -unsafe extern "C" fn destroy_value(ptr: *mut u8) { +unsafe extern "C" fn destroy_value(ptr: *mut u8) { // SAFETY: // // The OS TLS ensures that this key contains a null value when this @@ -133,13 +201,22 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) { // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. abort_on_dtor_unwind(|| { - let ptr = unsafe { Box::from_raw(ptr as *mut Value) }; - let key = ptr.key; - // SAFETY: `key` is the TLS key `ptr` was stored under. - unsafe { set(key, ptr::without_provenance_mut(1)) }; - drop(ptr); - // SAFETY: `key` is the TLS key `ptr` was stored under. - unsafe { set(key, ptr::null_mut()) }; + let value_ptr: *mut Value = ptr.cast(); + unsafe { + let key = (*value_ptr).key; + + // SAFETY: `key` is the TLS key `ptr` was stored under. + set(key, ptr::without_provenance_mut(1)); + + // drop and deallocate the value + let layout = + Layout::from_size_align_unchecked(crate::mem::size_of::>(), ALIGN); + value_ptr.drop_in_place(); + crate::alloc::dealloc(ptr, layout); + + // SAFETY: `key` is the TLS key `ptr` was stored under. + set(key, ptr::null_mut()); + }; // Make sure that the runtime cleanup will be performed // after the next round of TLS destruction. guard::enable(); diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 0a6f2e5d5088..70df7e724caf 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -132,6 +132,212 @@ impl fmt::Debug for LocalKey { } } +#[doc(hidden)] +#[allow_internal_unstable(thread_local_internals)] +#[unstable(feature = "thread_local_internals", issue = "none")] +#[rustc_macro_transparency = "semitransparent"] +pub macro thread_local_process_attrs { + + // Parse `cfg_attr` to figure out whether it's a `rustc_align_static`. + // Each `cfg_attr` can have zero or more attributes on the RHS, and can be nested. + + // finished parsing the `cfg_attr`, it had no `rustc_align_static` + ( + [] [$(#[$($prev_other_attrs:tt)*])*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)*] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),*)]]; + $($rest)* + ); + ), + + // finished parsing the `cfg_attr`, it had nothing but `rustc_align_static` + ( + [$(#[$($prev_align_attrs:tt)*])+] []; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)*]; + $($rest)* + ); + ), + + // finished parsing the `cfg_attr`, it had a mix of `rustc_align_static` and other attrs + ( + [$(#[$($prev_align_attrs:tt)*])+] [$(#[$($prev_other_attrs:tt)*])+]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),+)]]; + $($rest)* + ); + ), + + // it's a `rustc_align_static` + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [rustc_align_static($($align_static_args:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)* #[rustc_align_static($($align_static_args)*)]] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's a nested `cfg_attr(true, ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's a nested `cfg_attr(false, ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + + // it's a nested `cfg_attr(..., ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: ($cfg_lhs), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's some other attribute + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [$meta:meta $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$meta]]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + + // Separate attributes into `rustc_align_static` and everything else: + + // `rustc_align_static` attribute + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[rustc_align_static $($attr_rest:tt)*] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)* #[rustc_align_static $($attr_rest)*]] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(true, ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(false, ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(..., ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // doc comment not followed by any other attributes; process it all at once to avoid blowing recursion limit + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; $(#[doc $($doc_rhs:tt)*])+ $vis:vis static $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* $(#[doc $($doc_rhs)*])+]; + $vis static $($rest)* + ); + ), + + // 8 lines of doc comment; process them all at once to avoid blowing recursion limit + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + #[doc $($doc_rhs_1:tt)*] #[doc $($doc_rhs_2:tt)*] #[doc $($doc_rhs_3:tt)*] #[doc $($doc_rhs_4:tt)*] + #[doc $($doc_rhs_5:tt)*] #[doc $($doc_rhs_6:tt)*] #[doc $($doc_rhs_7:tt)*] #[doc $($doc_rhs_8:tt)*] + $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* + #[doc $($doc_rhs_1)*] #[doc $($doc_rhs_2)*] #[doc $($doc_rhs_3)*] #[doc $($doc_rhs_4)*] + #[doc $($doc_rhs_5)*] #[doc $($doc_rhs_6)*] #[doc $($doc_rhs_7)*] #[doc $($doc_rhs_8)*]]; + $($rest)* + ); + ), + + // other attribute + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[$($attr:tt)*] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$($attr)*]]; + $($rest)* + ); + ), + + + // Delegate to `thread_local_inner` once attributes are fully categorized: + + // process `const` declaration and recurse + ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = const $init:block $(; $($($rest:tt)+)?)?) => ( + $crate::thread::local_impl::thread_local_inner!($($other_attrs)* $vis $name, $t, $($align_attrs)*, const $init); + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? + ), + + // process non-`const` declaration and recurse + ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = $init:expr $(; $($($rest:tt)+)?)?) => ( + $crate::thread::local_impl::thread_local_inner!($($other_attrs)* $vis $name, $t, $($align_attrs)*, $init); + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? + ), +} + /// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax @@ -182,28 +388,11 @@ impl fmt::Debug for LocalKey { #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] #[allow_internal_unstable(thread_local_internals)] macro_rules! thread_local { - // empty (base case for the recursion) () => {}; - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); - $crate::thread_local!($($rest)*); - ); - - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); - ); - - // process multiple declarations - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - $crate::thread_local!($($rest)*); - ); - - // handle a single declaration - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - ); + ($($tt:tt)+) => { + $crate::thread::local_impl::thread_local_process_attrs!([] []; $($tt)+); + }; } /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 4d09b2b4e9d2..f320c287db32 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -205,6 +205,7 @@ pub use self::local::{AccessError, LocalKey}; #[doc(hidden)] #[unstable(feature = "thread_local_internals", issue = "none")] pub mod local_impl { + pub use super::local::thread_local_process_attrs; pub use crate::sys::thread_local::*; } diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 29f220d8a70a..dc8eadd75148 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -66,6 +66,8 @@ fn thread_local_hygeiene() { type Storage = (); type LazyStorage = (); type EagerStorage = (); + #[allow(non_camel_case_types)] + type usize = (); thread_local! { static A: LocalKey = const { () }; static B: Storage = const { () }; diff --git a/src/tools/miri/tests/pass/static_align.rs b/src/tools/miri/tests/pass/static_align.rs index f292f028568b..bc6a9bf8af7d 100644 --- a/src/tools/miri/tests/pass/static_align.rs +++ b/src/tools/miri/tests/pass/static_align.rs @@ -1,4 +1,7 @@ #![feature(static_align)] +#![deny(non_upper_case_globals)] + +use std::cell::Cell; // When a static uses `align(N)`, its address should be a multiple of `N`. @@ -8,7 +11,64 @@ static FOO: u64 = 0; #[rustc_align_static(512)] static BAR: u64 = 0; +struct HasDrop(*const HasDrop); + +impl Drop for HasDrop { + fn drop(&mut self) { + assert_eq!(core::ptr::from_mut(self).cast_const(), self.0); + } +} + +thread_local! { + #[rustc_align_static(4096)] + static LOCAL: u64 = 0; + + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(true, rustc_align_static(4096))] + static CONST_LOCAL: u64 = const { 0 }; + + #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))] + #[allow(unused_mut, reason = "test attribute handling")] + static HASDROP_LOCAL: Cell = Cell::new(HasDrop(core::ptr::null())); + + /// I love doc comments. + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(all(), + cfg_attr(any(true), + cfg_attr(true, rustc_align_static(4096))))] + #[allow(unused_mut, reason = "test attribute handling")] + /// I love doc comments. + static HASDROP_CONST_LOCAL: Cell = const { Cell::new(HasDrop(core::ptr::null())) }; + + #[cfg_attr(true,)] + #[cfg_attr(false,)] + #[cfg_attr( + true, + rustc_align_static(32), + cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")), + cfg_attr(false,) + )] + #[cfg_attr(false, rustc_align_static(0))] + static more_attr_testing: u64 = 0; +} + +fn thread_local_ptr(key: &'static std::thread::LocalKey) -> *const T { + key.with(|local| core::ptr::from_ref::(local)) +} + fn main() { assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256)); assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512)); + + assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32)); + + // Test that address (and therefore alignment) is maintained during drop + let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL); + core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast()))); + let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL); + core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast()))); } diff --git a/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs new file mode 100644 index 000000000000..29d4facffce9 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs @@ -0,0 +1,11 @@ +// The feature gate error may be emitted twice, but only on certain targets +//@ dont-require-annotations: ERROR +//@ dont-check-compiler-stderr + +#![crate_type = "lib"] + +thread_local! { + //~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature + #[rustc_align_static(16)] + static THREAD_LOCAL: u16 = 0; +} diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs index 93241db09f94..e2db7c01adf2 100644 --- a/tests/ui/static/static-align.rs +++ b/tests/ui/static/static-align.rs @@ -1,10 +1,14 @@ //@ run-pass +//@ compile-flags: --cfg FOURTY_TWO="42" --cfg TRUE --check-cfg=cfg(FOURTY_TWO,values("42")) --check-cfg=cfg(TRUE) #![feature(static_align)] +#![deny(non_upper_case_globals)] + +use std::cell::Cell; #[rustc_align_static(64)] static A: u8 = 0; -#[rustc_align_static(64)] +#[rustc_align_static(4096)] static B: u8 = 0; #[rustc_align_static(128)] @@ -17,10 +21,86 @@ unsafe extern "C" { static C: u64; } +struct HasDrop(*const HasDrop); + +impl Drop for HasDrop { + fn drop(&mut self) { + assert_eq!(core::ptr::from_mut(self).cast_const(), self.0); + } +} + +thread_local! { + #[rustc_align_static(4096)] + static LOCAL: u64 = 0; + + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(true, rustc_align_static(4096))] + static CONST_LOCAL: u64 = const { 0 }; + + #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))] + #[allow(unused_mut, reason = "test attribute handling")] + static HASDROP_LOCAL: Cell = Cell::new(HasDrop(core::ptr::null())); + + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(TRUE, + cfg_attr(FOURTY_TWO = "42", + cfg_attr(all(), + cfg_attr(any(true), + cfg_attr(true, rustc_align_static(4096))))))] + #[allow(unused_mut, reason = "test attribute handling")] + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + static HASDROP_CONST_LOCAL: Cell = const { Cell::new(HasDrop(core::ptr::null())) }; + + #[cfg_attr(TRUE,)] + #[cfg_attr(true,)] + #[cfg_attr(false,)] + #[cfg_attr( + TRUE, + rustc_align_static(32), + cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")), + cfg_attr(false,) + )] + #[cfg_attr(false, rustc_align_static(0))] + static more_attr_testing: u64 = 0; +} + +fn thread_local_ptr(key: &'static std::thread::LocalKey) -> *const T { + key.with(|local| core::ptr::from_ref::(local)) +} + fn main() { assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64)); - assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64)); + assert!(core::ptr::from_ref(&B).addr().is_multiple_of(4096)); assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128)); unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) }; + + assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32)); + + // Test that address (and therefore alignment) is maintained during drop + let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL); + core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast()))); + let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL); + core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast()))); } diff --git a/tests/ui/thread-local/long-docs.rs b/tests/ui/thread-local/long-docs.rs new file mode 100644 index 000000000000..0577d0b27c28 --- /dev/null +++ b/tests/ui/thread-local/long-docs.rs @@ -0,0 +1,266 @@ +//@ check-pass + +thread_local! { + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + pub static LONG_DOCS: () = (); + + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + #[allow(unused_mut, reason = "testing")] + pub static LONG_DOCS_2: () = (); +} + +fn main() {} diff --git a/tests/ui/thread-local/no-unstable.rs b/tests/ui/thread-local/no-unstable.rs new file mode 100644 index 000000000000..3de7985e62db --- /dev/null +++ b/tests/ui/thread-local/no-unstable.rs @@ -0,0 +1,17 @@ +thread_local! { + //~^ ERROR: use of an internal attribute [E0658] + //~| ERROR: use of an internal attribute [E0658] + //~| ERROR: `#[used(linker)]` is currently unstable [E0658] + //~| ERROR: `#[used]` attribute cannot be used on constants + + #[rustc_dummy = 17] + pub static FOO: () = (); + + #[cfg_attr(true, rustc_dummy = 17)] + pub static BAR: () = (); + + #[used(linker)] + pub static BAZ: () = (); +} + +fn main() {} diff --git a/tests/ui/thread-local/no-unstable.stderr b/tests/ui/thread-local/no-unstable.stderr new file mode 100644 index 000000000000..fc2541894e74 --- /dev/null +++ b/tests/ui/thread-local/no-unstable.stderr @@ -0,0 +1,57 @@ +error[E0658]: use of an internal attribute + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: use of an internal attribute + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: `#[used(linker)]` is currently unstable + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = note: see issue #93798 for more information + = help: add `#![feature(used_with_arg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `#[used]` attribute cannot be used on constants + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: `#[used]` can only be applied to statics + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. From 852aa20c90cca64426516f46c3d89cfd57086ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 25 Sep 2025 22:45:07 +0200 Subject: [PATCH 311/537] Rename `rust.use-lld` to `rust.bootstrap-override-lld` --- bootstrap.example.toml | 7 ++- src/bootstrap/src/core/build_steps/compile.rs | 4 +- src/bootstrap/src/core/config/config.rs | 20 ++++++-- src/bootstrap/src/core/config/mod.rs | 2 +- src/bootstrap/src/core/config/tests.rs | 36 +++++++++++--- src/bootstrap/src/core/config/toml/rust.rs | 49 ++++++++++++------- src/bootstrap/src/lib.rs | 12 ++--- src/bootstrap/src/utils/change_tracker.rs | 5 ++ src/bootstrap/src/utils/helpers.rs | 28 +++++++---- .../dist-aarch64-linux/Dockerfile | 2 +- .../host-x86_64/dist-x86_64-linux/Dockerfile | 2 +- 11 files changed, 113 insertions(+), 54 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 0cd571134ef1..0a39c6d8f247 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -768,8 +768,7 @@ # make this default to false. #rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true -# Indicates whether LLD will be used to link Rust crates during bootstrap on -# supported platforms. +# Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD. # If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH # will be used. # If set to `"self-contained"`, rust-lld from the snapshot compiler will be used. @@ -777,7 +776,7 @@ # On MSVC, LLD will not be used if we're cross linking. # # Explicitly setting the linker for a target will override this option when targeting MSVC. -#rust.use-lld = false +#rust.bootstrap-override-lld = false # Indicates whether some LLVM tools, like llvm-objdump, will be made available in the # sysroot. @@ -950,7 +949,7 @@ # Linker to be used to bootstrap Rust code. Note that the # default value is platform specific, and if not specified it may also depend on # what platform is crossing to what platform. -# Setting this will override the `use-lld` option for Rust code when targeting MSVC. +# Setting this will override the `bootstrap-override-lld` option for Rust code when targeting MSVC. #linker = "cc" (path) # Should rustc and the standard library be built with split debuginfo? Default diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index e699922f4dc0..cdd9a44a199c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1219,7 +1219,7 @@ pub fn rustc_cargo( // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object // with direct references to protected symbols, so for now we only use protected symbols if // linking with LLD is enabled. - if builder.build.config.lld_mode.is_used() { + if builder.build.config.bootstrap_override_lld.is_used() { cargo.rustflag("-Zdefault-visibility=protected"); } @@ -1256,7 +1256,7 @@ pub fn rustc_cargo( // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 - if builder.config.lld_mode.is_used() && !build_compiler.host.is_msvc() { + if builder.config.bootstrap_override_lld.is_used() && !build_compiler.host.is_msvc() { cargo.rustflag("-Clink-args=-Wl,--icf=all"); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6d9e3b54156e..271ce4cb950b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -41,7 +41,7 @@ use crate::core::config::toml::gcc::Gcc; use crate::core::config::toml::install::Install; use crate::core::config::toml::llvm::Llvm; use crate::core::config::toml::rust::{ - LldMode, Rust, RustOptimize, check_incompatible_options_for_ci_rustc, + BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc, default_lld_opt_in_targets, parse_codegen_backends, }; use crate::core::config::toml::target::Target; @@ -174,7 +174,7 @@ pub struct Config { pub llvm_from_ci: bool, pub llvm_build_config: HashMap, - pub lld_mode: LldMode, + pub bootstrap_override_lld: BootstrapOverrideLld, pub lld_enabled: bool, pub llvm_tools_enabled: bool, pub llvm_bitcode_linker_enabled: bool, @@ -567,7 +567,8 @@ impl Config { frame_pointers: rust_frame_pointers, stack_protector: rust_stack_protector, strip: rust_strip, - lld_mode: rust_lld_mode, + bootstrap_override_lld: rust_bootstrap_override_lld, + bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy, std_features: rust_std_features, break_on_ice: rust_break_on_ice, } = toml.rust.unwrap_or_default(); @@ -615,6 +616,15 @@ impl Config { let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); + if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { + panic!( + "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`" + ); + } + + let bootstrap_override_lld = + rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default(); + if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( "WARNING: setting `optimize` to `false` is known to cause errors and \ @@ -960,7 +970,7 @@ impl Config { let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out)); - if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained) + if matches!(bootstrap_override_lld, BootstrapOverrideLld::SelfContained) && !lld_enabled && flags_stage.unwrap_or(0) > 0 { @@ -1172,6 +1182,7 @@ impl Config { backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()), bootstrap_cache_path: build_bootstrap_cache_path, + bootstrap_override_lld, bypass_bootstrap_lock: flags_bypass_bootstrap_lock, cargo_info, cargo_native_static: build_cargo_native_static.unwrap_or(false), @@ -1238,7 +1249,6 @@ impl Config { libdir: install_libdir.map(PathBuf::from), library_docs_private_items: build_library_docs_private_items.unwrap_or(false), lld_enabled, - lld_mode: rust_lld_mode.unwrap_or_default(), lldb: build_lldb.map(PathBuf::from), llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false), llvm_assertions, diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 05a5dfc0bc5a..56b87823a365 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -37,7 +37,7 @@ use serde_derive::Deserialize; pub use target_selection::TargetSelection; pub use toml::BUILDER_CONFIG_FILENAME; pub use toml::change_id::ChangeId; -pub use toml::rust::LldMode; +pub use toml::rust::BootstrapOverrideLld; pub use toml::target::Target; use crate::Display; diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 4f2df76a1565..e19604d4ab12 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -17,7 +17,9 @@ use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; use crate::core::build_steps::{llvm, test}; use crate::core::config::toml::TomlConfig; -use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection}; +use crate::core::config::{ + BootstrapOverrideLld, CompilerBuiltins, StringOrBool, Target, TargetSelection, +}; use crate::utils::tests::TestCtx; use crate::utils::tests::git::git_test; @@ -222,11 +224,33 @@ fn verify_file_integrity() { #[test] fn rust_lld() { - assert!(matches!(parse("").lld_mode, LldMode::Unused)); - assert!(matches!(parse("rust.use-lld = \"self-contained\"").lld_mode, LldMode::SelfContained)); - assert!(matches!(parse("rust.use-lld = \"external\"").lld_mode, LldMode::External)); - assert!(matches!(parse("rust.use-lld = true").lld_mode, LldMode::External)); - assert!(matches!(parse("rust.use-lld = false").lld_mode, LldMode::Unused)); + assert!(matches!(parse("").bootstrap_override_lld, BootstrapOverrideLld::None)); + assert!(matches!( + parse("rust.bootstrap-override-lld = \"self-contained\"").bootstrap_override_lld, + BootstrapOverrideLld::SelfContained + )); + assert!(matches!( + parse("rust.bootstrap-override-lld = \"external\"").bootstrap_override_lld, + BootstrapOverrideLld::External + )); + assert!(matches!( + parse("rust.bootstrap-override-lld = true").bootstrap_override_lld, + BootstrapOverrideLld::External + )); + assert!(matches!( + parse("rust.bootstrap-override-lld = false").bootstrap_override_lld, + BootstrapOverrideLld::None + )); + + // Also check the legacy options + assert!(matches!( + parse("rust.use-lld = true").bootstrap_override_lld, + BootstrapOverrideLld::External + )); + assert!(matches!( + parse("rust.use-lld = false").bootstrap_override_lld, + BootstrapOverrideLld::None + )); } #[test] diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index e5987d7040aa..ca9e0d0bc98e 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -45,7 +45,9 @@ define_config! { codegen_backends: Option> = "codegen-backends", llvm_bitcode_linker: Option = "llvm-bitcode-linker", lld: Option = "lld", - lld_mode: Option = "use-lld", + bootstrap_override_lld: Option = "bootstrap-override-lld", + // FIXME: Remove this option in Spring 2026 + bootstrap_override_lld_legacy: Option = "use-lld", llvm_tools: Option = "llvm-tools", deny_warnings: Option = "deny-warnings", backtrace_on_ice: Option = "backtrace-on-ice", @@ -70,22 +72,33 @@ define_config! { } } -/// LLD in bootstrap works like this: -/// - Self-contained lld: use `rust-lld` from the compiler's sysroot +/// Determines if we should override the linker used for linking Rust code built +/// during the bootstrapping process to be LLD. +/// +/// The primary use-case for this is to make local (re)builds of Rust code faster +/// when using bootstrap. +/// +/// This does not affect the *behavior* of the built/distributed compiler when invoked +/// outside of bootstrap. +/// It might affect its performance/binary size though, as that can depend on the +/// linker that links rustc. +/// +/// There are two ways of overriding the linker to be LLD: +/// - Self-contained LLD: use `rust-lld` from the compiler's sysroot /// - External: use an external `lld` binary /// /// It is configured depending on the target: /// 1) Everything except MSVC -/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` -/// - External: `-Clinker-flavor=gnu-lld-cc` +/// - Self-contained: `-Clinker-features=+lld -Clink-self-contained=+linker` +/// - External: `-Clinker-features=+lld` /// 2) MSVC /// - Self-contained: `-Clinker=` /// - External: `-Clinker=lld` #[derive(Copy, Clone, Default, Debug, PartialEq)] -pub enum LldMode { - /// Do not use LLD +pub enum BootstrapOverrideLld { + /// Do not override the linker LLD #[default] - Unused, + None, /// Use `rust-lld` from the compiler's sysroot SelfContained, /// Use an externally provided `lld` binary. @@ -94,16 +107,16 @@ pub enum LldMode { External, } -impl LldMode { +impl BootstrapOverrideLld { pub fn is_used(&self) -> bool { match self { - LldMode::SelfContained | LldMode::External => true, - LldMode::Unused => false, + BootstrapOverrideLld::SelfContained | BootstrapOverrideLld::External => true, + BootstrapOverrideLld::None => false, } } } -impl<'de> Deserialize<'de> for LldMode { +impl<'de> Deserialize<'de> for BootstrapOverrideLld { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -111,7 +124,7 @@ impl<'de> Deserialize<'de> for LldMode { struct LldModeVisitor; impl serde::de::Visitor<'_> for LldModeVisitor { - type Value = LldMode; + type Value = BootstrapOverrideLld; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("one of true, 'self-contained' or 'external'") @@ -121,7 +134,7 @@ impl<'de> Deserialize<'de> for LldMode { where E: serde::de::Error, { - Ok(if v { LldMode::External } else { LldMode::Unused }) + Ok(if v { BootstrapOverrideLld::External } else { BootstrapOverrideLld::None }) } fn visit_str(self, v: &str) -> Result @@ -129,8 +142,8 @@ impl<'de> Deserialize<'de> for LldMode { E: serde::de::Error, { match v { - "external" => Ok(LldMode::External), - "self-contained" => Ok(LldMode::SelfContained), + "external" => Ok(BootstrapOverrideLld::External), + "self-contained" => Ok(BootstrapOverrideLld::SelfContained), _ => Err(E::custom(format!("unknown mode {v}"))), } } @@ -311,7 +324,6 @@ pub fn check_incompatible_options_for_ci_rustc( lto, stack_protector, strip, - lld_mode, jemalloc, rpath, channel, @@ -359,6 +371,8 @@ pub fn check_incompatible_options_for_ci_rustc( frame_pointers: _, break_on_ice: _, parallel_frontend_threads: _, + bootstrap_override_lld: _, + bootstrap_override_lld_legacy: _, } = ci_rust_config; // There are two kinds of checks for CI rustc incompatible options: @@ -374,7 +388,6 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); err!(current_rust_config.rpath, rpath, "rust"); err!(current_rust_config.strip, strip, "rust"); - err!(current_rust_config.lld_mode, lld_mode, "rust"); err!(current_rust_config.llvm_tools, llvm_tools, "rust"); err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust"); err!(current_rust_config.jemalloc, jemalloc, "rust"); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 4f4d35673d5d..d798639cc967 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -35,7 +35,7 @@ use utils::exec::ExecutionContext; use crate::core::builder; use crate::core::builder::Kind; -use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags}; +use crate::core::config::{BootstrapOverrideLld, DryRun, LlvmLibunwind, TargetSelection, flags}; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo}; @@ -1358,14 +1358,14 @@ impl Build { && !target.is_msvc() { Some(self.cc(target)) - } else if self.config.lld_mode.is_used() + } else if self.config.bootstrap_override_lld.is_used() && self.is_lld_direct_linker(target) && self.host_target == target { - match self.config.lld_mode { - LldMode::SelfContained => Some(self.initial_lld.clone()), - LldMode::External => Some("lld".into()), - LldMode::Unused => None, + match self.config.bootstrap_override_lld { + BootstrapOverrideLld::SelfContained => Some(self.initial_lld.clone()), + BootstrapOverrideLld::External => Some("lld".into()), + BootstrapOverrideLld::None => None, } } else { None diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 6b187578c31e..f311c84bec9b 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -556,4 +556,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.", }, + ChangeInfo { + change_id: 99999, + severity: ChangeSeverity::Warning, + summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.", + }, ]; diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index e802c0214ddc..faada9a111db 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -12,7 +12,7 @@ use std::{env, fs, io, panic, str}; use object::read::archive::ArchiveFile; -use crate::LldMode; +use crate::BootstrapOverrideLld; use crate::core::builder::Builder; use crate::core::config::{Config, TargetSelection}; use crate::utils::exec::{BootstrapCommand, command}; @@ -357,15 +357,19 @@ pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> /// Returns a flag that configures LLD to use only a single thread. /// If we use an external LLD, we need to find out which version is it to know which flag should we /// pass to it (LLD older than version 10 had a different flag). -fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: bool) -> &'static str { +fn lld_flag_no_threads( + builder: &Builder<'_>, + bootstrap_override_lld: BootstrapOverrideLld, + is_windows: bool, +) -> &'static str { static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new(); let new_flags = ("/threads:1", "--threads=1"); let old_flags = ("/no-threads", "--no-threads"); let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| { - let newer_version = match lld_mode { - LldMode::External => { + let newer_version = match bootstrap_override_lld { + BootstrapOverrideLld::External => { let mut cmd = command("lld"); cmd.arg("-flavor").arg("ld").arg("--version"); let out = cmd.run_capture_stdout(builder).stdout(); @@ -422,24 +426,28 @@ pub fn linker_flags( lld_threads: LldThreads, ) -> Vec { let mut args = vec![]; - if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() { - match builder.config.lld_mode { - LldMode::External => { + if !builder.is_lld_direct_linker(target) && builder.config.bootstrap_override_lld.is_used() { + match builder.config.bootstrap_override_lld { + BootstrapOverrideLld::External => { args.push("-Clinker-features=+lld".to_string()); args.push("-Zunstable-options".to_string()); } - LldMode::SelfContained => { + BootstrapOverrideLld::SelfContained => { args.push("-Clinker-features=+lld".to_string()); args.push("-Clink-self-contained=+linker".to_string()); args.push("-Zunstable-options".to_string()); } - LldMode::Unused => unreachable!(), + BootstrapOverrideLld::None => unreachable!(), }; if matches!(lld_threads, LldThreads::No) { args.push(format!( "-Clink-arg=-Wl,{}", - lld_flag_no_threads(builder, builder.config.lld_mode, target.is_windows()) + lld_flag_no_threads( + builder, + builder.config.bootstrap_override_lld, + target.is_windows() + ) )); } } diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile index e726329753f2..3abca36fe70d 100644 --- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile @@ -91,7 +91,7 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.ninja=false \ --set rust.debug-assertions=false \ --set rust.jemalloc \ - --set rust.use-lld=true \ + --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ --set rust.codegen-units=1 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 01f19eac1d2f..cb5747876199 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -92,7 +92,7 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.ninja=false \ --set llvm.libzstd=true \ --set rust.jemalloc \ - --set rust.use-lld=true \ + --set rust.bootstrap-override-lld=true \ --set rust.lto=thin \ --set rust.codegen-units=1 From b550688258ddc29618ebd2fa0b6b4a518f12c0e4 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:17:06 -0700 Subject: [PATCH 312/537] castkind::subtype in clippy --- src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 2bda6d50373c..cc98fac45c7c 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 @@ -141,7 +141,8 @@ fn check_rvalue<'tcx>( | CastKind::FloatToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _), + | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _) + | CastKind::Subtype, operand, _, ) => check_operand(cx, operand, span, body, msrv), @@ -312,7 +313,6 @@ fn check_place<'tcx>( | ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) | ProjectionElem::UnwrapUnsafeBinder(_) => {}, } From bd860bdf267644810c8efb4a8d74fdbd0ff8383c Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 26 Sep 2025 15:38:30 -0400 Subject: [PATCH 313/537] Fix typo in LLVM_VERSION_ macro use Co-authored-by: Nikita Popov --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b7637b29bca5..2e9fd6754f12 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -569,7 +569,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( } std::optional PGOOpt; -#if LLVM_VERSION_LE(22, 0) +#if LLVM_VERSION_LT(22, 0) auto FS = vfs::getRealFileSystem(); #endif if (PGOGenPath) { From 9d5adff08cafbb93a53c6f72fcec8cdf89d06e49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 19:45:06 +0000 Subject: [PATCH 314/537] Bump tar-fs from 2.1.3 to 2.1.4 in /editors/code Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 2.1.3 to 2.1.4. - [Commits](https://github.com/mafintosh/tar-fs/compare/v2.1.3...v2.1.4) --- updated-dependencies: - dependency-name: tar-fs dependency-version: 2.1.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/editors/code/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index ad8708e00c51..e35a159cbc3f 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -6405,9 +6405,9 @@ } }, "node_modules/tar-fs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", - "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dev": true, "license": "MIT", "optional": true, From eb3fb457f14c419b58fc8b20d72efcea94e06d9f Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 26 Sep 2025 15:37:44 -0400 Subject: [PATCH 315/537] split-dwarf: add documentation and test coverage --- .../src/compiler-flags/split-dwarf-out-dir.md | 7 + .../src/external_deps/rustc.rs | 7 + tests/run-make/split-debuginfo/rmake.rs | 148 ++++++++++++++++-- 3 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md diff --git a/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md new file mode 100644 index 000000000000..a2070730b42f --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md @@ -0,0 +1,7 @@ +# `split-dwarf-out-dir` + +On systems which use DWARF debug info this flag causes `.dwo` files produced +by `-C split-debuginfo` to be written to the specified directory rather than +placed next to the object files. This is mostly useful if you have a build +system which needs to control where to find compile outputs without running the +compiler and have to put your `.dwo` files in a separate directory. diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index b74b1d5e166f..b461a24a0616 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -366,6 +366,13 @@ impl Rustc { self } + pub fn split_dwarf_out_dir(&mut self, out_dir: Option<&str>) -> &mut Self { + if let Some(out_dir) = out_dir { + self.cmd.arg(format!("-Zsplit-dwarf-out-dir={out_dir}")); + } + self + } + /// Pass the `--verbose` flag. pub fn verbose(&mut self) -> &mut Self { self.cmd.arg("--verbose"); diff --git a/tests/run-make/split-debuginfo/rmake.rs b/tests/run-make/split-debuginfo/rmake.rs index e8de5aed1726..e53b71010781 100644 --- a/tests/run-make/split-debuginfo/rmake.rs +++ b/tests/run-make/split-debuginfo/rmake.rs @@ -187,6 +187,25 @@ enum UnstableOptions { Unspecified, } +#[track_caller] +fn dwo_out_filenames(dwo_out: Option<&str>) -> BTreeSet { + let dwo_out = if let Some(d) = dwo_out { + d + } else { + return BTreeSet::new(); + }; + let files = shallow_find_files(dwo_out, |path| { + // Fiilter out source files + !has_extension(path, "rs") + }); + files + .iter() + .map(|p| { + format!("{}/{}", dwo_out, p.file_name().unwrap().to_os_string().into_string().unwrap()) + }) + .collect() +} + #[track_caller] fn cwd_filenames() -> BTreeSet { let files = shallow_find_files(cwd(), |path| { @@ -196,6 +215,17 @@ fn cwd_filenames() -> BTreeSet { files.iter().map(|p| p.file_name().unwrap().to_os_string().into_string().unwrap()).collect() } +#[track_caller] +fn dwo_out_dwo_filenames(dwo_out: &str) -> BTreeSet { + let files = shallow_find_files(dwo_out, |p| has_extension(p, "dwo")); + files + .iter() + .map(|p| { + format!("{}/{}", dwo_out, p.file_name().unwrap().to_os_string().into_string().unwrap()) + }) + .collect() +} + #[track_caller] fn cwd_dwo_filenames() -> BTreeSet { let files = shallow_find_files(cwd(), |path| has_extension(path, "dwo")); @@ -376,17 +406,19 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { run_in_tmpdir(|| { println!( - "checking: unstable_options={:?} + split_kind={:?} + level={:?} + split_dwarf_kind={:?} + lto={:?} + remap_path_prefix={:?} + remap_path_scope={:?}", + "checking: unstable_options={:?} + split_kind={:?} + level={:?} + split_dwarf_kind={:?} + lto={:?} + remap_path_prefix={:?} + remap_path_scope={:?} + split_dwarf_out_dir={:?}", unstable_options, split_kind, level, split_dwarf_kind, lto, remap_path_prefix, - remap_path_scope + remap_path_scope, + split_dwarf_output_directory, ); match cross_crate_test { @@ -398,6 +430,7 @@ mod shared_linux_other_tests { lto, remap_path_prefix, remap_path_scope, + split_dwarf_output_directory, ), CrossCrateTest::No => simple_split_debuginfo( unstable_options, @@ -407,6 +440,7 @@ mod shared_linux_other_tests { lto, remap_path_prefix, remap_path_scope, + split_dwarf_output_directory, ), } }); @@ -420,7 +454,11 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { + if let Some(dwo_out) = split_dwarf_output_directory { + run_make_support::rfs::create_dir(dwo_out); + } match (split_kind, level, split_dwarf_kind, lto, remap_path_prefix, remap_path_scope) { // packed-crosscrate-split // - Debuginfo in `.dwo` files @@ -531,13 +569,19 @@ mod shared_linux_other_tests { .input("bar.rs") .crate_type("lib") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let bar_found_files = cwd_filenames(); + let mut bar_found_files = cwd_filenames(); + bar_found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let bar_dwo_files = cwd_dwo_filenames(); + let bar_dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(bar_dwo_files.len(), 1); let mut bar_expected_files = BTreeSet::new(); @@ -553,13 +597,19 @@ mod shared_linux_other_tests { .extern_("bar", "libbar.rlib") .input("main.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let overall_found_files = cwd_filenames(); + let mut overall_found_files = cwd_filenames(); + overall_found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let overall_dwo_files = cwd_dwo_filenames(); + let overall_dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(overall_dwo_files.len(), 2); let mut overall_expected_files = BTreeSet::new(); @@ -648,7 +698,11 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { + if let Some(dwo_out) = split_dwarf_output_directory { + run_make_support::rfs::create_dir(dwo_out); + } match (split_kind, level, split_dwarf_kind, lto, remap_path_prefix, remap_path_scope) { // off (unspecified): // - Debuginfo in `.o` files @@ -921,14 +975,19 @@ mod shared_linux_other_tests { rustc(unstable_options) .input("foo.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let found_files = cwd_filenames(); + let mut found_files = cwd_filenames(); + found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let dwo_files = cwd_dwo_filenames(); + let dwo_files = if let Some(dwo_dir) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_dir) + } else { + cwd_dwo_filenames() + }; assert_eq!(dwo_files.len(), 1); - let mut expected_files = BTreeSet::new(); expected_files.extend(dwo_files); expected_files.insert("foo".to_string()); @@ -1056,14 +1115,20 @@ mod shared_linux_other_tests { rustc(unstable_options) .input("foo.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) .run(); - let found_files = cwd_filenames(); + let mut found_files = cwd_filenames(); + found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let dwo_files = cwd_dwo_filenames(); + let dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(dwo_files.len(), 1); let mut expected_files = BTreeSet::new(); @@ -1358,6 +1423,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // off @@ -1370,6 +1436,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-split @@ -1382,6 +1449,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-single @@ -1394,6 +1462,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-lto-split @@ -1406,6 +1475,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-lto-single @@ -1418,6 +1488,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // FIXME: the remapping tests probably need to be reworked, see @@ -1433,6 +1504,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // packed-remapped-single @@ -1445,6 +1517,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // packed-remapped-scope @@ -1457,6 +1530,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("debuginfo"), + None, ); // packed-remapped-wrong-scope @@ -1469,6 +1543,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("macro"), + None, ); // packed-crosscrate-split @@ -1481,6 +1556,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-crosscrate-single @@ -1493,6 +1569,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-split @@ -1505,6 +1582,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, + ); + + // unpacked-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::No, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Unspecified, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-single @@ -1517,6 +1608,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-lto-split @@ -1529,6 +1621,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-lto-single @@ -1541,6 +1634,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-remapped-split @@ -1553,6 +1647,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, + ); + + // unpacked-remapped-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::No, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-remapped-single @@ -1565,6 +1673,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // unpacked-remapped-scope @@ -1577,6 +1686,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("debuginfo"), + None, ); // unpacked-remapped-wrong-scope @@ -1589,6 +1699,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("macro"), + None, ); // unpacked-crosscrate-split @@ -1601,6 +1712,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, + ); + + // unpacked-crosscrate-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::Yes, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Unspecified, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-crosscrate-single @@ -1613,6 +1738,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); } } From b7e444de16d5945908657200d59af608d8c6232c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 16:43:01 +0200 Subject: [PATCH 316/537] Add regression test for merged doctests compilation time display --- .../doctests-compilation-time-info/rmake.rs | 119 ++++++++++++++++++ .../doctests-merge/doctest-2024.stdout | 1 + tests/run-make/doctests-merge/rmake.rs | 2 + .../doctest/doctest-output.edition2015.stdout | 6 +- .../doctest/doctest-output.edition2024.stdout | 7 +- tests/rustdoc-ui/doctest/doctest-output.rs | 2 + .../doctest/merged-ignore-no_run.rs | 2 + .../doctest/merged-ignore-no_run.stdout | 5 +- 8 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 tests/run-make/doctests-compilation-time-info/rmake.rs diff --git a/tests/run-make/doctests-compilation-time-info/rmake.rs b/tests/run-make/doctests-compilation-time-info/rmake.rs new file mode 100644 index 000000000000..2bcf664923f2 --- /dev/null +++ b/tests/run-make/doctests-compilation-time-info/rmake.rs @@ -0,0 +1,119 @@ +//@ ignore-cross-compile (needs to run doctests) + +use run_make_support::rfs::write; +use run_make_support::{cwd, rustdoc}; + +fn assert_presence_of_compilation_time_report( + content: &str, + success: bool, + should_contain_compile_time: bool, +) { + let mut cmd = rustdoc(); + let file = cwd().join("foo.rs"); + + write(&file, content); + cmd.input(&file).arg("--test").edition("2024").env("RUST_BACKTRACE", "0"); + let output = if success { cmd.run() } else { cmd.run_fail() }; + + assert_eq!( + output + .stdout_utf8() + .split("all doctests ran in ") + .last() + .is_some_and(|s| s.contains("; merged doctests compilation took")), + should_contain_compile_time, + ); +} + +fn main() { + // Checking with only successful merged doctests. + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! let x = 12; +//! ```", + true, + true, + ); + // Checking with only failing merged doctests. + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! panic!(); +//! ```", + false, + true, + ); + // Checking with mix of successful doctests. + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! let x = 12; +//! ``` +//! +//! ```compile_fail +//! let x +//! ```", + true, + true, + ); + // Checking with mix of failing doctests. + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! panic!(); +//! ``` +//! +//! ```compile_fail +//! let x +//! ```", + false, + true, + ); + // Checking with mix of failing doctests (v2). + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! let x = 12; +//! ``` +//! +//! ```compile_fail +//! let x = 12; +//! ```", + false, + true, + ); + // Checking with mix of failing doctests (v3). + assert_presence_of_compilation_time_report( + "\ +//! ``` +//! panic!(); +//! ``` +//! +//! ```compile_fail +//! let x = 12; +//! ```", + false, + true, + ); + // Checking with successful non-merged doctests. + assert_presence_of_compilation_time_report( + "\ +//! ```compile_fail +//! let x +//! ```", + true, + // If there is no merged doctests, then we should not display compilation time. + false, + ); + // Checking with failing non-merged doctests. + assert_presence_of_compilation_time_report( + "\ +//! ```compile_fail +//! let x = 12; +//! ```", + false, + // If there is no merged doctests, then we should not display compilation time. + false, + ); +} diff --git a/tests/run-make/doctests-merge/doctest-2024.stdout b/tests/run-make/doctests-merge/doctest-2024.stdout index 7da08d68faae..a7e139bbd23d 100644 --- a/tests/run-make/doctests-merge/doctest-2024.stdout +++ b/tests/run-make/doctests-merge/doctest-2024.stdout @@ -5,3 +5,4 @@ test doctest.rs - init (line 8) ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/run-make/doctests-merge/rmake.rs b/tests/run-make/doctests-merge/rmake.rs index 7893d4988ebb..f2a1e8e13ddf 100644 --- a/tests/run-make/doctests-merge/rmake.rs +++ b/tests/run-make/doctests-merge/rmake.rs @@ -20,6 +20,8 @@ fn test_and_compare(input_file: &str, stdout_file: &str, edition: &str, dep: &Pa .expected_file(stdout_file) .actual_text("output", output.stdout_utf8()) .normalize(r#"finished in \d+\.\d+s"#, "finished in $$TIME") + .normalize(r#"ran in \d+\.\d+s"#, "ran in $$TIME") + .normalize(r#"compilation took \d+\.\d+s"#, "compilation took $$TIME") .run(); } diff --git a/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout b/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout index 0e2e30390ad9..2ff7174577e8 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout +++ b/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout @@ -1,8 +1,8 @@ running 3 tests -test $DIR/doctest-output.rs - (line 12) ... ok -test $DIR/doctest-output.rs - ExpandedStruct (line 28) ... ok -test $DIR/doctest-output.rs - foo::bar (line 22) ... ok +test $DIR/doctest-output.rs - (line 14) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 30) ... ok +test $DIR/doctest-output.rs - foo::bar (line 24) ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout b/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout index 0e2e30390ad9..20bfd7e7086e 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout +++ b/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout @@ -1,8 +1,9 @@ running 3 tests -test $DIR/doctest-output.rs - (line 12) ... ok -test $DIR/doctest-output.rs - ExpandedStruct (line 28) ... ok -test $DIR/doctest-output.rs - foo::bar (line 22) ... ok +test $DIR/doctest-output.rs - (line 14) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 30) ... ok +test $DIR/doctest-output.rs - foo::bar (line 24) ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/doctest-output.rs b/tests/rustdoc-ui/doctest/doctest-output.rs index 04bd1813b4c8..943f59e8b156 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.rs +++ b/tests/rustdoc-ui/doctest/doctest-output.rs @@ -7,6 +7,8 @@ //@[edition2024]compile-flags:--test --test-args=--test-threads=1 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" //@ check-pass //! ``` diff --git a/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs b/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs index 7dac64e6de42..f92bea74bfef 100644 --- a/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs +++ b/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs @@ -2,6 +2,8 @@ //@ compile-flags:--test --test-args=--test-threads=1 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" //@ check-pass /// ```ignore (test) diff --git a/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout b/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout index a32da0aeb964..6714cdb0b809 100644 --- a/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout +++ b/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout @@ -1,7 +1,8 @@ running 2 tests -test $DIR/merged-ignore-no_run.rs - ignored (line 7) ... ignored -test $DIR/merged-ignore-no_run.rs - no_run (line 12) - compile ... ok +test $DIR/merged-ignore-no_run.rs - ignored (line 9) ... ignored +test $DIR/merged-ignore-no_run.rs - no_run (line 14) - compile ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME From d13a5b0a6c12837007c51f229cb8c58b614cfb5b Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Fri, 26 Sep 2025 20:44:06 +0000 Subject: [PATCH 317/537] Handle self-loops too. --- compiler/rustc_mir_transform/src/jump_threading.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index c69660108d9a..68298767e7fd 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -842,9 +842,6 @@ fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); for (bb, bbdata) in traversal::postorder(body) { - let _new = visited.insert(bb); - debug_assert!(_new); - // Post-order means we visit successors before the block for acyclic CFGs. // If the successor is not visited yet, consider it a loop header. for succ in bbdata.terminator().successors() { @@ -852,6 +849,11 @@ fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { maybe_loop_headers.insert(succ); } } + + // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. + // bb1: goto -> bb1; + let _new = visited.insert(bb); + debug_assert!(_new); } maybe_loop_headers From e88fa086fb597041a207a9bb5df0654628d57b1a Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Sat, 27 Sep 2025 01:11:01 +0300 Subject: [PATCH 318/537] move Reborrow to ops, fix fmt issues --- library/core/src/marker.rs | 8 -------- library/core/src/ops/mod.rs | 2 +- library/core/src/ops/reborrow.rs | 8 +++++++- tests/ui/feature-gates/feature-gate-reborrow.rs | 2 +- tests/ui/feature-gates/feature-gate-reborrow.stderr | 4 ++-- tests/ui/reborrow/custom_mut.rs | 2 +- tests/ui/reborrow/custom_mut_coerce_shared.rs | 3 +-- tests/ui/reborrow/custom_mut_coerce_shared.stderr | 4 ++-- tests/ui/reborrow/option_mut.rs | 2 +- tests/ui/reborrow/option_mut.stderr | 4 ++-- tests/ui/reborrow/pin_mut.rs | 2 +- tests/ui/reborrow/pin_mut.stderr | 4 ++-- tests/ui/reborrow/pin_mut_coerce_shared.rs | 1 - 13 files changed, 21 insertions(+), 25 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index d03d7a43469a..fc715207d5da 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1364,11 +1364,3 @@ pub macro CoercePointee($item:item) { pub trait CoercePointeeValidated { /* compiler built-in */ } - -/// Allows value to be reborrowed as exclusive, creating a copy of the value -/// that disables the source for reads and writes for the lifetime of the copy. -#[lang = "reborrow"] -#[unstable(feature = "reborrow", issue = "145612")] -pub trait Reborrow { - // Empty. -} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 9814f5d5795c..ab1ad407ee28 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -191,7 +191,7 @@ pub use self::range::{OneSidedRange, OneSidedRangeBound}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[unstable(feature = "reborrow", issue = "145612")] -pub use self::reborrow::CoerceShared; +pub use self::reborrow::{CoerceShared, Reborrow}; #[unstable(feature = "try_trait_v2_residual", issue = "91285")] pub use self::try_trait::Residual; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] diff --git a/library/core/src/ops/reborrow.rs b/library/core/src/ops/reborrow.rs index 90288f766d50..f83f4233a4de 100644 --- a/library/core/src/ops/reborrow.rs +++ b/library/core/src/ops/reborrow.rs @@ -1,4 +1,10 @@ -use crate::marker::Reborrow; +/// Allows value to be reborrowed as exclusive, creating a copy of the value +/// that disables the source for reads and writes for the lifetime of the copy. +#[lang = "reborrow"] +#[unstable(feature = "reborrow", issue = "145612")] +pub trait Reborrow { + // Empty. +} /// Allows reborrowable value to be reborrowed as shared, creating a copy /// that disables the source for writes for the lifetime of the copy. diff --git a/tests/ui/feature-gates/feature-gate-reborrow.rs b/tests/ui/feature-gates/feature-gate-reborrow.rs index f016f6c6bfa5..96eecfb28a10 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow.rs +++ b/tests/ui/feature-gates/feature-gate-reborrow.rs @@ -1,3 +1,3 @@ -use std::marker::Reborrow; //~ ERROR use of unstable library feature `reborrow` +use std::ops::Reborrow; //~ ERROR use of unstable library feature `reborrow` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow.stderr b/tests/ui/feature-gates/feature-gate-reborrow.stderr index 5e3033f3bf1f..1224909f564b 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow.stderr +++ b/tests/ui/feature-gates/feature-gate-reborrow.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `reborrow` --> $DIR/feature-gate-reborrow.rs:1:5 | -LL | use std::marker::Reborrow; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | use std::ops::Reborrow; + | ^^^^^^^^^^^^^^^^^^ | = note: see issue #145612 for more information = help: add `#![feature(reborrow)]` to the crate attributes to enable diff --git a/tests/ui/reborrow/custom_mut.rs b/tests/ui/reborrow/custom_mut.rs index b55a5e6faa3d..1e7c46932382 100644 --- a/tests/ui/reborrow/custom_mut.rs +++ b/tests/ui/reborrow/custom_mut.rs @@ -1,5 +1,5 @@ #![feature(reborrow)] -use std::marker::Reborrow; +use std::ops::Reborrow; struct CustomMut<'a, T>(&'a mut T); impl<'a, T> Reborrow for CustomMut<'a, T> {} diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.rs b/tests/ui/reborrow/custom_mut_coerce_shared.rs index 28d802aabffe..e2d25835c093 100644 --- a/tests/ui/reborrow/custom_mut_coerce_shared.rs +++ b/tests/ui/reborrow/custom_mut_coerce_shared.rs @@ -1,6 +1,5 @@ #![feature(reborrow)] -use std::marker::Reborrow; -use std::ops::CoerceShared; +use std::ops::{CoerceShared, Reborrow}; struct CustomMut<'a, T>(&'a mut T); impl<'a, T> Reborrow for CustomMut<'a, T> {} diff --git a/tests/ui/reborrow/custom_mut_coerce_shared.stderr b/tests/ui/reborrow/custom_mut_coerce_shared.stderr index 90d8a9816054..508651badc0a 100644 --- a/tests/ui/reborrow/custom_mut_coerce_shared.stderr +++ b/tests/ui/reborrow/custom_mut_coerce_shared.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/custom_mut_coerce_shared.rs:24:12 + --> $DIR/custom_mut_coerce_shared.rs:23:12 | LL | method(a); | ------ ^ expected `CustomRef<'_, ()>`, found `CustomMut<'_, ()>` @@ -9,7 +9,7 @@ LL | method(a); = note: expected struct `CustomRef<'_, ()>` found struct `CustomMut<'_, ()>` note: function defined here - --> $DIR/custom_mut_coerce_shared.rs:20:4 + --> $DIR/custom_mut_coerce_shared.rs:19:4 | LL | fn method(a: CustomRef<'_, ()>) {} | ^^^^^^ -------------------- diff --git a/tests/ui/reborrow/option_mut.rs b/tests/ui/reborrow/option_mut.rs index 60b7145a7b2e..04d8301772de 100644 --- a/tests/ui/reborrow/option_mut.rs +++ b/tests/ui/reborrow/option_mut.rs @@ -1,4 +1,4 @@ -fn method(a: Option<& mut ()>) {} +fn method(a: Option<&mut ()>) {} fn main() { let a = Some(&mut ()); diff --git a/tests/ui/reborrow/option_mut.stderr b/tests/ui/reborrow/option_mut.stderr index 497319d2e903..d665e266079e 100644 --- a/tests/ui/reborrow/option_mut.stderr +++ b/tests/ui/reborrow/option_mut.stderr @@ -11,8 +11,8 @@ LL | let _ = method(a); note: consider changing this parameter type in function `method` to borrow instead if owning the value isn't necessary --> $DIR/option_mut.rs:1:14 | -LL | fn method(a: Option<& mut ()>) {} - | ------ ^^^^^^^^^^^^^^^^ this parameter takes ownership of the value +LL | fn method(a: Option<&mut ()>) {} + | ------ ^^^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function diff --git a/tests/ui/reborrow/pin_mut.rs b/tests/ui/reborrow/pin_mut.rs index 966106969943..959cb14f8c9a 100644 --- a/tests/ui/reborrow/pin_mut.rs +++ b/tests/ui/reborrow/pin_mut.rs @@ -1,6 +1,6 @@ use std::pin::Pin; -fn method(a: Pin<& mut ()>) {} +fn method(a: Pin<&mut ()>) {} fn main() { let a = &mut (); diff --git a/tests/ui/reborrow/pin_mut.stderr b/tests/ui/reborrow/pin_mut.stderr index 8a10e2d9af26..64e3f603e111 100644 --- a/tests/ui/reborrow/pin_mut.stderr +++ b/tests/ui/reborrow/pin_mut.stderr @@ -11,8 +11,8 @@ LL | let _ = method(a); note: consider changing this parameter type in function `method` to borrow instead if owning the value isn't necessary --> $DIR/pin_mut.rs:3:14 | -LL | fn method(a: Pin<& mut ()>) {} - | ------ ^^^^^^^^^^^^^ this parameter takes ownership of the value +LL | fn method(a: Pin<&mut ()>) {} + | ------ ^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function diff --git a/tests/ui/reborrow/pin_mut_coerce_shared.rs b/tests/ui/reborrow/pin_mut_coerce_shared.rs index fd529195fe01..06af0b765d04 100644 --- a/tests/ui/reborrow/pin_mut_coerce_shared.rs +++ b/tests/ui/reborrow/pin_mut_coerce_shared.rs @@ -10,5 +10,4 @@ fn main() { //~| NOTE arguments to this function are incorrect //~| NOTE types differ in mutability //~| NOTE expected struct `Pin<&()>` - //~| NOTE found struct `Pin<&mut ()>` } From 413f095a85adb21331f6e64cf030ead124a6ba07 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Fri, 26 Sep 2025 15:37:19 -0700 Subject: [PATCH 319/537] this ice now requires -Zvalidate-mir also slightly minimized the test --- tests/crashes/120016.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/crashes/120016.rs b/tests/crashes/120016.rs index 7eda330e7ade..12f54dbc3d92 100644 --- a/tests/crashes/120016.rs +++ b/tests/crashes/120016.rs @@ -1,19 +1,19 @@ //@ known-bug: #120016 -//@ compile-flags: -Zcrate-attr=feature(const_async_blocks) +//@ compile-flags: -Zvalidate-mir //@ edition: 2021 -#![feature(type_alias_impl_trait, const_async_blocks)] +#![feature(type_alias_impl_trait)] struct Bug { V1: [(); { - type F = impl std::future::Future; + type F = impl Sized; #[define_opaque(F)] fn concrete_use() -> F { - //~^ ERROR to be a future that resolves to `u8`, but it resolves to `()` - async {} + //~^ ERROR + 1i32 } - let f: F = async { 1 }; - //~^ ERROR `async` blocks are not allowed in constants + let f: F = 0u32; + 1 }], } From 4e9716fbc5fb0f85d838ee9350ade2be5c2a6201 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 14 Sep 2025 10:30:29 -0400 Subject: [PATCH 320/537] Update CURRENT_RUSTC_VERSION post-bump --- compiler/rustc_feature/src/accepted.rs | 6 +- compiler/rustc_feature/src/removed.rs | 4 +- compiler/rustc_feature/src/unstable.rs | 18 +++--- library/alloc/src/boxed.rs | 2 +- library/alloc/src/collections/btree/map.rs | 10 +-- library/alloc/src/collections/btree/set.rs | 10 +-- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- library/core/src/any.rs | 2 +- library/core/src/array/mod.rs | 6 +- library/core/src/cell.rs | 4 +- library/core/src/iter/adapters/chain.rs | 2 +- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 2 +- library/core/src/iter/traits/accum.rs | 2 +- library/core/src/net/ip_addr.rs | 12 ++-- library/core/src/num/int_macros.rs | 56 ++++++++-------- library/core/src/num/uint_macros.rs | 64 +++++++++---------- library/core/src/ptr/mod.rs | 4 +- library/core/src/str/mod.rs | 8 +-- library/core/src/sync/atomic.rs | 14 ++-- library/core/src/time.rs | 8 +-- library/std/src/ffi/os_str.rs | 2 +- library/std/src/os/windows/ffi.rs | 2 +- library/std/src/panic.rs | 2 +- library/std/src/path.rs | 24 +++---- .../src/platform-support/apple-ios-macabi.md | 2 +- .../rustc/src/platform-support/apple-ios.md | 2 +- .../feature-gate-sanitize.stderr | 2 +- 29 files changed, 138 insertions(+), 138 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 6af4cfb0e562..364a1202b05c 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -205,7 +205,7 @@ declare_features! ( (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions /// for functions with varargs. - (accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)), + (accepted, extended_varargs_abi_support, "1.91.0", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. @@ -400,7 +400,7 @@ declare_features! ( /// Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None), /// Allows use of `sse4a` target feature. - (accepted, sse4a_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (accepted, sse4a_target_feature, "1.91.0", Some(44839)), /// Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897)), /// Allows the definition recursive static items. @@ -414,7 +414,7 @@ declare_features! ( /// Allows the use of `#[target_feature]` on safe functions. (accepted, target_feature_11, "1.86.0", Some(69098)), /// Allows use of `tbm` target feature. - (accepted, tbm_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (accepted, tbm_target_feature, "1.91.0", Some(44839)), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301)), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index e37fc6b7bfcc..32115535e994 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -192,7 +192,7 @@ declare_features! ( (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667), // Allows the use of `no_sanitize` attribute. /// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]` - (removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), + (removed, no_sanitize, "1.91.0", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), /// Note: this feature was previously recorded in a separate /// `STABLE_REMOVED` list because it, uniquely, was once stable but was /// then removed. But there was no utility storing it separately, so now @@ -203,7 +203,7 @@ declare_features! ( (removed, object_safe_for_dispatch, "1.83.0", Some(43561), Some("renamed to `dyn_compatible_for_dispatch`"), 131511), /// Allows using `#[omit_gdb_pretty_printer_section]`. - (removed, omit_gdb_pretty_printer_section, "CURRENT_RUSTC_VERSION", None, None, 144738), + (removed, omit_gdb_pretty_printer_section, "1.91.0", None, None, 144738), /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None, 65794), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93e5588146e1..6ef0df72365e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -327,7 +327,7 @@ declare_features! ( (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, movrs_target_feature, "1.88.0", Some(137976)), - (unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (unstable, nvptx_target_feature, "1.91.0", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), @@ -471,7 +471,7 @@ declare_features! ( /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), /// Allows deriving the From trait on single-field structs. - (unstable, derive_from, "CURRENT_RUSTC_VERSION", Some(144889)), + (unstable, derive_from, "1.91.0", Some(144889)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (unstable, doc_auto_cfg, "1.58.0", Some(43781)), /// Allows `#[doc(cfg(...))]`. @@ -481,7 +481,7 @@ declare_features! ( /// Allows `#[doc(masked)]`. (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows features to allow target_feature to better interact with traits. - (incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)), + (incomplete, effective_target_features, "1.91.0", Some(143352)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -554,9 +554,9 @@ declare_features! ( /// Allows fused `loop`/`match` for direct intraprocedural jumps. (incomplete, loop_match, "1.90.0", Some(132306)), /// Allow `macro_rules!` attribute rules - (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)), + (unstable, macro_attr, "1.91.0", Some(83527)), /// Allow `macro_rules!` derive rules - (unstable, macro_derive, "CURRENT_RUSTC_VERSION", Some(143549)), + (unstable, macro_derive, "1.91.0", Some(143549)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. @@ -613,7 +613,7 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), - (unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)), + (unstable, reborrow, "1.91.0", Some(145612)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant @@ -627,13 +627,13 @@ declare_features! ( /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), /// Allows the use of the `sanitize` attribute. - (unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)), + (unstable, sanitize, "1.91.0", Some(39699)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), /// Allows using `#[rustc_align_static(...)]` on static items. - (unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)), + (unstable, static_align, "1.91.0", Some(146177)), /// Allows attributes on expressions and non-item statements. (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. @@ -645,7 +645,7 @@ declare_features! ( /// Allows subtrait items to shadow supertrait items. (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), /// Allows the use of target_feature when a function is marked inline(always). - (unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)), + (unstable, target_feature_inline_always, "1.91.0", Some(145574)), /// Allows using `#[thread_local]` on `static` items. (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1c549f7b6ba1..5a63d90b95fa 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1706,7 +1706,7 @@ impl Default for Box { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "pin_default_impls", since = "1.91.0")] impl Default for Pin> where T: ?Sized, diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index e3b53b2fe291..9dfbbd913225 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1456,7 +1456,7 @@ impl BTreeMap { /// assert_eq!(low.keys().copied().collect::>(), [0, 1, 2, 3]); /// assert_eq!(high.keys().copied().collect::>(), [4, 5, 6, 7]); /// ``` - #[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "btree_extract_if", since = "1.91.0")] pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A> where K: Ord, @@ -1943,7 +1943,7 @@ impl Default for Values<'_, K, V> { } /// An iterator produced by calling `extract_if` on BTreeMap. -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1976,7 +1976,7 @@ pub(super) struct ExtractIfInner<'a, K, V, R> { range: R, } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl fmt::Debug for ExtractIf<'_, K, V, R, F, A> where K: fmt::Debug, @@ -1988,7 +1988,7 @@ where } } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl Iterator for ExtractIf<'_, K, V, R, F, A> where K: PartialOrd, @@ -2062,7 +2062,7 @@ impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> { } } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl FusedIterator for ExtractIf<'_, K, V, R, F> where K: PartialOrd, diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index e6b0a1f63232..6e6996bcbd69 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1218,7 +1218,7 @@ impl BTreeSet { /// assert_eq!(low.into_iter().collect::>(), [0, 1, 2, 3]); /// assert_eq!(high.into_iter().collect::>(), [4, 5, 6, 7]); /// ``` - #[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "btree_extract_if", since = "1.91.0")] pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, @@ -1553,7 +1553,7 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet { } /// An iterator produced by calling `extract_if` on BTreeSet. -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1568,7 +1568,7 @@ pub struct ExtractIf< alloc: A, } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl fmt::Debug for ExtractIf<'_, T, R, F, A> where T: fmt::Debug, @@ -1581,7 +1581,7 @@ where } } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, @@ -1601,7 +1601,7 @@ where } } -#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "btree_extract_if", since = "1.91.0")] impl FusedIterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index aed3357afbf4..627e5c7f976a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2377,7 +2377,7 @@ impl Default for Rc<[T]> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "pin_default_impls", since = "1.91.0")] impl Default for Pin> where T: ?Sized, diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a466b74944c5..3a8695d34a80 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3636,7 +3636,7 @@ impl Default for Arc<[T]> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "pin_default_impls", since = "1.91.0")] impl Default for Pin> where T: ?Sized, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 76ea2d18a82f..3ab95438c3ff 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -774,7 +774,7 @@ impl TypeId { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_type_id", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_type_id", since = "1.91.0")] pub const fn of() -> TypeId { const { intrinsics::type_id::() } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index d713e575b58d..0dc10758a856 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -49,7 +49,7 @@ pub use iter::IntoIter; /// ``` #[inline] #[must_use = "cloning is often expensive and is not expected to have side effects"] -#[stable(feature = "array_repeat", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "array_repeat", since = "1.91.0")] pub fn repeat(val: T) -> [T; N] { from_trusted_iterator(repeat_n(val, N)) } @@ -627,7 +627,7 @@ impl [T; N] { /// assert_eq!(strings.len(), 3); /// ``` #[stable(feature = "array_methods", since = "1.77.0")] - #[rustc_const_stable(feature = "const_array_each_ref", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_array_each_ref", since = "1.91.0")] pub const fn each_ref(&self) -> [&T; N] { let mut buf = [null::(); N]; @@ -658,7 +658,7 @@ impl [T; N] { /// assert_eq!(floats, [0.0, 2.7, -1.0]); /// ``` #[stable(feature = "array_methods", since = "1.77.0")] - #[rustc_const_stable(feature = "const_array_each_ref", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_array_each_ref", since = "1.91.0")] pub const fn each_mut(&mut self) -> [&mut T; N] { let mut buf = [null_mut::(); N]; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7d4a66640b10..6aadb7a86cd1 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -705,8 +705,8 @@ impl Cell<[T; N]> { /// let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); /// ``` - #[stable(feature = "as_array_of_cells", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "as_array_of_cells", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "as_array_of_cells", since = "1.91.0")] + #[rustc_const_stable(feature = "as_array_of_cells", since = "1.91.0")] pub const fn as_array_of_cells(&self) -> &[Cell; N] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 3ebdf7b47279..0ece54554d46 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -60,7 +60,7 @@ impl Chain { /// assert_eq!(iter.next(), Some(6)); /// assert_eq!(iter.next(), None); /// ``` -#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_chain", since = "1.91.0")] pub fn chain(a: A, b: B) -> Chain where A: IntoIterator, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 6c6de0a4e5c9..1ff5093922b6 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -32,7 +32,7 @@ mod zip; pub use self::array_chunks::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; -#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_chain", since = "1.91.0")] pub use self::chain::chain; #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::cloned::Cloned; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index bc07324f5204..c7e1c4ef767b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -404,7 +404,7 @@ pub use self::adapters::StepBy; pub use self::adapters::TrustedRandomAccess; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccessNoCoerce; -#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "iter_chain", since = "1.91.0")] pub use self::adapters::chain; pub(crate) use self::adapters::try_process; #[stable(feature = "iter_zip", since = "1.59.0")] diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 3b805139ded1..375b5ef52859 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -148,7 +148,7 @@ macro_rules! saturating_integer_sum_product { saturating_integer_sum_product!(@impls Saturating(0), Saturating(1), "The short-circuiting behavior of this implementation is unspecified. If you care about \ short-circuiting, use [`Iterator::fold`] directly.", - #[stable(feature = "saturating_iter_arith", since = "CURRENT_RUSTC_VERSION")], + #[stable(feature = "saturating_iter_arith", since = "1.91.0")], $(Saturating<$a>)*); ); } diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 9779fb8fe4d5..a1bfd774710d 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -631,8 +631,8 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]); /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); /// ``` - #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_from", since = "1.91.0")] + #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr { @@ -1478,8 +1478,8 @@ impl Ipv6Addr { /// addr /// ); /// ``` - #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_from", since = "1.91.0")] + #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr { @@ -2043,8 +2043,8 @@ impl Ipv6Addr { /// addr /// ); /// ``` - #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_from", since = "1.91.0")] + #[rustc_const_stable(feature = "ip_from", since = "1.91.0")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 0d80c40fb236..c3460a640906 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -519,8 +519,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -609,8 +609,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -659,8 +659,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -749,8 +749,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -799,8 +799,8 @@ macro_rules! int_impl { /// ``` should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -906,8 +906,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -973,8 +973,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1139,8 +1139,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1205,8 +1205,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1286,8 +1286,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1342,8 +1342,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1517,8 +1517,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1693,8 +1693,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1762,8 +1762,8 @@ macro_rules! int_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index d68c7be9865b..752498bfbd81 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -667,8 +667,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -762,8 +762,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_signed(3);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -821,8 +821,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -946,8 +946,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1002,8 +1002,8 @@ macro_rules! uint_impl { "::MAX), Some(0));" )] /// ``` - #[stable(feature = "unsigned_signed_diff", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "unsigned_signed_diff", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_signed_diff", since = "1.91.0")] + #[rustc_const_stable(feature = "unsigned_signed_diff", since = "1.91.0")] #[inline] pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> { let res = self.wrapping_sub(rhs) as $SignedT; @@ -1055,8 +1055,8 @@ macro_rules! uint_impl { /// ``` should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1151,8 +1151,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1205,8 +1205,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1353,8 +1353,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1409,8 +1409,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1694,8 +1694,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1750,8 +1750,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1922,8 +1922,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2104,8 +2104,8 @@ macro_rules! uint_impl { /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")] /// ``` - #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_overflow_ops", since = "1.91.0")] + #[rustc_const_stable(feature = "strict_overflow_ops", since = "1.91.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2682,7 +2682,7 @@ macro_rules! uint_impl { /// /// assert_eq!((sum1, sum0), (9, 6)); /// ``` - #[stable(feature = "unsigned_bigint_helpers", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] @@ -2774,7 +2774,7 @@ macro_rules! uint_impl { /// #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")] /// ``` - #[stable(feature = "unsigned_bigint_helpers", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] @@ -2991,7 +2991,7 @@ macro_rules! uint_impl { /// 789_u16.wrapping_mul(456).wrapping_add(123), /// ); /// ``` - #[stable(feature = "unsigned_bigint_helpers", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] @@ -3057,7 +3057,7 @@ macro_rules! uint_impl { /// u32::to_le_bytes(0xcffc982d) /// ); /// ``` - #[stable(feature = "unsigned_bigint_helpers", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "unsigned_bigint_helpers", since = "1.91.0")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 625024373ef4..b29d26765425 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -975,7 +975,7 @@ pub const fn dangling_mut() -> *mut T { #[must_use] #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] -#[rustc_const_stable(feature = "const_exposed_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_exposed_provenance", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub const fn with_exposed_provenance(addr: usize) -> *const T { @@ -1016,7 +1016,7 @@ pub const fn with_exposed_provenance(addr: usize) -> *const T { #[must_use] #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] -#[rustc_const_stable(feature = "const_exposed_provenance", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_exposed_provenance", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub const fn with_exposed_provenance_mut(addr: usize) -> *mut T { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 2e473d348b0b..3a5efa7d8351 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -404,8 +404,8 @@ impl str { /// assert_eq!(closest, 10); /// assert_eq!(&s[..closest], "❤️🧡"); /// ``` - #[stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "round_char_boundary", since = "1.91.0")] + #[rustc_const_stable(feature = "round_char_boundary", since = "1.91.0")] #[inline] pub const fn floor_char_boundary(&self, index: usize) -> usize { if index >= self.len() { @@ -447,8 +447,8 @@ impl str { /// assert_eq!(closest, 14); /// assert_eq!(&s[..closest], "❤️🧡💛"); /// ``` - #[stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "round_char_boundary", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "round_char_boundary", since = "1.91.0")] + #[rustc_const_stable(feature = "round_char_boundary", since = "1.91.0")] #[inline] pub const fn ceil_char_boundary(&self, index: usize) -> usize { if index >= self.len() { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1b4a54b1b7a7..30a42d4eb5e6 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2208,7 +2208,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_add(val.wrapping_mul(size_of::()), order) @@ -2252,7 +2252,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { self.fetch_byte_sub(val.wrapping_mul(size_of::()), order) @@ -2286,7 +2286,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2321,7 +2321,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2371,7 +2371,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2420,7 +2420,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. @@ -2467,7 +2467,7 @@ impl AtomicPtr { /// ``` #[inline] #[cfg(target_has_atomic = "ptr")] - #[stable(feature = "strict_provenance_atomic_ptr", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "strict_provenance_atomic_ptr", since = "1.91.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. diff --git a/library/core/src/time.rs b/library/core/src/time.rs index d205bc376f12..f721fcd6156c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -416,8 +416,8 @@ impl Duration { /// assert_eq!(6 * 60 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "duration_constructors_lite", since = "1.91.0")] + #[rustc_const_stable(feature = "duration_constructors_lite", since = "1.91.0")] #[must_use] #[inline] pub const fn from_hours(hours: u64) -> Duration { @@ -444,8 +444,8 @@ impl Duration { /// assert_eq!(10 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "duration_constructors_lite", since = "1.91.0")] + #[rustc_const_stable(feature = "duration_constructors_lite", since = "1.91.0")] #[must_use] #[inline] pub const fn from_mins(mins: u64) -> Duration { diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index a39565d21592..6c098034eea3 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -137,7 +137,7 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] pub const fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index 345d5b74285e..20e5383dc09e 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -141,7 +141,7 @@ impl OsStrExt for OsStr { pub struct EncodeWide<'a> { inner: alloc::wtf8::EncodeWide<'a>, } -#[stable(feature = "encode_wide_debug", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "encode_wide_debug", since = "1.91.0")] impl fmt::Debug for EncodeWide<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 5e8d2f8e78ec..1997785885d3 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -122,7 +122,7 @@ impl<'a> PanicHookInfo<'a> { /// ``` #[must_use] #[inline] - #[stable(feature = "panic_payload_as_str", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "panic_payload_as_str", since = "1.91.0")] pub fn payload_as_str(&self) -> Option<&str> { if let Some(s) = self.payload.downcast_ref::<&str>() { Some(s) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 88d8a4f21cac..718c7c2e3b1a 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1191,7 +1191,7 @@ impl PathBuf { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] pub const fn new() -> PathBuf { PathBuf { inner: OsString::new() } } @@ -1594,7 +1594,7 @@ impl PathBuf { /// p.add_extension(""); /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); /// ``` - #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_add_extension", since = "1.91.0")] pub fn add_extension>(&mut self, extension: S) -> bool { self._add_extension(extension.as_ref()) } @@ -2103,7 +2103,7 @@ impl PartialEq for PathBuf { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for PathBuf { #[inline] fn eq(&self, other: &str) -> bool { @@ -2111,7 +2111,7 @@ impl cmp::PartialEq for PathBuf { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for str { #[inline] fn eq(&self, other: &PathBuf) -> bool { @@ -2119,7 +2119,7 @@ impl cmp::PartialEq for str { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for PathBuf { #[inline] fn eq(&self, other: &String) -> bool { @@ -2127,7 +2127,7 @@ impl cmp::PartialEq for PathBuf { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for String { #[inline] fn eq(&self, other: &PathBuf) -> bool { @@ -2724,7 +2724,7 @@ impl Path { /// /// [`Path::file_stem`]: Path::file_stem /// - #[stable(feature = "path_file_prefix", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_file_prefix", since = "1.91.0")] #[must_use] pub fn file_prefix(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before)) @@ -2888,7 +2888,7 @@ impl Path { /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt")); /// ``` - #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_add_extension", since = "1.91.0")] pub fn with_added_extension>(&self, extension: S) -> PathBuf { let mut new_path = self.to_path_buf(); new_path.add_extension(extension); @@ -3405,7 +3405,7 @@ impl PartialEq for Path { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for Path { #[inline] fn eq(&self, other: &str) -> bool { @@ -3414,7 +3414,7 @@ impl cmp::PartialEq for Path { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for str { #[inline] fn eq(&self, other: &Path) -> bool { @@ -3422,7 +3422,7 @@ impl cmp::PartialEq for str { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for Path { #[inline] fn eq(&self, other: &String) -> bool { @@ -3430,7 +3430,7 @@ impl cmp::PartialEq for Path { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq for String { #[inline] fn eq(&self, other: &Path) -> bool { diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md index c6f68f7a1e81..0d0acaa3bef2 100644 --- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md +++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md @@ -57,7 +57,7 @@ $ rustc --target aarch64-apple-ios-macabi your-code.rs ``` The target can be differentiated from the iOS targets with the -`target_env = "macabi"` cfg (or `target_abi = "macabi"` before Rust CURRENT_RUSTC_VERSION). +`target_env = "macabi"` cfg (or `target_abi = "macabi"` before Rust 1.91.0). ```rust if cfg!(target_env = "macabi") { diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md index 3ac147047546..5de87dc349eb 100644 --- a/src/doc/rustc/src/platform-support/apple-ios.md +++ b/src/doc/rustc/src/platform-support/apple-ios.md @@ -73,7 +73,7 @@ $ cargo +nightly build -Zbuild-std --target armv7s-apple-ios The simulator variants can be differentiated from the variants running on-device with the `target_env = "sim"` cfg (or `target_abi = "sim"` before -Rust CURRENT_RUSTC_VERSION). +Rust 1.91.0). ```rust if cfg!(all(target_vendor = "apple", target_env = "sim")) { diff --git a/tests/ui/feature-gates/feature-gate-sanitize.stderr b/tests/ui/feature-gates/feature-gate-sanitize.stderr index 513999636a95..59e8b69de2e3 100644 --- a/tests/ui/feature-gates/feature-gate-sanitize.stderr +++ b/tests/ui/feature-gates/feature-gate-sanitize.stderr @@ -4,7 +4,7 @@ error[E0557]: feature has been removed LL | #![feature(no_sanitize)] | ^^^^^^^^^^^ feature has been removed | - = note: removed in CURRENT_RUSTC_VERSION; see for more information + = note: removed in 1.91.0; see for more information = note: renamed to sanitize(xyz = "on|off") error[E0658]: the `#[sanitize]` attribute is an experimental feature From 201f299ef6039886042ad8dd7c76a4fbd1a77a3f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 15 Sep 2025 22:01:36 -0400 Subject: [PATCH 321/537] Apply cfg(bootstrap) replacement --- compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_index/src/idx.rs | 6 ------ compiler/rustc_lint_defs/src/builtin.rs | 11 ++++------- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_span/src/lib.rs | 1 - src/bootstrap/src/core/sanity.rs | 4 ---- src/librustdoc/lib.rs | 1 - src/tools/clippy/clippy_lints/src/lib.rs | 1 - src/tools/clippy/tests/missing-test-files.rs | 1 - src/tools/miri/src/lib.rs | 1 - src/tools/miri/tests/panic/mir-validation.rs | 5 ----- tests/ui/track-diagnostics/track.rs | 7 +------ tests/ui/track-diagnostics/track.stderr | 6 +++--- 13 files changed, 8 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 8ace560d85d1..9c0ec4e51a0c 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![doc(rust_logo)] #![feature(array_try_map)] #![feature(assert_matches)] diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 9cd7134659c5..2fb2008f9a3d 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -130,12 +130,6 @@ impl IntoSliceIdx for core::range::RangeFrom { impl IntoSliceIdx for core::range::RangeInclusive { type Output = core::range::RangeInclusive; #[inline] - #[cfg(bootstrap)] - fn into_slice_idx(self) -> Self::Output { - core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } - } - #[inline] - #[cfg(not(bootstrap))] fn into_slice_idx(self) -> Self::Output { core::range::RangeInclusive { start: self.start.index(), last: self.last.index() } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3d0974d5d280..939f3d088b12 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2309,10 +2309,10 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![cfg_attr(not(bootstrap), feature(sanitize))] + /// #![feature(sanitize)] /// /// #[inline(always)] - /// #[cfg_attr(not(bootstrap), sanitize(address = "off"))] + /// #[sanitize(address = "off")] /// fn x() {} /// /// fn main() { @@ -4837,16 +4837,13 @@ declare_lint! { /// /// ### Example /// - #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] - #[cfg_attr(bootstrap, doc = "```rust")] + /// ```rust,compile_fail /// #![doc = in_root!()] /// /// macro_rules! in_root { () => { "" } } /// /// fn main() {} - #[cfg_attr(not(bootstrap), doc = "```")] - #[cfg_attr(bootstrap, doc = "```")] - // ^ Needed to avoid tidy warning about odd number of backticks + /// ``` /// /// {{produces}} /// diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5023b2740eff..754a258eef93 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e95b743b1ce2..35dbbe58db9a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,7 +17,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 91d80c96e426..eaa9e3a6a3e9 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -33,11 +33,7 @@ pub struct Finder { // // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ - "armv7a-vex-v5", - "riscv64a23-unknown-linux-gnu", // just a dummy comment so the list doesn't get onelined - "aarch64_be-unknown-hermit", - "aarch64_be-unknown-none-softfloat", "x86_64-unknown-motor", ]; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5d8f8f4bed12..c4f24e09ddbf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,5 +1,4 @@ // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/" diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index c56fa257b068..b0083b99f175 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -7,7 +7,6 @@ #![feature(iter_intersperse)] #![feature(iter_partition_in_place)] #![feature(never_type)] -#![cfg_attr(bootstrap, feature(round_char_boundary))] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![feature(unwrap_infallible)] diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index 63f960c92fa3..9fff3132498d 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -1,6 +1,5 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] -#![cfg_attr(bootstrap, feature(path_file_prefix))] use std::cmp::Ordering; use std::ffi::OsStr; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 7f5f25b9f66b..1f82f154b0b3 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![feature(abort_unwind)] #![feature(cfg_select)] #![feature(rustc_private)] diff --git a/src/tools/miri/tests/panic/mir-validation.rs b/src/tools/miri/tests/panic/mir-validation.rs index b9097f2e8c53..2d0d530754d8 100644 --- a/src/tools/miri/tests/panic/mir-validation.rs +++ b/src/tools/miri/tests/panic/mir-validation.rs @@ -9,11 +9,6 @@ // and we don't even get a regular panic; rustc aborts with a different exit code instead. //@ignore-host: windows -// FIXME: this tests a crash in rustc. For stage1, rustc is built with the downloaded standard -// library which doesn't yet print the thread ID. Normalization can be removed at the stage bump. -// For the grep: cfg(bootstrap) -//@normalize-stderr-test: "thread 'rustc' panicked" -> "thread 'rustc' ($$TID) panicked" - #![feature(custom_mir, core_intrinsics)] use core::intrinsics::mir::*; diff --git a/tests/ui/track-diagnostics/track.rs b/tests/ui/track-diagnostics/track.rs index 9ce0a4a555ac..2d6d6170fe0b 100644 --- a/tests/ui/track-diagnostics/track.rs +++ b/tests/ui/track-diagnostics/track.rs @@ -13,13 +13,8 @@ // top of this file are present, then assume all args are present. //@ normalize-stderr: "note: compiler flags: .*-Z ui-testing.*-Z track-diagnostics" -> "note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics" -// FIXME: this tests a crash in rustc. For stage1, rustc is built with the downloaded standard -// library which doesn't yet print the thread ID. Normalization can be removed at the stage bump. -// For the grep: cfg(bootstrap) -//@normalize-stderr: "thread 'rustc' panicked" -> "thread 'rustc' ($$TID) panicked" - fn main() { - break rust + break rust; //~^ ERROR cannot find value `rust` in this scope //~| NOTE created at //~| ERROR `break` outside of a loop or labeled block diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr index bc04ded379df..76b4bd14f5cd 100644 --- a/tests/ui/track-diagnostics/track.stderr +++ b/tests/ui/track-diagnostics/track.stderr @@ -1,7 +1,7 @@ error[E0425]: cannot find value `rust` in this scope --> $DIR/track.rs:LL:CC | -LL | break rust +LL | break rust; | ^^^^ not found in this scope | = note: -Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC @@ -9,7 +9,7 @@ LL | break rust error[E0268]: `break` outside of a loop or labeled block --> $DIR/track.rs:LL:CC | -LL | break rust +LL | break rust; | ^^^^^^^^^^ cannot `break` outside of a loop or labeled block | = note: -Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC @@ -17,7 +17,7 @@ LL | break rust error: internal compiler error: It looks like you're trying to break rust; would you like some ICE? --> $DIR/track.rs:LL:CC | -LL | break rust +LL | break rust; | ^^^^^^^^^^ | = note: -Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/lib.rs:LL:CC From 54669d7db41952d4c04d735d2c6702d1b2022fed Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 15 Sep 2025 22:04:38 -0400 Subject: [PATCH 322/537] Bump stage0 --- src/stage0 | 1000 ++++++++++++++++++++++++++-------------------------- 1 file changed, 500 insertions(+), 500 deletions(-) diff --git a/src/stage0 b/src/stage0 index a705cd1c760d..6d2f0402f4ac 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,506 +13,506 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_date=2025-08-05 +compiler_date=2025-09-16 compiler_version=beta -rustfmt_date=2025-09-05 +rustfmt_date=2025-09-16 rustfmt_version=nightly -dist/2025-08-05/rustc-beta-aarch64-apple-darwin.tar.gz=b9d8f74da46aeadb6c650a4ccfc3c2de08e229e4211a198fa2914103f09f579d -dist/2025-08-05/rustc-beta-aarch64-apple-darwin.tar.xz=493ed87c65bac5593c104373a3277ddc2330072796704e4b6800c531326da860 -dist/2025-08-05/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=6c20a3b2e4d3ef9a54b1fe4f50c71895d4d8557d6960f887ef4958c0f2a19eab -dist/2025-08-05/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=d6bffc013745c0d69f4cf7ab4f747f8ad885e3b1b77fa56c2e7de8808e278294 -dist/2025-08-05/rustc-beta-aarch64-pc-windows-msvc.tar.gz=3b6bf7e2aff93854346c1d0970cf207c049c17c5ea6ee299dcdb1fd92e996fc0 -dist/2025-08-05/rustc-beta-aarch64-pc-windows-msvc.tar.xz=8241fdc7c673499091700cfcfafe10f3b70bf91918a3b7204a73d2b28445cfa5 -dist/2025-08-05/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=36a093e6c99f227e293ebcaebc89e58166e3da7447d2499069c616610fb4e691 -dist/2025-08-05/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=7cad77f36dcabbe77d603b8b3b4bfa83488a3af2e9b815f698f544de148c77a8 -dist/2025-08-05/rustc-beta-aarch64-unknown-linux-musl.tar.gz=421980aa1ef5467f59c1a8ad43415d69057c9277fdc91d1d5c2b53c246e8bbe9 -dist/2025-08-05/rustc-beta-aarch64-unknown-linux-musl.tar.xz=0ba5b4cd4f5975a58cf86331de5a3c80fb2fd620d50797360a5af4ebf2bba575 -dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=13b3e61ca606bfdf90d46a8873ca4f14fa07ad8bd77364f1a85f557f31ba7299 -dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=f6a1991e55af549d6cd59ddbebb6d2289d90d1e37b2a9449d7831b4c117a54bf -dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=a5533df1ae642bcea571aa6c2b5eda16a56c6cd597906081840bb7531f7b02a3 -dist/2025-08-05/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=2a7187ad6d0215f07d0472880e117556508780e37df6e2a1a7fdbb67fd8dc87e -dist/2025-08-05/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=3ae6e7d83ae3e1c5c8030ba93b9103addaf11f0f8807f1fbf813305d8e6a9188 -dist/2025-08-05/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=324d6de1a8e4d9c1dd13cc86665fd06cb167d4a3ea55607cd5353300733f480e -dist/2025-08-05/rustc-beta-i686-pc-windows-gnu.tar.gz=0bc4b50638818008e054af245d4e987ce5e55fdc56e19d31c18e8c0165f860ab -dist/2025-08-05/rustc-beta-i686-pc-windows-gnu.tar.xz=b0e5343207a9684d5efe81e536d23135df07bebd869dcad69c632811e1e37137 -dist/2025-08-05/rustc-beta-i686-pc-windows-msvc.tar.gz=c3231335a50402989d4e08857fd7194a3fe5384d2aa34153a25a3f2955a942ef -dist/2025-08-05/rustc-beta-i686-pc-windows-msvc.tar.xz=be578fcbfe32e40fd9688e618927ddcce88e7e08a279778d4c3399eb46e8ae29 -dist/2025-08-05/rustc-beta-i686-unknown-linux-gnu.tar.gz=96b2cdda499b63aadb76b37a4895623a4806c5c8db8f6edeaeb1b812d337192f -dist/2025-08-05/rustc-beta-i686-unknown-linux-gnu.tar.xz=f6496eabe0efcc09c7a4994cc4825e9c3e494c8ca7679cfcbd38a699438e1b74 -dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=3403d7be2f49387149ce075b427f8eaa306066db9fd4ec69de61dc01f6834037 -dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=8cb3a329ef3632afc1f709b9f9b99a2ab7f5c18590590ddacf64f1b3e5a3ff69 -dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=9485ce37e99a6a53b5521683bec65d015a730a41c4c3f3baa19226edd211fc39 -dist/2025-08-05/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=450d91ad61a23f69560e53c7001aec047bd17fb4831bafb97e7226162bb3c0f4 -dist/2025-08-05/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=dc9ff117a7dd3e685c634e8668d78022f66f6e58dc449fbe5f398688ed2dae0a -dist/2025-08-05/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=7dbc936f94d531040601d6fc02d9db87335a1b7927637494c9e208a43f012010 -dist/2025-08-05/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=4a68557cf53063817ee651f5838ad2c3de93a647b9002fe3c82f0372cbd71708 -dist/2025-08-05/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=f5ae9c4ba17d2941e8fa947d9712a8db8dbbdecbcfa4330988d02b9299fbc814 -dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=ad33c48172c3b9abbd95b9dd3c1d38d5f6bc25fe84b95e492b6cdad27ef1bf19 -dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=89d40fb02cded4e8d9b3e177f07e1b984481d493015a2532dfdb5b8aaf5ffa94 -dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=a5ab7a321363502609a4ec5464be96629c693395503c8ce285990db3c556a775 -dist/2025-08-05/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=7e3b5afc7858857d5840bd6e788fd88449555e2fbe4c9a206ee3552e61dd79b0 -dist/2025-08-05/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=fde633217cf77d6fc6f901d84619f681a1fd1e42be75960809bab4806528a451 -dist/2025-08-05/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=69541c68f31a401229d770ef2ea6d032104fe928db845eae23f04c40db021a8d -dist/2025-08-05/rustc-beta-s390x-unknown-linux-gnu.tar.gz=dc257bbab4790dbc3f9df70853eadce198dd5f6f47c8e830254ee2b21c6c79a3 -dist/2025-08-05/rustc-beta-s390x-unknown-linux-gnu.tar.xz=d5a9d5c555241b231eacc0584db0b540ee2982e8bd66cf8568064aab4beb0c94 -dist/2025-08-05/rustc-beta-sparcv9-sun-solaris.tar.gz=96b25f8ce6db2f9d9b7e8da75839d1bd4c97011bebd2544633ab2061e4460bb3 -dist/2025-08-05/rustc-beta-sparcv9-sun-solaris.tar.xz=88438d143441da62bf5415857aab3490697f7f413b7de41cd113bac1480ea7de -dist/2025-08-05/rustc-beta-x86_64-apple-darwin.tar.gz=f59175ef402489c1dd2f6a8984ecb66314240a8e4f7c55e5d92017fc025fa4ee -dist/2025-08-05/rustc-beta-x86_64-apple-darwin.tar.xz=21de96e49395252e6eb5b175ee794acad78ccd4ac081303a8da7ec84bf2b6ab1 -dist/2025-08-05/rustc-beta-x86_64-pc-solaris.tar.gz=164a9b76347131d78fb81519627ab50f13a313d8da13d09f7fa479a41c519458 -dist/2025-08-05/rustc-beta-x86_64-pc-solaris.tar.xz=0f91f1f4b8880944341d82894b830a70f8a60837687829e0ab9626f3281ddd1b -dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnu.tar.gz=634711ae22708a5ae57bb2022fd22257664a8510b59975f4b4ad4b9a8acf475b -dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnu.tar.xz=b72c0d3f5800e92b91d1361e52b28ff622aeb1f1cbdff2efd22c2f2a3315dd68 -dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=668f3a8b48092721bb6e1a01440776d6b906850a11e1bcc37a50bb13ef8d7b04 -dist/2025-08-05/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=e06a183829e09448e76daaf8c317b52d11fac7d16ad191ef61b8f7a806eb9414 -dist/2025-08-05/rustc-beta-x86_64-pc-windows-msvc.tar.gz=564849501d1e41fe776f5443b87c9500621adef97eff05d2c03d539ea3c886da -dist/2025-08-05/rustc-beta-x86_64-pc-windows-msvc.tar.xz=6a1c1cc47c0e8b6aaad215d4d4e8b770b96336e9f2a0317fcf0511b662966bfd -dist/2025-08-05/rustc-beta-x86_64-unknown-freebsd.tar.gz=560bcc4d150f4e22f5598d61fce86c9baeda1b57bda837270f7cac78cfc12b19 -dist/2025-08-05/rustc-beta-x86_64-unknown-freebsd.tar.xz=cdfe207645068b4659b0f979cae177723c5f211084f45ae9180b2d93ee83fce6 -dist/2025-08-05/rustc-beta-x86_64-unknown-illumos.tar.gz=5a362ca0c686b0e0666824df3f304ec49d7d419abb08473fece69d41e96ee625 -dist/2025-08-05/rustc-beta-x86_64-unknown-illumos.tar.xz=fb4e7b12b5223545f6fd57754744f03dd6807b6801e97f9f0fe07bc371efed62 -dist/2025-08-05/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=74225a1889120c0174a056e7ca7656f38e8788137ee3d29df857567ae0605692 -dist/2025-08-05/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=2d37542e88f84a0501841e12865262142fec0efef9ca729d26a3c333f16e465d -dist/2025-08-05/rustc-beta-x86_64-unknown-linux-musl.tar.gz=156eabc89e1ee9558b9de6f60b1bc47c81ab33ae20fa946c4ad4e32b7f30c221 -dist/2025-08-05/rustc-beta-x86_64-unknown-linux-musl.tar.xz=0cf9e649b9020fcfd25282ae1edb1ac59560b7d6d0f79ff7ff3b62871ff25d86 -dist/2025-08-05/rustc-beta-x86_64-unknown-netbsd.tar.gz=8db86a95b22efc2ff2f344e301171813375ccfd2aacad61d3aa84a63f573647a -dist/2025-08-05/rustc-beta-x86_64-unknown-netbsd.tar.xz=68c10c6431b4433d4de5d24a9bb6ebabe99769b077cdd80ab5e0ee67a273035e -dist/2025-08-05/rust-std-beta-aarch64-apple-darwin.tar.gz=872e61e6d6915c02de0b9437b910f6f37f5e11c83347bbe2284a59c31aa27ac3 -dist/2025-08-05/rust-std-beta-aarch64-apple-darwin.tar.xz=748516af852836f06efa927cc96bdd2ad6b012d0262e87bdec97a112212cc24a -dist/2025-08-05/rust-std-beta-aarch64-apple-ios.tar.gz=2c1cf24819ec790d124c7ace59c12a903250eefdad6362b40c779a97b732459e -dist/2025-08-05/rust-std-beta-aarch64-apple-ios.tar.xz=b2fd6df9653b6c0bc13d4331355b3b9a4756886ba46d6c744687bf7bbd8e4630 -dist/2025-08-05/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=c266b75c66ea17b174ce8a746bbad78bca58bd72c3cdda603f20a868f9b3b00c -dist/2025-08-05/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=da5558b25c82a5fc1b66786b035212c5d0df2d4124da3e581e15636f29547dd0 -dist/2025-08-05/rust-std-beta-aarch64-apple-ios-sim.tar.gz=8441032f41e142faebe78e84501344180447121602a2000d1310d7a716cf3695 -dist/2025-08-05/rust-std-beta-aarch64-apple-ios-sim.tar.xz=48713adfa5605addd97e13312f6bc4cf103c06623f67705732684b51d0bed8b1 -dist/2025-08-05/rust-std-beta-aarch64-linux-android.tar.gz=1eb2bbc5fac670aa5867546f1caf1378591d5c0d3a3800ca1dd052645fea0cd6 -dist/2025-08-05/rust-std-beta-aarch64-linux-android.tar.xz=ae5e8aedcc5c8bf719e8ed788d52cc69daf64dfcf878e8497b45454c1c582c56 -dist/2025-08-05/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=bedf5d7663acb4e1afed9dea4b5b8e9b7f0e0dd68e311d3597819ddd028576f7 -dist/2025-08-05/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=e19fd9dc6d9e774e30a9e4a16ac5d6d1fd3300eb880c09f6b61cc63d52370629 -dist/2025-08-05/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=8ad111b1e8e19fdc5bd33d82a1f6d88b9c1809e27531af9d9fed2e37f75edeb4 -dist/2025-08-05/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=332976524e42b4d7b2763a28cae3ebbc3eec03465c098df26e81242294277de4 -dist/2025-08-05/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=92f4737a1775c1fed9311b8949950c6606ca34d272f787d222923555fb69f98b -dist/2025-08-05/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=2f1ebaa974dc3c6b39c43e38cf6d9f5c6fba0d46229a0423be676d817905850c -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=798dafd6f581f367dfed9763b62b35e77466f87ae8252a52f503f1c1bf58f1a5 -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=c4434727604a2773f73e8919a6e967c7c487d75684514cacbe59fb2d6a5f0d29 -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=c48d4e44b0e94f341e7ab2f9d47b08280930152a53dff20d6c9140739fbd2898 -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=8cac54d6a39c13dd0f38fde523a852c5db7f61a7f05b3e3ad0f78c7f59513d02 -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=5c3d7ea7ac6ab60311fb49c5a2f04a92266bc8a675d7f333219177a91b400f9b -dist/2025-08-05/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=f1f9f8a71fc5903bf720d39bedaadab16363b37f9e99817d7cf27b7122ad1ad0 -dist/2025-08-05/rust-std-beta-aarch64-unknown-none.tar.gz=ceffb671e87556b304e63cf01572e1cad8c8cfa0b33ccd1a373b033c60696376 -dist/2025-08-05/rust-std-beta-aarch64-unknown-none.tar.xz=a9a9b17f2b4fdf45f46359726e0c28f6a1289a7abf81fdbe1ae180b2f550aa60 -dist/2025-08-05/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=9f6f6a121e3b19b7b3b2c85dcd13544c12af18cc5544403e29ea8bbd5b13fecc -dist/2025-08-05/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=5b0f0059dd5d837fad74aaf2971fb135229b030a832268106be512557cc7a611 -dist/2025-08-05/rust-std-beta-aarch64-unknown-uefi.tar.gz=67166c7d6d7210ca97c3610abfa126234653d0e26658bbea64d574852fad04fe -dist/2025-08-05/rust-std-beta-aarch64-unknown-uefi.tar.xz=05f72e7c0ebbf7b41bf3e773bbbc073ca9c71417a80dec8f3916dafbe0cdcf7b -dist/2025-08-05/rust-std-beta-arm-linux-androideabi.tar.gz=bdf103a29035659972f35bb9060ba8df5ca9b7b068e3c094d758331a5e667144 -dist/2025-08-05/rust-std-beta-arm-linux-androideabi.tar.xz=8fa8b6994b4e04fec77a6657db0fde4e4cb9336466ce0c4f3e2b154709969c93 -dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=4298510905c958e45291c2fbc4c54bfed9fdafbd48636896fe00a73e94f700ba -dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=79e0e393f5286429755faee738ed110fb1cc51b83aec3c94194e903f0b938d73 -dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=37278a621e2449b9030045c174c71f3ddf74e70b49b5f247c36fea1b1654979f -dist/2025-08-05/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=3ac094e855f7593a22a56ec40923384a0e25265645d05b2a46dde2612d9c6cf9 -dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b5bc7d83a3c59764cdc169ae349e01cd052b8ab054eb13b4f2a1cd02ddd7fd6c -dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=2f8558fee897543da620531e500f3a73c5aac4ea815b7bd418945103dedde530 -dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=2e812427b5169e7de22b720776208ae92f9075c5509f6b9ad8666b9866232735 -dist/2025-08-05/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=e544363209177357386f220d6c4101b1d86d84c03e51254ff459ca42ef187107 -dist/2025-08-05/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=778c947235bb0023ca26dc0592e4d3cb9ad9665c3316d57822c173ba2b5e231e -dist/2025-08-05/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=3a5bf7620e1b24e1f72968f5cc28cc58acc9b5739f2c08f5c4b9e449d8c551a1 -dist/2025-08-05/rust-std-beta-armebv7r-none-eabi.tar.gz=fcace82dc77156a6e7c658fc5abe4992075cfe822fb18a1edfca1967102a6adc -dist/2025-08-05/rust-std-beta-armebv7r-none-eabi.tar.xz=9616372693902e89b55de55b62009a59baccb11ccb63710a475856deca70655c -dist/2025-08-05/rust-std-beta-armebv7r-none-eabihf.tar.gz=2c596de7d22a4762908676d4e048f5075cbf2d66c5f7a03afb96e709f2d080ca -dist/2025-08-05/rust-std-beta-armebv7r-none-eabihf.tar.xz=b1ff9e3fe11acc22fa5ad46530dff62bfceac9df6fcbd3da7999535a00dd2e3e -dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=e033e4bfc11a5bcb7f0645426fac899f7d071236a228300ca2022935997b17fd -dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=919587b40e2bc6c6e8f496244c357c04d5e53b8adb9b3f274432943fd789a1a4 -dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=392a1f0528e4b783e5fd0be74efbec58eb3b0ebd69c3855675301ebf96b76c4a -dist/2025-08-05/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=183144eb89cc1a035c04d50c4060e159ca5099fec71f4f25801a924fa013d04a -dist/2025-08-05/rust-std-beta-armv7-linux-androideabi.tar.gz=f968b761773b76f151b39dce0f3757f59eee2d8b70373d1419e0986429885d7d -dist/2025-08-05/rust-std-beta-armv7-linux-androideabi.tar.xz=fecda678541a151b76f3874e710e875a662a9165eaf1cf12b081ea55ea18a38b -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=300d7e8adaad86ddeff643109d0c83a87e41a056171f9d48b0b6108719003325 -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=acb8f61c97efae6e95aaabe1cab1300bc3cc3a1dc2066c7e2376ad6a9994971c -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=5e90333cb68f3161f8cb30e69d4ebe46f6653998651c72a87a795ab02c11dade -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=355bc516a7a6454eaacc66eadaa4d640cb3ffc7b5400a01bb4bdccf4470ae650 -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=8daa2c4c4dd9e8a1b9ee8a60f2cab0dab81aaf1e7a9d732093979ccdeac8bf60 -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=52b78d85f8e9e19da83504bb523aecf7b641d15c1de2f9b988bedf52912636d4 -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=c63000f15b52881c20f40cf1468afd4f3a2a6a84e944357fe6532c7d0e281b3a -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=53fc3486e4d805386c1ac4d6a1007a9b5461ae606c9c820951b720b45dc8f35c -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=315fc371ac2cddeb65c87bd50369e28247c16ca55fdab527e88899e01adc9efe -dist/2025-08-05/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=d7999aff0a39c63709977f5c18d79b575f8bfb467fbacf4f1b41cd26b52a6701 -dist/2025-08-05/rust-std-beta-armv7a-none-eabi.tar.gz=0707721586e8929811c2904e4136d31f5c415e3f00bfa88dbb920360aa9deea9 -dist/2025-08-05/rust-std-beta-armv7a-none-eabi.tar.xz=bedfd1a808f758f5088ea0fcb746d3ccf11730945e2b07220e93829c0d5c472a -dist/2025-08-05/rust-std-beta-armv7r-none-eabi.tar.gz=315fadb161b3be540b7a276ebe15b1f8d4bdf73b46c1633e39f698014aca8eb1 -dist/2025-08-05/rust-std-beta-armv7r-none-eabi.tar.xz=4bc2fcd9dee2ee44914da0e6af3763c7ddcbe3ebd9fb20c1d552a0226cd877d7 -dist/2025-08-05/rust-std-beta-armv7r-none-eabihf.tar.gz=9c8be30130709ff94a9718091559a752530f0eeb21be80fc3cca0665e85ae0dc -dist/2025-08-05/rust-std-beta-armv7r-none-eabihf.tar.xz=f0dd0bd30ed70c3a022016d8bbed54a6e942571f2e4c773bd8b4198d7dccdb5c -dist/2025-08-05/rust-std-beta-i586-unknown-linux-gnu.tar.gz=ca6c3b8af1c44deaf7dce9e8d4c8786a5801226b30beaa646067d393eeaa0ee8 -dist/2025-08-05/rust-std-beta-i586-unknown-linux-gnu.tar.xz=4e96f0e5f2e3eda60ca2b6d9ce234ae74c5eb2412a7e2c0c571eaf792dca6e28 -dist/2025-08-05/rust-std-beta-i586-unknown-linux-musl.tar.gz=60c736e3ac2aa5b9ceedcd73e39efa12bc9b889ef85f548170f80fbf2b05dfa0 -dist/2025-08-05/rust-std-beta-i586-unknown-linux-musl.tar.xz=fe636d893e38c32a163a88ece160d5b5ea61a3fa63463d4e4f425d229c2927f1 -dist/2025-08-05/rust-std-beta-i686-linux-android.tar.gz=9e62d61041187a91b74c81fe77cd6802a7e38c5a535412c71850426f6a48f37c -dist/2025-08-05/rust-std-beta-i686-linux-android.tar.xz=862d3d5442fb011b917f565aaadb201c22e7b2ecd6a68c0c410b3335741c1c22 -dist/2025-08-05/rust-std-beta-i686-pc-windows-gnu.tar.gz=05a8da51c477e2c2ce4ea12d41c8afaaf0d226a6b933b6c55fd3584b39103366 -dist/2025-08-05/rust-std-beta-i686-pc-windows-gnu.tar.xz=cf15b3d2011ceb57064d0b2285defee7df8628c3bf2b95f7f2ac92a449546d4f -dist/2025-08-05/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=fe11b777eae25d823f40352e47272222c2de8edc2d271eb4f6e7ff508efa198d -dist/2025-08-05/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=a7bb6f223e3542e613eaa7f2b9d9974be71cd2debf8426faa50cfb63fde681fd -dist/2025-08-05/rust-std-beta-i686-pc-windows-msvc.tar.gz=5fbd709698d80b3227a8bc6cbecfc597e99dede3824c751e1d166cac2c5862dc -dist/2025-08-05/rust-std-beta-i686-pc-windows-msvc.tar.xz=92fd2a6a5dbe53f68e9ba3ce40cd3beea95ba9d6a2f1293f7f3d917f34739a66 -dist/2025-08-05/rust-std-beta-i686-unknown-freebsd.tar.gz=182acad6cea45855f66646d437ee44ddb1f85c2c998cc5c7a4bbb025ca0d9da9 -dist/2025-08-05/rust-std-beta-i686-unknown-freebsd.tar.xz=53f8bfaabff1dbc47929a99a92025a31c1e272bf6a8091c4f95d33557dfe9ea1 -dist/2025-08-05/rust-std-beta-i686-unknown-linux-gnu.tar.gz=b80dd4e77c56256f7a7f837bf84129d19e1a4aa08a0ca7e2881402371a7e4395 -dist/2025-08-05/rust-std-beta-i686-unknown-linux-gnu.tar.xz=52efb657f28303b0747cf281c972653abfbeb4bf6d0b841f8bbab7f08c5d7310 -dist/2025-08-05/rust-std-beta-i686-unknown-linux-musl.tar.gz=323abc9766231dca10c225b3ec567c694c0ff6f6eddcc30d728a0f08aa6d2186 -dist/2025-08-05/rust-std-beta-i686-unknown-linux-musl.tar.xz=8998ce49f1be28bcd837831f1d7b79b0b339bc74ced42adb6d997ed016e90e88 -dist/2025-08-05/rust-std-beta-i686-unknown-uefi.tar.gz=07261ce98c95839b8714f40e07cbffa32c10fc7c59394dc87b07e144564c5fef -dist/2025-08-05/rust-std-beta-i686-unknown-uefi.tar.xz=fb6eb023b9722a44e63bcd48fd88c61cf41453842a211107c84039c6883409e5 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=d0a52888f5ef3107ecdbf28b918eb516a9176ae8695079a81a22d1b7ca0e29bd -dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=c14a477558a6c924e05e1b58bd9df60f5e4966c7f0da294dd38e3bd89c1dc5f6 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=bbb93219393948d055df44edcdfff4b03ca251205c545d6f1bd53ade5f314d52 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=48b437a8afe240828c0377a6baa276500f125661f1bc888ebd1ea546f0497f4a -dist/2025-08-05/rust-std-beta-loongarch64-unknown-none.tar.gz=fcec6b60a1a22dcd04b8409d38103496d76bb4297ded9f1f092743bd05f0bd54 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-none.tar.xz=2f4aacb734b5a1dd522b4836035ab213db675508b9ff9a1bdc0c2df3ea9d39d1 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=aad8445e9a5deb4a466ebed84cab101bbe8ef49530315c0349d93e2062ae65a8 -dist/2025-08-05/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=906e1cbd1e3b22eb5c378417646baf18b00acb274ee4198ea59ea356f4f1a0da -dist/2025-08-05/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=b0d7e8daae2eff0c660b6e01bc76258550b9bfbdbf95c104019db7c797339ef5 -dist/2025-08-05/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=c0bffdbb4de90486cad1a26df997006c142f1acc7ed39419975c10b0d09c6217 -dist/2025-08-05/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=3c845cade37fe2b1cfe3087c69f9ecb3e0eec32d2558701c677d4c21ea9e08db -dist/2025-08-05/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=15830d827258f6c3386fa09da66e06ff0460098b46432e28b4e96bd36d61e787 -dist/2025-08-05/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=4b63d9260253f1d3a0168ed367792284584b87aa936fc76262e9fe0ad83c7fa1 -dist/2025-08-05/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=dfba70ad94524437fc8ec5e4684239eceb76678112776915f02502b80cb0afac -dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=3d96bebe611a0167a43060312cbfa2fe4000b9949772ee44ffd27226acd006c8 -dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=44e95c2756f52129b8bd21d7d4ad7ec8e05e43192f3bc894cba4a371b579a6d8 -dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=ca5b7c47b63fa8e005078cb73d111462c438b764909ca106933837ac93d5780f -dist/2025-08-05/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=b102756451c18003ad1b132d25d333ed1a0e4959b87d2904a6e407fc02a7e422 -dist/2025-08-05/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=a592e995b40d3b1eb69cb1f7cd3c100713ea092742ab6ec5769e8df8551ffa16 -dist/2025-08-05/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=af9cd91be3d667cf31b535862882537a406f49932f58308f283228b20fc7bd76 -dist/2025-08-05/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=bf9e9d0f8c4ce8041c6e628e1b637ac0cb316f865f97a43cf2bf522e255c5ec1 -dist/2025-08-05/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=c3e56d71c1586559212f701508ee94f0bfa7801e7d2fdc62c062dcce8a0d040d -dist/2025-08-05/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=068023ed1f1dea01f2523f3b2b9ef41b22a301ceafa0526ebaa757481d14408a -dist/2025-08-05/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=1e3db6625ebb12a8c735cf4e8658a33bac7bca461de1e516860843d50027ee7d -dist/2025-08-05/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=aeb986eef375fa1ebb179668c6778c587d1af8b9e1ff50e5b56f9a3b48f1d8df -dist/2025-08-05/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=45d314189b9327645f6490628157fce32b7b59eccdf57676be0c31e1247f5385 -dist/2025-08-05/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=82d6e6549c80e62d392654693a28528f2ea540652f3ec0810b6646968cae6509 -dist/2025-08-05/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=805ffe0a6dfbc886f0ba93ac9ce796c110ea6d0a64b2d6209cdadd56cd2a570f -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=941c683ef7d013166c7f3439ee1229f80a367405f55bab9072dd12725364db6b -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=8b666222443b3954a7550b14ef919b7ab038e6a4a2355386e42c9acbe28f2024 -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=80f740bd004b98d5c090fe280ef5e372e4bff7a34dc2ba4940204cf02f50bb93 -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=b69ad00f5d60c63fa6d7b32c4d7006d195540d902f8390754c7db92a9221973d -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=ed52f0f9bac7b9d7ec49226eea471e44fecf0416608a5b169d35b12d009e9c1b -dist/2025-08-05/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=d4dc1b096b26814f14e1e23717cef10f3f63cdc6902e345916e015a99851cb69 -dist/2025-08-05/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=aa1de02a79f16bb4affb50c3ba0e719352c9925fc57f22f989eed3f7df1a8e5c -dist/2025-08-05/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=a36e2749e118f995417f0de9c9835db4b36f8ed6d76d8805510853984f648c5b -dist/2025-08-05/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=32e6e3672d3c379a1defb6c661eca6f2ce342784feaceafec004bdaa89a0b226 -dist/2025-08-05/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=a449f0392193ab8a48a30b0a8c0c57b0a02747ae8302d08b3be89d475f1b8291 -dist/2025-08-05/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=a4e0901c13d3c534e176fdf824a97e5a6ca66a198b73a132b957d41b1f198261 -dist/2025-08-05/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=64720eab59f7c958aadd360b8e2dc5696760d62e9f5f44daba890fc55a4fb6a1 -dist/2025-08-05/rust-std-beta-sparcv9-sun-solaris.tar.gz=8d5d3be06cfe5431b9a8e965fe06837efe531c365e8d46ee8cdc8e9da19099f0 -dist/2025-08-05/rust-std-beta-sparcv9-sun-solaris.tar.xz=913d7fc4aa75ac2175aa52891f9086d48065d96007885e0caf5feb628953a86d -dist/2025-08-05/rust-std-beta-thumbv6m-none-eabi.tar.gz=ca59366093c472f19381fdc71aacf6b3d659750a8a3bd8894191a42c8c3b82f9 -dist/2025-08-05/rust-std-beta-thumbv6m-none-eabi.tar.xz=e16dc610520f4748ffca99b235e58a544e7f97ca4cf99cbebbeb106ed4acffd1 -dist/2025-08-05/rust-std-beta-thumbv7em-none-eabi.tar.gz=08a281c1bd56149ebd05531fe405a621383ad440fcf273fec04e0792f325d669 -dist/2025-08-05/rust-std-beta-thumbv7em-none-eabi.tar.xz=a9f7eadfa375061835f139bbb870a5692b727de8a85fb8177d8fabd0588e28cd -dist/2025-08-05/rust-std-beta-thumbv7em-none-eabihf.tar.gz=f996d8b1aae894af11407ac90c277e161acd58378307548ffaa2fa0a4314f3d7 -dist/2025-08-05/rust-std-beta-thumbv7em-none-eabihf.tar.xz=48b9e7d257ad1fac0b23b3a7d6b3ae8afb5dd19db7b5dd2a59ddfe51364db72f -dist/2025-08-05/rust-std-beta-thumbv7m-none-eabi.tar.gz=1061c6b8794aa4e1f66ff17d91934bb9711c6064362cca7bca1d7cdd4f9189cb -dist/2025-08-05/rust-std-beta-thumbv7m-none-eabi.tar.xz=974b1078724ac06757d7899fde62f623e61c86ac0853cdbf02a252b13383e55a -dist/2025-08-05/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=a4fd4047a744bea871a54af311f27a08b5f7c8f04e5e62f7abf292689378ab4f -dist/2025-08-05/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=19c31d2a0982689228eb58522ac7610d33cfcc1b5f72ee2e41e218695a49d09d -dist/2025-08-05/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=8b5e150d6950866734b025e58b3714c4acfe631785fc464e6fe3cbedd98709d0 -dist/2025-08-05/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=23ca585e084fb548488e17adaea92e16ac98340fe146073046d1bfbe6faa325f -dist/2025-08-05/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=d31bcb162cd2ee40a69acb2c201c07c233b8c2710bc07ad322263121f0d422db -dist/2025-08-05/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=67354653ab11222806f4a688c11be6dc80468785e14a8b58f2285a695c53c5a2 -dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=ad61d8510d82ca1094a893879d7148446e2880dd1d172b9e8a420772b0b4611b -dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=5c1ddf66949a40265effbc76ac3da59efb1bb3349dbe2a8037b8215375647fdb -dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=4895c9a6659e831cdacd314ff2ca4c968fd368c6bf9308f334468cb07892ae56 -dist/2025-08-05/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=f64a05715457288b36dd16fcbbdd91816829b889047c277841f3f4972bcc6076 -dist/2025-08-05/rust-std-beta-wasm32-unknown-emscripten.tar.gz=3b144570ddc44868a6609f921028b23f994de337c54a96fccaf976abe4e2ceff -dist/2025-08-05/rust-std-beta-wasm32-unknown-emscripten.tar.xz=355a1bc09dd4163a416cb78e55ec998e95b8acbb9b072dbd3a8e34f5e95d3378 -dist/2025-08-05/rust-std-beta-wasm32-unknown-unknown.tar.gz=52213b11d29f02d4531495c9d35ee7022ef6b8400a8386b8728156b33d2a9eed -dist/2025-08-05/rust-std-beta-wasm32-unknown-unknown.tar.xz=1f282c355a1499fc2a212705700fbb8de7e568dbdc5d43d3c895af86fe9f735b -dist/2025-08-05/rust-std-beta-wasm32-wasip1.tar.gz=f40da6445acb1e854625a02b1078f670874e75d763168430d0ca17ef3b9bae26 -dist/2025-08-05/rust-std-beta-wasm32-wasip1.tar.xz=a0e59495bacc1bceaeec940273fcc6d1505c283de9e2a60ee7d492f2a7efec3d -dist/2025-08-05/rust-std-beta-wasm32-wasip1-threads.tar.gz=4b4eb08ab33ff2a300828c65a9636f32428dfec784bf115aa53856b5336d61d5 -dist/2025-08-05/rust-std-beta-wasm32-wasip1-threads.tar.xz=54ae55557d66f922112a42aa2c296841f5919907ccd81354f0dbe1b0517867f8 -dist/2025-08-05/rust-std-beta-wasm32-wasip2.tar.gz=b625337e6180ec57abbed063de5bf384949254c46a5fbbb12804a3dbd0d1c3a6 -dist/2025-08-05/rust-std-beta-wasm32-wasip2.tar.xz=5a098a042f5586e7e1b7444bf64edf3dcc535d75226fa44be420c0d42b90c25c -dist/2025-08-05/rust-std-beta-wasm32v1-none.tar.gz=b11ed27b745437b39ea9699f7fd5413bdb25019720569b9940f1cbac4849344c -dist/2025-08-05/rust-std-beta-wasm32v1-none.tar.xz=3dd3f07214429f36a088a89c3de7404659d1b584895ff5b7938845fd4a669f27 -dist/2025-08-05/rust-std-beta-x86_64-apple-darwin.tar.gz=14522f13786b81727646acfcb18c81b3f78b24bf522ebaf65adba416971d9939 -dist/2025-08-05/rust-std-beta-x86_64-apple-darwin.tar.xz=b78a1df21a97c25d9977a69bf778190fbf34947c6837f895aeeb53c870083438 -dist/2025-08-05/rust-std-beta-x86_64-apple-ios.tar.gz=a5d57bef3b09c4a4e6789d756cbec9e9459261ab70c94a406d4519eb2da992ec -dist/2025-08-05/rust-std-beta-x86_64-apple-ios.tar.xz=1b461aaf03e808d26bcae49417f04b71ad1432f266f0b25b3d6b26a67b7f8953 -dist/2025-08-05/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=6c7a3326abd3fb7c878af095699164237f97ce5827bd428d8aad5c9818b2098c -dist/2025-08-05/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=427684c9613ce04737837a594987bb1eb81d1d3f5ea2a1b19c2b76b3be32ab62 -dist/2025-08-05/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=2e10607e6eb7fb3168fe593f1d260b52ac578d590cc6788555346cf9bac9f586 -dist/2025-08-05/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=256331077a036bfed1650177cd1a886aeb4ce9aa9ce2a35f5450767f5e06aee6 -dist/2025-08-05/rust-std-beta-x86_64-linux-android.tar.gz=b5943cc4d10bf039d9b52e56713a99e8edb21d9de3655450d16c557c9013f47e -dist/2025-08-05/rust-std-beta-x86_64-linux-android.tar.xz=ceeb89fa082b98c8d50c043cfd2e4bb8ac1d98943859a75d74a555ffda8d0a5d -dist/2025-08-05/rust-std-beta-x86_64-pc-solaris.tar.gz=98d9d51da4b74a2a1899be7f0dd8d3c0f980fb4ce96fddd1c2dedb76e174984b -dist/2025-08-05/rust-std-beta-x86_64-pc-solaris.tar.xz=0fed1f0452475bf10d3ec0bfef12e9fe05bb117910d871f4099bdd4ca947d74b -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=f458eab66adc91aba026a434cab47bbbd98a9d5e7d0f5a1a1979e0e6a89c8e7e -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=bfdc3bb5b66a525281236b01513f49d96d644e4cd62ce89eb59a8179fe4707b0 -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=b543f21106bc3a72d31a5c49118553187cbb0d2e630ea943aa97d3ae5bb4c40f -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=9056c113ee03defb6cd33acbed9829712b57ef3606623169d28416be4110a31a -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=c66ff2e88c79f3fe574f9ef7822d5d2e6f73efe3ebe67c6bd35096622b668d1c -dist/2025-08-05/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=45765252e930a96badbf06eb04ec092bb989c0ce2067aaab52b7ddc72ea511b8 -dist/2025-08-05/rust-std-beta-x86_64-unknown-freebsd.tar.gz=9b3d68e86e0ce6a484bf615313f98bd289db73899a55cecfa5b7955b4b0878f4 -dist/2025-08-05/rust-std-beta-x86_64-unknown-freebsd.tar.xz=bd48292b8582167a5e89ebe521c9754495403968c184b925df8b2ec1da344fc3 -dist/2025-08-05/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=b4c6c046299391beb2f50eff198f4c9b6571b6c1748dd621bdd154694fffce3a -dist/2025-08-05/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=a30857c8f066191b64d7b52378fae8790814a251ca452c80710bd9a49c5c0c85 -dist/2025-08-05/rust-std-beta-x86_64-unknown-illumos.tar.gz=1ee4b264021b510342c2ed96da0dacf5cf1704874de3bf9380642433defb3e0a -dist/2025-08-05/rust-std-beta-x86_64-unknown-illumos.tar.xz=ca431d4426cfba2efd408b8822f9aeb0961d81373c6154a0b7eeb957abebc33b -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=ebba9fa476d5b0a42054a6b6ca51526efd7c2cf5ac34eb8af119bfa69f3f0a5c -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=d4498920cce484a8b3a5cdf8ee856d80cf1379f9782169340dfff2597b530598 -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=20c37745f3ee13c2c81dfc77a80919cc0448180f6be0be56d7fb5239e5651294 -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=dd319a6c381b372ba230d86bd07a089cd2431656c7c765f029e8e10d60bbd778 -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=d0c20b13113eb62c9a78a796418386d0352f4221095de272018af6d5ec6bd9f1 -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=d0e1001e8e5af571f0fd53115ec873091a33e4943dd27a16ccd74dcd8c71abce -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=4be537d5fb6c0d867a131539ef4b0872f9f6d175ba0517fed50b1d463c615157 -dist/2025-08-05/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=ca034c852a4c9099a062f55c5e479bd700f2ffd89a3b2c2c7354df54e41057a8 -dist/2025-08-05/rust-std-beta-x86_64-unknown-netbsd.tar.gz=11b5a73da1f560c218cecf9a71d6b2173df1fbe276e63e20e1e85f2dc48579bf -dist/2025-08-05/rust-std-beta-x86_64-unknown-netbsd.tar.xz=2de6a8850076e9c1edd8aa3e13902ebbc599da9637f88da347858007f8e5c212 -dist/2025-08-05/rust-std-beta-x86_64-unknown-none.tar.gz=dacb8aa48387ad15380a094104bbcfabdcdd5f88e189d9203fd3e3f466b92fa3 -dist/2025-08-05/rust-std-beta-x86_64-unknown-none.tar.xz=ce2eb95efe252de2ecbe619b3805b01ec84863a9b30330dc4ad5683d67d7c9d8 -dist/2025-08-05/rust-std-beta-x86_64-unknown-redox.tar.gz=bf28f90b1b24eabd80da75262bd260ee811ef30a1ba94bdeb7a005f132ceeead -dist/2025-08-05/rust-std-beta-x86_64-unknown-redox.tar.xz=99aa3603b7fdc84893a02e66a774e147439a1cfd77ba63818c58b11ae692058d -dist/2025-08-05/rust-std-beta-x86_64-unknown-uefi.tar.gz=75c57e4a9367a6fbee02f8857da2dd4bce8bd20c8946a3c2460a77cb95af0972 -dist/2025-08-05/rust-std-beta-x86_64-unknown-uefi.tar.xz=552c14c20d1f786c8350882a32618951de0a06e0636fa3b8d69f2ffab7e7561d -dist/2025-08-05/cargo-beta-aarch64-apple-darwin.tar.gz=4723292f91e645d3f86474ed55e52eae4f35af7458602d3da9d38b0a513cfeef -dist/2025-08-05/cargo-beta-aarch64-apple-darwin.tar.xz=d0150ce874376c41950966b0385f011ebbbd5ef4955deec7829d8ccb669e9e86 -dist/2025-08-05/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=fb0a8a8dff4d42f9491ed9a0223a9541bbaf8691c831b5536220494c479b21e3 -dist/2025-08-05/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=6bd35ea43ab877d84bff4b32b965371b942b10c6f6feabb3a5b481a4c84513fc -dist/2025-08-05/cargo-beta-aarch64-pc-windows-msvc.tar.gz=3437221155f338e81f55dea9d715b3958fe7d3a260d77d14725e62d0780bfc76 -dist/2025-08-05/cargo-beta-aarch64-pc-windows-msvc.tar.xz=94886636f7bf805809a8a1ac99b514036c5db1755ccfed61cb6cd01d57d244a3 -dist/2025-08-05/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=7f167793fc72f5fdb6bbed97e96684cfa089f9932d3a64239bc755fe7603e7a3 -dist/2025-08-05/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=1018ea99c4142db9fbf386547dee8396dc27d3d3608085a1b0b0e97e2d0172c7 -dist/2025-08-05/cargo-beta-aarch64-unknown-linux-musl.tar.gz=8e03af7a838e81c12c395ed76151aa6ead12b3e60effa3b0d775508118149058 -dist/2025-08-05/cargo-beta-aarch64-unknown-linux-musl.tar.xz=507de5fbe92e144dd37dc34123ee58b9e46805c85eccd4a759a117020578d742 -dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=263ad4a9ed084dd76b6ea62d377fa470043f78e0343f7fb80d5c9b50659d8977 -dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=ed850f484ee870172b721ab6824f0a15b41dd80ffc623557aa58a5b839d992c5 -dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=afb4cdac4a3c28fe08fbba8b98962eec6c625f6a10a52ee8cc988881852b79dd -dist/2025-08-05/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=7f332d11e74d76efe236a7858021a626d31fb856d9ad0745369b99d9fdfe3b44 -dist/2025-08-05/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=5c0c79bbf734c0ce18001cf27605f6728d83d24bc97ea5c78b423fb9faf46d96 -dist/2025-08-05/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=3aff39ef7b9e8adc2e6bca19c2940287c4e091ad7ce4503c46334e6969ce0c95 -dist/2025-08-05/cargo-beta-i686-pc-windows-gnu.tar.gz=af99a5778ab4c9cea122897bcd3ea1626893156fb71346d66a584553d6531469 -dist/2025-08-05/cargo-beta-i686-pc-windows-gnu.tar.xz=8425eda844728c0353b4c7edc4636141dad265e461addf009cfa1a224df0e7cd -dist/2025-08-05/cargo-beta-i686-pc-windows-msvc.tar.gz=46d1b318b6cf826d8e7e694e54ce5b9c651dc2f8facf32ddebe21fc32e1e8dc4 -dist/2025-08-05/cargo-beta-i686-pc-windows-msvc.tar.xz=bef58a9f31aa3434152f79b2e271958fb07e925c938a569d1c9431f7764d19f1 -dist/2025-08-05/cargo-beta-i686-unknown-linux-gnu.tar.gz=c432ae4d909a21336a6645b85a90ec541818424bb76da16b19979a61a11845b2 -dist/2025-08-05/cargo-beta-i686-unknown-linux-gnu.tar.xz=053c02b341219d583caba881e525eae2cbb125ecc188e1b43d641fd7f3f027f2 -dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=40542d76adaebdbc3fb16047a8324d439abba0485d227253614beddcc3cee2dd -dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=d25210467dabf91917eefad9a5a415a3912a31b37ce1fd3d755b6c72b3a6ce8a -dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=09755de73380c39daf64208df9708613ed6f8790e2f5cf79e80cb7826fd74f28 -dist/2025-08-05/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e8eab1aa5b41c04b518d43a86849307cbfec76df13c834a460c546ab6b170089 -dist/2025-08-05/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=93398391d308bd0c08fa2a7bab7bb6a38b78400280cbe765604a3da9d6caeb47 -dist/2025-08-05/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=ed37a7c5a8c62db06e709779b81d1e013975feeb82c185c76bb3d218aa142cc4 -dist/2025-08-05/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=a398b3ff0967b1ec2fdc2716a6b2c3a04defc14ebed577d93e45040aa5552dc8 -dist/2025-08-05/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=51d6a1a3e71713157a4e6291023b8393e21334a952a947f82f9636a725989281 -dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=cef935747fe5205c3c5944f4dcf80e3111d2859616e7d727b8a5c77abe2d9fef -dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=fcb8aee743adcc3796b564570e0ad6d9950031160ba9a6cafbd92af2f0a0c213 -dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=73b2c9676122e842a73a8a9890f1e1aac426f75449a99b4fc0ae3f5dd5ce238e -dist/2025-08-05/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=ba293bb860349ee4732c5363d38b5e386544a25f65ef8ee33850061bc84bfe64 -dist/2025-08-05/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=bff3ac251a42b1664a544706185826a4d9137cde990620dc73951252d2d7fb41 -dist/2025-08-05/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=61056d4405af01b4b1c3134af8e83ed86473d0846beb41d3ab72df92edf316a6 -dist/2025-08-05/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f89a30322a3621c4737f932788f4ca78c83b9f2845e324c4944522f35d44baf1 -dist/2025-08-05/cargo-beta-s390x-unknown-linux-gnu.tar.xz=394d522c9553182cf5f496e2b5324499c1845c0a0621fa527aaa925946b58d21 -dist/2025-08-05/cargo-beta-sparcv9-sun-solaris.tar.gz=0b18adbb22b34448576e6a3ba637c7565d369e1c994474337bed48b3cd0b0231 -dist/2025-08-05/cargo-beta-sparcv9-sun-solaris.tar.xz=c57709b87524d29661f77df3e3585bae4776fb3fb6de3874edb942f724543a89 -dist/2025-08-05/cargo-beta-x86_64-apple-darwin.tar.gz=c8faf66575d43fcbc03376225ac22d571def08ed1fc239d468c15929d9ecd393 -dist/2025-08-05/cargo-beta-x86_64-apple-darwin.tar.xz=538d81c3fe2b5a9edfc1e99655120d37fa159dcf761e1ddbe5233115e39b38b1 -dist/2025-08-05/cargo-beta-x86_64-pc-solaris.tar.gz=a2fb63b0a2cc3d3ea9523c8ffe61ba9ccb367dff136e6fc39aeea6400034363c -dist/2025-08-05/cargo-beta-x86_64-pc-solaris.tar.xz=02e8990865ef8f14a31e4d0f17be4cc0cbecda7e82e062b4b9cfdb99dd45156d -dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ba86f300cd40cb3cb23ac41970246ce54c03ee153f86127a379fecda930c020b -dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnu.tar.xz=3bc0bf2da392ac52bcf2aa1dc19bea1a86bd7a4fe246feaae862a792c82ec476 -dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=68a2a34e656395fabd42d20b7008d96b2a86e9a47caa52e6e2613ccb3b1b2d8f -dist/2025-08-05/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=1e2e31fe2306e26bfe58c49a99cc89664e8a7857c2c18ad74c20cdb35bd3c586 -dist/2025-08-05/cargo-beta-x86_64-pc-windows-msvc.tar.gz=5fa21f665aa40fab1896bd4a49dc5608b4b453d26f4b975771908634c699ab8e -dist/2025-08-05/cargo-beta-x86_64-pc-windows-msvc.tar.xz=adc5900506d399246960445c1e2d59f0c4b2a5cfeff9972f1617de030ce82bfa -dist/2025-08-05/cargo-beta-x86_64-unknown-freebsd.tar.gz=a2bbb1d5fa283e77ddbbc0c8d69e36b9c2bbb01912f302f522af48c2187327b3 -dist/2025-08-05/cargo-beta-x86_64-unknown-freebsd.tar.xz=11e1a51740a728f5825364a8679b28454a68e7efc96320730f9b58a8fc2e6fae -dist/2025-08-05/cargo-beta-x86_64-unknown-illumos.tar.gz=9993f4130b5ce50898e530e7411efe6923a36b5d56459ab672b1395717fe69bb -dist/2025-08-05/cargo-beta-x86_64-unknown-illumos.tar.xz=0a41315ced9f4fdce9c1877a4c27e5cca6e494f5dc8c2560334a5b75d42f495e -dist/2025-08-05/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=6b8f74b1c850093acb7227306caaed4581d70d015ebb0bb5f924af1c8bee7bd1 -dist/2025-08-05/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=f6f7bb4e4f1156329946d83bad5893e508645dd76b9ce522a53ea673791da006 -dist/2025-08-05/cargo-beta-x86_64-unknown-linux-musl.tar.gz=68c829663d6166661563704e25a6e85a973705e12efc9265a23264b9ffbff4d7 -dist/2025-08-05/cargo-beta-x86_64-unknown-linux-musl.tar.xz=2c40e68c9978e58250f0e017b5cdb2fc390f26ef96324129c489f55898784488 -dist/2025-08-05/cargo-beta-x86_64-unknown-netbsd.tar.gz=65166585138bc6f09f54f88ee889aea6d4e63019d64a684798341d6b332ce99d -dist/2025-08-05/cargo-beta-x86_64-unknown-netbsd.tar.xz=97491edef98b3a13b0571907555bf5867be13ec8fd4af69142db92a8deaf8586 -dist/2025-08-05/clippy-beta-aarch64-apple-darwin.tar.gz=b933611d47ccbcf5aad43f1134cc72ac708fdf59bace0dab75cfe139e2357373 -dist/2025-08-05/clippy-beta-aarch64-apple-darwin.tar.xz=c3d473e366db3b271cbe438b3a5531e9c5a72e28248d94de0f81ee93a8a2e7cd -dist/2025-08-05/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=e5b4fc054121eb13b21171b2e851dc1c824e11aad1257dc92b4ca9e332898b40 -dist/2025-08-05/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=40bddcdd9186cfb9f8763e8e289087c15c2c8b8ab78f41ba7380cdb08fedb0da -dist/2025-08-05/clippy-beta-aarch64-pc-windows-msvc.tar.gz=7e7c47305708ae073ed8d86e621a3c0be0e135b2480508814665f24121588a56 -dist/2025-08-05/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c4a5bfe2d48a2301adb4f7524cccd64f4a3ccecf985f131972a13bd221346454 -dist/2025-08-05/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=dd26d49359f6010e94e04198067f83c83e81618546d1cf51606d157a02b4938f -dist/2025-08-05/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=e7c9834067311a87f547450108718582991498a102dfcba0e1a99671205e9bc2 -dist/2025-08-05/clippy-beta-aarch64-unknown-linux-musl.tar.gz=b584c26e267b0f7e105f65c436c12cfd6d9b8f2b92f9662a4797fa5e95455e11 -dist/2025-08-05/clippy-beta-aarch64-unknown-linux-musl.tar.xz=6b0eaadfea879cfc8c758fce002ffe77e34484e167c496ac0659dcc789dfc080 -dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=eebd0632971888cb3bcc3b07a06f25a47af594ce5606e8e1e069fe85ec702e5c -dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=946d6791e4e15ffca6195bd7c9bd2d160b9c65468fddc800948f41adc8fec597 -dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=3862815aa14e8122b70b39c1137088e0c2a724900d2d13ac2b37a1a430b23a1f -dist/2025-08-05/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=8278e11b7ea2bc035e6de21f826a775d66273a9031195d8b887752137424f2e0 -dist/2025-08-05/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=83a847698eeafcbd3288d59013157d3d2a11b90b521ebadf1b26dac90877d11f -dist/2025-08-05/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=308de9cedc422c2051661df74024ab26c59b86368fbf50ce4dd7b2b2907ccc8f -dist/2025-08-05/clippy-beta-i686-pc-windows-gnu.tar.gz=95fe71a1f8e68f0f3a5306dfa04e269c636ad036908e201c1b4ed7a3f99b1dc7 -dist/2025-08-05/clippy-beta-i686-pc-windows-gnu.tar.xz=5b8c928be909433fb005498a92d2fb3ff535f31c68a5e134523f9731cacb029a -dist/2025-08-05/clippy-beta-i686-pc-windows-msvc.tar.gz=d736ec4f447f6b204f250b044b406b4e4b96f014887b6f7755b037e211aad3af -dist/2025-08-05/clippy-beta-i686-pc-windows-msvc.tar.xz=8a4ac568284aabb994964323465c7287715d3dd4ab881271a4746d2ae5390ffc -dist/2025-08-05/clippy-beta-i686-unknown-linux-gnu.tar.gz=d8b87338abdb4123eb25dd778d038c516c5bd472e1426b5a5f74f25126957039 -dist/2025-08-05/clippy-beta-i686-unknown-linux-gnu.tar.xz=ebb6dcc1b038deff6a966062ca3a966d3426f8932e5aeba398636a2d2e9be0c0 -dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=51bf4e84be5b677ad9afba442d9567b96f59209219cddad5eb3f49b788bd8fe2 -dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=e63e3346089c7f300bdc73521def20cd2a012f8de98b8b05a653e85f3516371c -dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=aeb3782ca34a0ac47420109c241041ebbc029050a690a5c828c865108f56ca18 -dist/2025-08-05/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=80dabbd511bd5bdfc944d7613a02c9bdac702abf2de916222a37e59a92c2e577 -dist/2025-08-05/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=9307396973615663330474ec145efebd4246c6bae5d979a80b6d93f832af0137 -dist/2025-08-05/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=fb2a34f9472d2c1beb1381e9ff8bca23d9058c978fdb2e52a3c7f0cba8305c59 -dist/2025-08-05/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=e985eebd182d78604861ce60aba5078e98a9a078b76752da8fabcfc5fa471fc3 -dist/2025-08-05/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=1092ddf60ba04418f91c1e51f9c9da1e0d6b61dbdb104fc8028043dc1a33caec -dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=bf0238a4909fa15034f067d5a51e38e43c91e69f29f51c39246d5c0b23925042 -dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=39caa6aedcd746ed1c4745e207cf8cd65de7b774f15e8892987ce2c3fdde543e -dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=b19ef1a8cdc21925887ced0c594ff5ab658bf66a0d137c01b6375fcdd0de8e35 -dist/2025-08-05/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=0ec300c1e791f946503db692e602680acf11857715b9ecc87cb446ac10d2527c -dist/2025-08-05/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=e7c8fe214ffd70599648cfacb50b3457597b479d320bf8383869dda8b0559d42 -dist/2025-08-05/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=d8ba0c42074c2a94dff3b05f2388f17225044485abd0459e155928f4762c8988 -dist/2025-08-05/clippy-beta-s390x-unknown-linux-gnu.tar.gz=510b9c9ca885a8e91c3d25f14cbfb34a7a927d374fa1a9149678d7ed9c4e4c2c -dist/2025-08-05/clippy-beta-s390x-unknown-linux-gnu.tar.xz=b53697799d99beb46fc17b3cca8ccfdc4ecbf7f3e1fd47f031852f07fb749ea0 -dist/2025-08-05/clippy-beta-sparcv9-sun-solaris.tar.gz=f3109a1dd87c23256057fcc94d3fade0b49d20a51040b4fbdda366f5b7c9b58e -dist/2025-08-05/clippy-beta-sparcv9-sun-solaris.tar.xz=ba265d781254d0b032d836a440c94c31ca33bc136e027ad05332cfc0cf40bf54 -dist/2025-08-05/clippy-beta-x86_64-apple-darwin.tar.gz=74c49a7cd4b6605b9a43961415fcaed1197b8f5aca798efd4b62a15d837b956b -dist/2025-08-05/clippy-beta-x86_64-apple-darwin.tar.xz=69128daabb11fd29720752bb13d83ef4bb3faa1d4aea8d525da2cb04f42b6010 -dist/2025-08-05/clippy-beta-x86_64-pc-solaris.tar.gz=e1975507778e448ac9b3040f330340f3a7d54e6dd40357494e3d891008375364 -dist/2025-08-05/clippy-beta-x86_64-pc-solaris.tar.xz=43c142c870116f4c2408f4b3208680b81390a4b37805f5a32696ad17bb313b48 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnu.tar.gz=ccd8806b6614edb270a2816cf0dc3b6376046fe58d258d296ffb222929d42d91 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnu.tar.xz=21148cd754493da3cdf72adc8da19ebfca1da8d642e1bef51782772241b48084 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=5a7cecb6c054a71ec5b1fb284f6bf2c069925fffcc1757ac631e8a2d08b116b0 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=b451057a4a75341924072fe26334eefce8b6eaa3edd79d3226eb02c1c99fcdb3 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-msvc.tar.gz=74e9cea693203c6217934549694a240460dda2818b144bac5777f41c44a06d53 -dist/2025-08-05/clippy-beta-x86_64-pc-windows-msvc.tar.xz=bd90fc3fc80f28ce415dc1cfd105d17ec5ecfc63fae017baeec734bf94f5d71b -dist/2025-08-05/clippy-beta-x86_64-unknown-freebsd.tar.gz=fb61d60d6c66a4632911944b5c7858b8c055ab8ae5a194d78e7d7ba18b65e940 -dist/2025-08-05/clippy-beta-x86_64-unknown-freebsd.tar.xz=bbc7b2aa6f05ecf391a757ffc5b6fa6e0989d00f7e8fa48b83faca8996f99dd1 -dist/2025-08-05/clippy-beta-x86_64-unknown-illumos.tar.gz=10e8be6eb15269cb2d0573e19e3a5004dbbd2b14e2f016d6b9c60713e22f716b -dist/2025-08-05/clippy-beta-x86_64-unknown-illumos.tar.xz=c3748db93829d3f5d9c5498592d247468125ca301ef238c41e42d37b7b90c6a4 -dist/2025-08-05/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=5a0365eda14ac1a366f3c480a2358eccbfcbfce86323711d7fcfdcfd85652b42 -dist/2025-08-05/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=908576635e79fe589583f18bd6ace4c488cd11ed0c59501082bb0b397df24f39 -dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.gz=79fd42cffac98024308c511144b716d18693b902dbdc1c4b88645bc7d4ae7109 -dist/2025-08-05/clippy-beta-x86_64-unknown-linux-musl.tar.xz=a3a616554ed25630df9f8cef37a5d36573e6f722b1f6b4220ff4885e2d3a60de -dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.gz=ad1849cb72ccfd52ba17a34d90f65226726e5044f7ffbe975c74f23643d87d98 -dist/2025-08-05/clippy-beta-x86_64-unknown-netbsd.tar.xz=608001728598164e234f176d0c6cfe7317dde27fb4cbb8ad1c2452289e83bf30 -dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.gz=6fd7eece7221e76c2596e0472e7311fdced87e9fab26d2a4673a3242fe779bd3 -dist/2025-09-05/rustfmt-nightly-aarch64-apple-darwin.tar.xz=1a662a55931f58be9ac05841360305f277f8b1e36f99bd0a2ee4d2cc92b7ad14 -dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d1c3c52cf61522697d726b32ed28d7b8b4cfadf30ec57f242e8c7f9f8e09f692 -dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=2cc7cbbfa06803a2fe422ed3266f6eb519360b403c83f92259cc1b83f5ddca45 -dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=61f525d050d1ff4a29cc7240912d84c9c091f25195b58411af9ef176175a3200 -dist/2025-09-05/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=504b8ace2ab7ac13be143d95ed74d94940e8706ef9f53b7778da215840337e20 -dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=ff48bd98d109310638822f5813042583900e2b70edd45fccd871c7c03dd1c2e6 -dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=b3de2bba7858e76cdafd326f3072e4c5b534ca9b679ea62caeffb07722e9a3c9 -dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ca4caedc50f09995dad7bc6e001cc863c524e28c45c186022ded589f3728709 -dist/2025-09-05/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=8f2cfb052f9697052d89bb729d17d74583af3fa0be98f18a3c44ea518a8f4855 -dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=b12ac2a38b379bf0de4a92f29ca40e1955c45273e798edd1a72bd40253de70f1 -dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=87fb7185aa46f3810e09479dc8fafb66d13b41f4f40e9c4e866ea77fa47b1bb6 -dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=be1e8377f3d10f4f8a07ae06ab9f649f9d2fc9cfc395abaa5f0ad10a95c4fe7a -dist/2025-09-05/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=60646799fdacdafec9e0ed81357b5db70f85bb1241fe775e71b8ad3feb686116 -dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=ed8cade9b846efb5ac121aa70ac188fbd2e61fa9402fe68c80b2cbd3ee32ccbd -dist/2025-09-05/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=0d0bfbd9cd4123e0404fe476a6f16eec6e435ce28d328dc0dd0aad257b295d64 -dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=bd411db34707c36d5b60f14bba776b0b89b69d4266007a3b591c467a17ef053c -dist/2025-09-05/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=f0f2a6a81177ae6d06ff9b8f4a5bdf3bc8b26710aaf0f09258b32f7f710722c0 -dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=b49130da444e01fe4ef997b649aada8978b8dcca60dd38cf9e7400a7c7569e1b -dist/2025-09-05/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=0195cdddc74cba2bf17eaa1d53edb1a2bc0e34cdf13c7b25a34ad9729a2635b8 -dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=1141897495ddca10fd6d9476a624b6a340fc2bfc619148e183bcf355a0078b18 -dist/2025-09-05/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=81b31bc8b3d431120005c3c8eeff3ed194dd18e56220c175c3250855cbdcddbe -dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=10a27070239e7dfcf701669c8d93ecb2d310b9fde768639a2bf5be62cd13528d -dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=0ac4a529f4f62a94d5ae4cc8a4a52f0e7d57296ac0884258dcc5478e6b0b1785 -dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=9d0ed6778fc4f0601be1e317438cf95c414fcab6d3207c635babb4f3a6faf2b0 -dist/2025-09-05/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=e40b607faf2f37c9d654cc0b60c47ea155893a3b62236cd66728f68665becb18 -dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=46c029ebbfa35972b0b9e366d17c41ff8e278e01ce12634d5e3146cbf6d1a32e -dist/2025-09-05/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=8d1462fd09b04a94bfb1c1841c522430b644961995bf0e19e7c8fa150628e7c7 -dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=5827684ccb4d38956e77858ddeadeaff2d92905c67093207bed0f38202268151 -dist/2025-09-05/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=975c7d7beb5b66caed7d507aaec092fdf33de2308f4dc7de46fe74e5e15b5352 -dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=8829677ab0f898c98badf22dad61094cf53c6d599b2cc76142d3d792a44f3770 -dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3d961bead4010f8a488a065ac8a4153e3c747dfcd7d5f7eeba1cad00767a7ac5 -dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=0138c30ebe74e8ee838d9eef31c7882812bb52d2304f2de7c23c47dedd6a5032 -dist/2025-09-05/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=bdb4b7b3c89a30c79f51b5fa33a2a29fc8313f8193bc43ee611e8ce7d80382d2 -dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=8e440dd400bf3eb4a144318459e111069a64bb309a5a51eeb0f0383dc48ee55f -dist/2025-09-05/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=f623e1d7d38d94965d7653fdf4a272630b2b6dec81662fbbe5d2573f2f3f3b8f -dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=f46a8278352d5a981c6746b876fe19df3093090a866d20d24cd5cb081136b1c0 -dist/2025-09-05/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=fdf8b44c6f110a33ad7f969e651ad396c880a85545aadfee8a24ca3cbed35974 -dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=59d778dea354867d64c809b40443ca0762c685dd0e5361971daab04aa7c5a5ad -dist/2025-09-05/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=18628b2888d77281fc9b2ac5636ce4ec444ab0e47bbe0e8a08238f90040c20a3 -dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.gz=169d9f2ee4a0c726040f4940370d1162502aa6568a0a442c92cad3fbc7bd95c2 -dist/2025-09-05/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7f955cfa1ab07819f31cd904b0a79c67cae70090aabc7dafffdc1f3f67463248 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.gz=d2cc32d6be1d0f1a8654400f0418d16e789b62db3fbc0cca0d0d492615bcf6e2 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-solaris.tar.xz=3dbc29c923a6a2809a8ef561d2ad375211b09dcb107bceabbf510ab0d7b471f0 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=d9b4ca2abf1062e888b31f31f517ccc6b451bd2bfdae915ec3984bc88a8be91a -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=00c6d92b6e82ae58e682e72c974f2dcc865820567ba44ed008e4759dfdbdca87 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e75424d0aece8d548b2c9d896291288615d08ff2a37f1c4844a70839c612e633 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=cce9578d9b35bd8192a26e2dc7d7f7e7d5b9f08c7d73b3f4dde08208b448b063 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=ac4282e06b0972033f974c63d2c6cbf194d4e66a1c811f443d3fa0b886868825 -dist/2025-09-05/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=a2465b31855861d0e0eea072bb366480acf2bafdd7fdfdab79c809d8bbf8d8e4 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=30c22a97066a5711f207c1919a1d74a328540da0d9d6f85a0cc044174049c927 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=40987da0b665940f9c406cfbb4889dc101d73846730b0bdfa1382d051297ad08 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=443ba10092122fbba9854abb4aa9d2e71d8e5e65b99fae6dd572909bf50f28c5 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=10285942b9140efc9897965cb3a4204145e774bd1b0c2690d45d8b04498fb917 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=b09af4fe367df416bce622654d9e3dfb610c564f5e6d14b200d949340595673c -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=1f9a585a017cee5a05190377cab105603f039fbefd9b4934278dc555dfca91b0 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=24f911745fcc9f120e44acccb98f54dc6406e492915410aae17efdd00e2752c3 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=48eb58ba1d58701dbff341e19fb6d446ed937cc410207b35297babafa29dd889 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=c2d1cfdcd8a08bde3f9a635eaf2d6d2fbd82e4cabbbd459e3c47e64bf1581f11 -dist/2025-09-05/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=ed1775b4fd3d7d1203f8749f70328ea4ade802fa0a76c4d7ab3e2d63ca1535af -dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.gz=4b64c4148e5cdd6585a4200125cc394c6a998da3686ef758f37742ec2d33d573 -dist/2025-09-05/rustc-nightly-aarch64-apple-darwin.tar.xz=fd45182f9db059bdc17f2c465dbaae22589eb8e8d2d88776437a34ddca3b7153 -dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=c14f2d7f391492d150f2f2f91af413266649cbdbdb042fc8b660b3cb141b80c7 -dist/2025-09-05/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=d72ea1c571fe2376ef05cfd15fb3207ee2d27c3c851f3391dfbb082c06a5bdd0 -dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=3a485d8fd8d58fdfbc1216e51414aa4d90f0c7285a99abea0fa5935d2337251b -dist/2025-09-05/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=7317060a29eecd2e28d47f0ff8780150059756b07e2bc9137c3877be8af593b7 -dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=58a53ae147de1beb0a53629898bf7c51097351271be3713a2e2344b86a4080a4 -dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=f79d2730843dbea9e9588fd1c1b0d854441969d8f93f76021f06af2efe22b845 -dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=eddf23e28b8067021e80883faf2eb1d6d3005a6e8419a1232b84236bea286f78 -dist/2025-09-05/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=4f0af1a66050f5e2d9d48b696349b9ccd420bdcfdb88b251a6655cc22a11949b -dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=fd2f0446e3c993d746e8a5f72ccebd8b0a49172316ac1d1c58bad10596becbf3 -dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=0b06e7ba47621819b4e59e048e5d336b3d6978e906c7363f06bbc804e49f1046 -dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=97d7c34b53628f28e6636fae738a18d0f1f4c60a9febddfb7145e6b91fcf3fdc -dist/2025-09-05/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=323025215bf851024a7eb6566ad7dc5719832d81e8d46e70adaece98adc5644b -dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3017e03222d030448ffe2805624143540197bd6d3b3e93f9f73469ace25ae4be -dist/2025-09-05/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=4f6e86b185fb54f7a0b7d09a0faae7daac722351354f6abebd388efb3037dfa0 -dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.gz=292c3770b96cde97072d70c58234488f955ed5582b7c3044c6de66891e73d639 -dist/2025-09-05/rustc-nightly-i686-pc-windows-gnu.tar.xz=6855d3fd9040fb4da554fd732eaf8a1c723921c35bb8a8efb31c78af69b2e4ec -dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.gz=64a86a2971ed9934bbb6aaa0afc2a7f747da463afb55b51a7c5fdbdaa294e437 -dist/2025-09-05/rustc-nightly-i686-pc-windows-msvc.tar.xz=c98f1fc3e077b8c8eb3e526c416a6551c08c62e58be57b4a4c7d59670bc435f9 -dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.gz=5481c97d788899f896473380dde0877808489bc4a0ed6d98265558631fa67a57 -dist/2025-09-05/rustc-nightly-i686-unknown-linux-gnu.tar.xz=afadaae945c0b9a8b50dbdee28791e0c03c880cb22d3c20996eeb7fab94df0bf -dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=18b276a2464b6c5a817d72384f25442c7619cac05b2d8d0af212c0dad96ccfc6 -dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b74323cd2dbee966eebe8e63e24fae026ecd900a025e9167cca0341e50333cc3 -dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=916dc5144107d9173479b320b55b0a95d2d42156c69fbdb0f21377d825fe0892 -dist/2025-09-05/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=3a83da72aa4a6553ecd957af35a05274528dc79f87d24d8470c20b8b4478b05b -dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=59e031b6b79a1f11406c0640e1a357f2941967ea8c034a94148d60928038e58e -dist/2025-09-05/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=53f0e33cf2651d5dc8931ec5af8f04994188d8f9a10a5c61bd72cc822df34501 -dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=0eec56e3b725d918cb21e494a803b2e38eb6d744f64f1a82481a4c704eb7c1f0 -dist/2025-09-05/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=5efc97abb235f349c6cc952b4a1e4dae7d56d70b0f8b8da2a1060b85f9b734fd -dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=cb45bbcdf8841b1ac184a0aacc909f153c830e8051260e09ca4e32c1f048e2fb -dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=1c9ddddb90d45612e4fd190fb71e527b523df13146343dde200580fb2b638794 -dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=3a9bdd4d14e8f121d3051944ee83a901b5ca4c0921f2d01e34596fb7450b49e3 -dist/2025-09-05/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=732b9abb8a80191884fe1ff1d4d923cc1b74c21b81e6327bc5979ae526337400 -dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=1826e74200fe286478e1659ab88ea86b43efa7b023074d00dbc814d80bebc883 -dist/2025-09-05/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=c30b52d0f474fd6193bb1b3e147fb79fa8cc31e5db38444f023d84d1c2d93d12 -dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=c330067621ed25d8383f27e494346eca4d7d4866e48f331f2ec897ff1c386e56 -dist/2025-09-05/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=cb4097ea582a83a94cab80ff2f36b6f7141c140d75c30b1d261a1ddd4ea45bd4 -dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.gz=0af19e764f10333017a3ab66020b82c7185ad648d1230b68f10977e0affb937f -dist/2025-09-05/rustc-nightly-sparcv9-sun-solaris.tar.xz=a22cfb55cdd122dd99bf3566eabd781bb2ecded90c71a41fd33b1e0588bcc39c -dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.gz=163a07b91e36e85c6c41368598793667414cdc6cadc980866811234539f3aec3 -dist/2025-09-05/rustc-nightly-x86_64-apple-darwin.tar.xz=76711800685b39b3b75945395682062c40efe3195f9979784bf318837e21768a -dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.gz=69142a6c04703c3c8309c6fdf66b25831bf9efa3ee70cc93da4b5b75f901b29a -dist/2025-09-05/rustc-nightly-x86_64-pc-solaris.tar.xz=7e535f4aa136284e4bdfd4d56891caac6844dab91e1b711fa3914a5974dfcb60 -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=ff0ea563126ff28df297258001d9fac4dbd85788b5d27a0f5d6be75306f21139 -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=6b66adcaa9a5332979591464242423897f59276e9e2cbeb9ab038a72e72c3a5c -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=64cac5e377bc115a8f8176719575903e695337941db43cfb35546d65c0723130 -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=11e2765e4b3e2296ea05ecf735cf7b5f7beb08d76d12449cfae67f88bab02819 -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=c7d15ae7cd5af774ae70e63fec3ba8723b85fa4c4640917b3960907eedb30b39 -dist/2025-09-05/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=55036567af270cdac046fb4306e515787ca6ef5073617311fac79fb87ffe9366 -dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.gz=2d24470d2bb4c4d2605c15f1b2654cc45805384babb73b1960e8aea0b8cc227d -dist/2025-09-05/rustc-nightly-x86_64-unknown-freebsd.tar.xz=fa41782cb2e22aba30d1619db1f478c0305944ceb4de1d1001f221c5c68c104e -dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.gz=d0f9785f76c59f3a67a499cfff4a5639f3ae05cbc76750b867faaa60b7d67f78 -dist/2025-09-05/rustc-nightly-x86_64-unknown-illumos.tar.xz=925e473c6e31d8811879a805358cfd2e5ab8f4de836c270d02dc8403771bed3a -dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ebac845114b89dfe7d0efc0cfe8820902faad617ed21eb2a701d73cf7b544a85 -dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2512a5462e3f46c95ed4aba4228282a357b3e0694e9db117a857196448fe7bcc -dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b4a5d364b84464e9a92140fff50349d4942b8d970b64150a4bc6d720cc6c4a4e -dist/2025-09-05/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=6c57c2edc305737530f8551d789ee79ff952f42a0d52d6f8d7d7f1ea2027cfca -dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.gz=f3192ded327875d5a27fb50c690e3fce36669e8f71c47de304dc21edad573ff9 -dist/2025-09-05/rustc-nightly-x86_64-unknown-netbsd.tar.xz=11359e4731866f6a788e5699867e45befdf1ad49ef35c0aba22af76d3f327cc3 +dist/2025-09-16/rustc-beta-aarch64-apple-darwin.tar.gz=3e3fbcf51f2632b8890b38537ea5446147b85fd62b21798b4fb2a032a4abd6c9 +dist/2025-09-16/rustc-beta-aarch64-apple-darwin.tar.xz=296ef2ae4dc8b4f411423a4384821e5b8e305be809b55522a0f02c97b83ce14a +dist/2025-09-16/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=fe7026f1310a84f3490d0ffb8476bddc36992fcb2d7e450c036aae6bbbb218ef +dist/2025-09-16/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=70bd356d7f39ff1ef8511941671caae84f43d3a9ab493ed131467d27bf5c53f1 +dist/2025-09-16/rustc-beta-aarch64-pc-windows-msvc.tar.gz=9b0f42d2713c20d1df9e401410f874f04ffbff2e0c61d19d2f8689d4e55da562 +dist/2025-09-16/rustc-beta-aarch64-pc-windows-msvc.tar.xz=086ff4c532289581325b1cb5c629f899418dd392249d3c0bd2137a0d73ebccca +dist/2025-09-16/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=4860148593cc5f5662cb89c9484d71af472223b8a9f9644e6709802154e7d02d +dist/2025-09-16/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=a7f290455c134c72518267e7dfc5a51d550497ffcf539dac3b41c57486e1d370 +dist/2025-09-16/rustc-beta-aarch64-unknown-linux-musl.tar.gz=7a17d7a65ca7c933de8829e5991f991d917df7007c122fc55d64efa0fe53344a +dist/2025-09-16/rustc-beta-aarch64-unknown-linux-musl.tar.xz=6ab69fc25888475048dc5eac7adc7f6b02295dc7de7d0e92aad5ff562c500322 +dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=00ff0a967ee41642e6b316b190485a7d04c6749ff571e55cf73548b0e7d74b05 +dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=ce2c11e633e367544a70b0a3ad998a2d680277e62ece3eacbf350fa1ada6332a +dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=ded847d958f0417fba13e71ded42cee387387076b4426b2f2002d53dd998c27c +dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=54ee1d25f57db5d1c2b153533362ecb7fd326b8dd46b8240367ea865a059ca68 +dist/2025-09-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=8f964d41f6608ba04d2d84f5532a057654f3f328b19bc6ee4b9a88f6f64dcec7 +dist/2025-09-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=b6a34332cb027345f54f75e03cee1c65345e8671df081e8dd23111d2233bf6e6 +dist/2025-09-16/rustc-beta-i686-pc-windows-gnu.tar.gz=760c5f1bc081a14b4df2e0c6a1ce80d96b63e15e0b751cfe535eb5775aa9e34b +dist/2025-09-16/rustc-beta-i686-pc-windows-gnu.tar.xz=4376609352714e1e30a4b0c57fe43beb2b0edccda412e18e11c3b8b3092a87d0 +dist/2025-09-16/rustc-beta-i686-pc-windows-msvc.tar.gz=3d0f08e30f4ae2cb513548f66cc6405ba0c2cc74e826c04cf0bdad3d3c14bcfa +dist/2025-09-16/rustc-beta-i686-pc-windows-msvc.tar.xz=a68b01fb491496bb2b8861af9b900a2960f4ea9f64f0946caa09c043ecb3df2f +dist/2025-09-16/rustc-beta-i686-unknown-linux-gnu.tar.gz=3b56ab8e485b3e4bd5c0f1e1ff30389acb9d0d0e0662ff834fb3a855157c965a +dist/2025-09-16/rustc-beta-i686-unknown-linux-gnu.tar.xz=fe871e45e0d987dcaa6a30df8394c54da0204965686a089d6903fff75b8a01e5 +dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=71d53cb70f1962379614c86b07fdea7c1b343587a56734d39aa7de29667d6629 +dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=658f204ab2536ad3b56f238c55c5c6cf3bd7794aceff379f0f5492d28841b5bc +dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=0fe154b5b305259a36b80b9b53894336ceba1562155c05cf92debc5d7bb7e645 +dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=27357f4331d5c357a7b20002571276e2d77e58384095fd3a6910d44a0d85aa87 +dist/2025-09-16/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=bf87cb1717fad96abbb86091c44de6bdeed2bd60437ffa9037d27dda1c71cdbe +dist/2025-09-16/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=778d126b47dc5ef07085c5c760399130219cda6221f6f4ec57c26ebdd7e33299 +dist/2025-09-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=eae03019370901fb49b708c76d001ec9e3df27e7fa1ea9ceb2200640e9d6dfea +dist/2025-09-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=61c1b21acc668bdf36cbf64f2b53348d997ffc9997c6ad282d10226e86740044 +dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=057eb2050b31110529a80e27c6df0c95a14bb1f7c568b487dd3a718755a74d27 +dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=cb3078b44dbb6793ac98a28bd6bd7076c28ae13c5ddd1aa02310ec89130b6575 +dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=9a5109124546788b802be36d9415bf0d5bfcc087389156c65a2e30672e10e7b1 +dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=6987de797339aa2f231485897b0a498a841a49f1d0b83fa7e98c0a76767cbe44 +dist/2025-09-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=17cd423d53f6d8fe53dff7abada43d545a2de14136eae7cd02b958f9fe93f5a0 +dist/2025-09-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=740945fe14eeea917d64ff47e997ca17be1e0f14dca30632a9fbfb560405b040 +dist/2025-09-16/rustc-beta-s390x-unknown-linux-gnu.tar.gz=52e15e3a56a16b2989b34f0a051ff06fb8dd51be3e6874c41a4ba1e2128d35ff +dist/2025-09-16/rustc-beta-s390x-unknown-linux-gnu.tar.xz=6f998aede2a805d8159f2ea63dda76a7d25eb9cdbd26863394aacfa6d80de084 +dist/2025-09-16/rustc-beta-sparcv9-sun-solaris.tar.gz=45c85ec3de0a773b2c2f4b624abe28c3a906020e1ce6ceded75c0099a1fc1899 +dist/2025-09-16/rustc-beta-sparcv9-sun-solaris.tar.xz=d811ff717ebc59aa9bc5c26ee4b8dcfdb3d2f5a1759179eccf549c8a765fb3dd +dist/2025-09-16/rustc-beta-x86_64-apple-darwin.tar.gz=d31302c29a9efe362d2be87b83b229d5369b2462cea133f9b1b4c7c4cf0f26dd +dist/2025-09-16/rustc-beta-x86_64-apple-darwin.tar.xz=b8f9f0b2e4c681da9bf7fbac2fc22ec2f44c136b368821bfea5a5ab29d85527a +dist/2025-09-16/rustc-beta-x86_64-pc-solaris.tar.gz=498902a6de8cae1494aae6223604381c4e109a38c14649f6e27b075d3f26a685 +dist/2025-09-16/rustc-beta-x86_64-pc-solaris.tar.xz=1cfaeae163fcd4dd2ff44a80c245012576ecb4257d7d763a51f2d7e58878a29b +dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnu.tar.gz=d4c6fa5158c83500d30ef44e129889408dbc49ec862c985a1c36820d3550e94d +dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnu.tar.xz=17bd90bfd6603b24d26397acac55e4b2c23b0dc574834de7bc1f8c2c720aab97 +dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=d270c52fec5ef2e9f009cc3e697b6188320fbeb5445092c7a11af67e520cc9f0 +dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=81f91fc07821af63606268821a039578a7c9b09b8c0e96b85163831fee92e6a5 +dist/2025-09-16/rustc-beta-x86_64-pc-windows-msvc.tar.gz=233356bbd9a46168663752d7dcab67e7ae3ae732fab410bc8adb84230e22398f +dist/2025-09-16/rustc-beta-x86_64-pc-windows-msvc.tar.xz=5f33d8b3a064235c23dfd2edfa8b5f6f2c5075d26529f81881501b8323eae60d +dist/2025-09-16/rustc-beta-x86_64-unknown-freebsd.tar.gz=fda4fa10690458ee7db6081267458e47113e854d65695c95813039400772e263 +dist/2025-09-16/rustc-beta-x86_64-unknown-freebsd.tar.xz=570cd878e440b5d70a0d5fc90917b92a6b8b544a2e6844baafee1fef22d32732 +dist/2025-09-16/rustc-beta-x86_64-unknown-illumos.tar.gz=f8b7273e16de291fad24f2ebbd928b55007a75605fc25ddc35a4967f17e709f6 +dist/2025-09-16/rustc-beta-x86_64-unknown-illumos.tar.xz=77d7f5de006a9d0c56a2cf79423a5702bff445f6e34b4935326d3db30ac8b086 +dist/2025-09-16/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=f61a57a75252d63930630af7d597f3046b7f7f09691cd6ff8c3a080871fa19de +dist/2025-09-16/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=b56298c4ba7a955ecb9135bba06ff6bdb7f4df94b6d64c99460e90e5a022fb87 +dist/2025-09-16/rustc-beta-x86_64-unknown-linux-musl.tar.gz=c6fec77bf71bf35ded56cf70eca28a94e083e0af458b00ed665eedf9270abd73 +dist/2025-09-16/rustc-beta-x86_64-unknown-linux-musl.tar.xz=bce669d29a995189e9d99f686b1f9535ad82cc877a106c89af5b423bef8a9d6f +dist/2025-09-16/rustc-beta-x86_64-unknown-netbsd.tar.gz=cb1a0f5ff6d9c28b83f9c82fcfbf404b2920a7da8233d957e43fe001d5190318 +dist/2025-09-16/rustc-beta-x86_64-unknown-netbsd.tar.xz=25953b44e3b196e89b5dc6028805517f42f6367c6b990a930ba44f63dce0a855 +dist/2025-09-16/rust-std-beta-aarch64-apple-darwin.tar.gz=8ada740b1af444b98c3df74f5f810a05036b6195e6b54115a7e34bed23a30d1c +dist/2025-09-16/rust-std-beta-aarch64-apple-darwin.tar.xz=1211a726975c1a9fbd679156644b83c446cab4d6eb7728d3dc38db6c949b997f +dist/2025-09-16/rust-std-beta-aarch64-apple-ios.tar.gz=58e7ec536d9bee83dcbcdad819c4a27689f02a20acbc75ffcb6ceeec7929da4f +dist/2025-09-16/rust-std-beta-aarch64-apple-ios.tar.xz=f0afe719f83531e0c22d0621b9137d30bacd17ffcc9d0188e9cee2a71f10afa0 +dist/2025-09-16/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=e1f067b248dfcf1d6efbc589a0938ceeaa81087d041889d65b90f4f82aeb35ff +dist/2025-09-16/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=182ad0986236f21ba93d49ed3dbec72e54cbc88d18adf77848e87f497b7b2f05 +dist/2025-09-16/rust-std-beta-aarch64-apple-ios-sim.tar.gz=cd367dce5dc4a5d209db298f97070e55ec16caa8931ef17a189bf5d7f5c21212 +dist/2025-09-16/rust-std-beta-aarch64-apple-ios-sim.tar.xz=b51aba09d7ced8b69e15ec9ca381379cf9f910c1f89109c8764cc15d51fd8293 +dist/2025-09-16/rust-std-beta-aarch64-linux-android.tar.gz=89154dba00da80cd67cff7e9beb1f68721bae9686e1fcff1379a2a4f549eec79 +dist/2025-09-16/rust-std-beta-aarch64-linux-android.tar.xz=d373ed69ed30521b2f724deac051662bcc7d4a919c1ff9f56b59ef028f07dcf0 +dist/2025-09-16/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=9e84923928671f76762752a559d0e9a54f513b2f518eaad3da6f5772e46183c0 +dist/2025-09-16/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=9170e87332e2a74624fa1dbaddb725f6cb331a8f65a5b0b2781c04aa58bc48fe +dist/2025-09-16/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=929786491660eedf2cb6c02036ce560043a7bec349bde762effa53ba59d17c81 +dist/2025-09-16/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=72b395a15c0af1c92434a95010fec5435343190c3b90d55d2c7d17d3d4c6da52 +dist/2025-09-16/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=36245bab64c4757821ca0732fe88fb5620601035f50bcd2d061386903abe7027 +dist/2025-09-16/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=4c1bfe4453d36d554956f7ebb169bb81912815a28960bd7caf977940109573f1 +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=080603e3b117d3654b2e0b88ec172f4c5319ebadf9386074e7e6f0c466e9c90a +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=4ea35b78b18a121bd3b0165d9f3278f3a454e108564e02b6c7d7133a33a99788 +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=9c5b7188fed949b0462f9d6c45221b8b98e7feebdc4f8bc2d6d0d652cf3b3c24 +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=31514db13f19dea13e47b8eff9fd8daec6bd0a73816aefadb94ad4e771d6a902 +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=a540735416f0b264444281865e1ed450c5bd58275f73426191cfb547b674ea7a +dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=9922ad22f002f5df232d8ed1dcdcd23a5e1a0a5b4b27e27c3b5fbd5b39087d03 +dist/2025-09-16/rust-std-beta-aarch64-unknown-none.tar.gz=618073f52e27d3ebd15b028398524a12e3bd91d4147e70b2160430e03ecdb178 +dist/2025-09-16/rust-std-beta-aarch64-unknown-none.tar.xz=3fa92c9383ac122c4b9ea2a00ff9f38d94b52c384b418b13ea573115daa07563 +dist/2025-09-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=33c4825523ef0e27b038111d3504cfbb4e049fcc3e136ddec186268346b647d9 +dist/2025-09-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=4487b93a8c7ac712328c98a660948e795e833f4edd3c92449df5472de6e320b9 +dist/2025-09-16/rust-std-beta-aarch64-unknown-uefi.tar.gz=f0c275d8bd220dc066541e6f2c7e41b6d019d698fa2b613c1f9c87ab4e29f4af +dist/2025-09-16/rust-std-beta-aarch64-unknown-uefi.tar.xz=daed68a82600fe2f3652ae87e4c491460891906fcd06ae206bc794c354771564 +dist/2025-09-16/rust-std-beta-arm-linux-androideabi.tar.gz=9fa058b5bd0ac5af231cc5ee31f67cf3f16b361a41aceb43b17c81d8e180d16e +dist/2025-09-16/rust-std-beta-arm-linux-androideabi.tar.xz=c6868144f5f5fdfc0d993f66fa91a01a91e0288014a7ab5d6233a93447508852 +dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=5cd076f756c63e54067d780167da3e35bcb04f487fefa093028b0cd3435a2fcb +dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=3322a270f3696fc2254536608ebc49e047ad59e1a01493381c9c52f813bcb8ae +dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8bed8176ed380d974c2bc6df5314ac385ca6b72a623a8d16c00b753932a64db9 +dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=d557f55446ba39a1b3335ff1e4196ab40effa4ba42b2ce91bbde93738fd93da0 +dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=12a56e9f5c9caf4e262b9361af5ea5b62ec29b18ffdb807cda83655c531670b5 +dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=82b28e64f6278cb24573d699b14826a51be465b68cb48e767a26f1938221f5c4 +dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=a3076f1f12895062e42a8ceacd5c06a3156b5a553c708615fddb975366d9424a +dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=4bf81edd4a193e6850bccbffb66c6005b1b99322192e87183d684dd9ec528cad +dist/2025-09-16/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=2170d924f4ccc579baf862171934029505d476170825397580154dfab860d4a8 +dist/2025-09-16/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=dc3bdf6f93b32aa19987d149ed7da7616f3785f67a63fcf1e0d1aebeb8007d67 +dist/2025-09-16/rust-std-beta-armebv7r-none-eabi.tar.gz=2863a22ce3663edd346d730cac4bbdef3b9cd2ea2cd5907dcbc61220833e24e8 +dist/2025-09-16/rust-std-beta-armebv7r-none-eabi.tar.xz=74a752daef0446ed260845b016b3e57d20de4e914102713e0c3b652329f9f6f1 +dist/2025-09-16/rust-std-beta-armebv7r-none-eabihf.tar.gz=8fc3fcf203da0fa6f321abbda405ba0121dbd898ea02513431a5ca3dd5e6e16d +dist/2025-09-16/rust-std-beta-armebv7r-none-eabihf.tar.xz=65cfd5061c4db0963b28f7bc636ece115ff7b812710ba9f902977f5014bdeafd +dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=1cb760fdde8e9d84c5caa787488f0bb05c5e649f411b666f2d6a5440126f5992 +dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=9146b64438a68c506a93ae3c4d4d1a928358b562fac3b7513a95c8098cebdae0 +dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=9df691f77c95a0bdf5c45fc546c2319863cdca4d433780fe8c7cd146496382b8 +dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=bba043357ba6c78fd46430c169710a264109ee5dadb79b98075744bac273418c +dist/2025-09-16/rust-std-beta-armv7-linux-androideabi.tar.gz=ab5726ae0472a8563b7e1e0dd6de32e1e9ee2dca45259bd1d382a24167919c61 +dist/2025-09-16/rust-std-beta-armv7-linux-androideabi.tar.xz=5af2a58f78fcd9dbcf1fac95cb50633ab9128e1e728960c0025e310a5528326f +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=9ff1f79f8c03756b41f8386995dbb011387982a657262c013579d0866a18ff1d +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=32dd8b2be52449b4e592a87acfba122b80990d2993fa81b48b81c0de4afb1533 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=7420a4ecd9ebb55b6864a22fedec9def0585f8460eaebbcd9e236cac2ae0a6a8 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=75de468d6d4041d77e5757118c3c93df6319f30ba6372fdc8e859b9e48f27d81 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=96f7dbe5d4bfe852b22f971cb59b7fa0981fd7fdc9e8d28fd1b6f6ae3bc59bfa +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=4166e6b0c28eca8a507f1d3c83948ba09361198466eeb648f491d9850e884df9 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=035c4db6428b912280ac56bb520bad29255b3c30bec0e89839721443109a7ce5 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=4a94449dd1f02d748c79ec1aed3907cbce97dc5641e5be3b3011234ef3517987 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=94006dd7c1a1d6cb28972369a0b0c429de992d541549d4b292fd6b737eacce24 +dist/2025-09-16/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=bb5cce4d13f2ae9d9d6f254d021d516189f29b6e78f3c1824e0803f7856ce7e9 +dist/2025-09-16/rust-std-beta-armv7a-none-eabi.tar.gz=453d62c4392ffd108233b7ce9b6abf0cc04b28a63bbbc5b979927ed7e9f8481f +dist/2025-09-16/rust-std-beta-armv7a-none-eabi.tar.xz=9b4093e7735ffe3c79f16f99a412492588a6652242e2a18c0f278e24e34cb333 +dist/2025-09-16/rust-std-beta-armv7r-none-eabi.tar.gz=293dcff7ac56a7f52fbfa1afef9fa2b4a3e14b9b418c5a56e12e8c7cc76c963f +dist/2025-09-16/rust-std-beta-armv7r-none-eabi.tar.xz=75f3737b88d197769d999b484aeb6aff705696fdccec8f3772c7a1e10630b146 +dist/2025-09-16/rust-std-beta-armv7r-none-eabihf.tar.gz=3d988af87a2c90efc5674f77baf67f5933fe60ae6ab9f4eb4256f14d98446824 +dist/2025-09-16/rust-std-beta-armv7r-none-eabihf.tar.xz=e91a15900421a8a445a7a0038923ad197fea4ec19e972ba7ff75fd4dd7d7ac12 +dist/2025-09-16/rust-std-beta-i586-unknown-linux-gnu.tar.gz=19795fe21f305ed033354d127f8e9e7aa0e9d7c67f756d22beb161aaeb9a0742 +dist/2025-09-16/rust-std-beta-i586-unknown-linux-gnu.tar.xz=8afa409edf8dfb45eab3565add6dde2fa71118008ee1e7e1416fb8dc11f66fde +dist/2025-09-16/rust-std-beta-i586-unknown-linux-musl.tar.gz=43aaa9101863b6a419330ec75f0ffde61faf2a27f050947d2a200e5a705dd085 +dist/2025-09-16/rust-std-beta-i586-unknown-linux-musl.tar.xz=86ac890f2aaee4382a126ad9e667d53039dbca550aa548090706bdc308749962 +dist/2025-09-16/rust-std-beta-i686-linux-android.tar.gz=c3df364048b9af096c607a8e5639dc37d470ab125441ea04a2f2241766338bd5 +dist/2025-09-16/rust-std-beta-i686-linux-android.tar.xz=556bb5e7e4effb543c04a64cba683b81a6ffaa319cf1d053482968767480b9b9 +dist/2025-09-16/rust-std-beta-i686-pc-windows-gnu.tar.gz=8c141a8c3b4cdbc2eff61d2a557fa602b9039dd54ff2000d0a0b790ae58c0879 +dist/2025-09-16/rust-std-beta-i686-pc-windows-gnu.tar.xz=3995a3c391e242663533680600a38343396e2a73b6876b1dd691d83dd143eac7 +dist/2025-09-16/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=3da461c03124d6ca148ed1d4cc80be4bd0d9f4610df95770ca800d72ef6c2b4f +dist/2025-09-16/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=7eaba102d1ce8ea0461657dcce62a5f8826f2154f56f89e9385e75fdc763c399 +dist/2025-09-16/rust-std-beta-i686-pc-windows-msvc.tar.gz=d1e31c04ff2145122df2ab05af6e2ba1091d1788741234cc39524f1289886187 +dist/2025-09-16/rust-std-beta-i686-pc-windows-msvc.tar.xz=330aca62a0cb38342ce6eda427c6074651ddd0c83c4b28b53ddc736edf049ee5 +dist/2025-09-16/rust-std-beta-i686-unknown-freebsd.tar.gz=48dabb6775c14d23bf04a8c5c26f2e4d6af369dff6d506aa08cf2a08d75a5d8d +dist/2025-09-16/rust-std-beta-i686-unknown-freebsd.tar.xz=db97db17addbf5d4e314f77ac9bb232a661042edf7beeed73b252e44c6439fe8 +dist/2025-09-16/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3abbec5a87dfe240bbdaf6e9a92acb2d8e6e684983803daadc7750290da71264 +dist/2025-09-16/rust-std-beta-i686-unknown-linux-gnu.tar.xz=568aec0d1427a2d866c7550dfc770be13401902741999410d4dc2e7772ec0a57 +dist/2025-09-16/rust-std-beta-i686-unknown-linux-musl.tar.gz=0739e8dcab50c87156cb3e52a18b57da6040fffd9509561fb3046e81be953a40 +dist/2025-09-16/rust-std-beta-i686-unknown-linux-musl.tar.xz=8ed8a4b1f402593db73fc2e9540664d9e4e12b8e1b5f027e56b2f3c4784a8995 +dist/2025-09-16/rust-std-beta-i686-unknown-uefi.tar.gz=40a2726131ef0e6102667bcc8ea9a64b4b19f12d58696ab434b74f9abf37cee0 +dist/2025-09-16/rust-std-beta-i686-unknown-uefi.tar.xz=500b0018fe01e9a9949ca077bb69426078a2774e83b95319d09bab5d3f6d0e04 +dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=64aadbe1da544e2f08cafb217ec1ad341b8e2adc660f60502f700773983d059a +dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=e864959561ee49a0ae680f93307929d0e16013d2ef0743a525c5d592faa10704 +dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=c709c58bb18b5a9385e07998dfe31e3ade0661fbfd4811907a6e7cfffbfe2e6c +dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=e797481997def9fe0a6466b31439d1eeb4b299c92cde3a25a7fdd557611f0888 +dist/2025-09-16/rust-std-beta-loongarch64-unknown-none.tar.gz=79d43f32d6830a0d3c9e1e8fca3ba87db44e692cc70431ac6cabea5bc59b8f0b +dist/2025-09-16/rust-std-beta-loongarch64-unknown-none.tar.xz=4d158a9d4f4e1943b2d00fd19adad762c35af24200742440bccfea62304272b8 +dist/2025-09-16/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=f0c460fee60c913463d9c1fbe369287ab436cc7e2882487afef457c78cf86ad3 +dist/2025-09-16/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=f15e2baff9b0ce68ca7e1595f00b21c45bff33a1b75fbf05a8f04b096295aa0f +dist/2025-09-16/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=102c4017e11cc3407f4871aaade7f3292c8cdc92707a243788e0e4a62604cce0 +dist/2025-09-16/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=6eaad8877694af02a10d18ce609b6678d96e75f87a1684b67279c9915601bd3b +dist/2025-09-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=26139715f7faac9be6e458ee1be840db044692a518cd0fde29c59454405d3063 +dist/2025-09-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=0edf1c0a3b8ce5dc76f1ade2dceb91f96a5afa3e54c7f25f3d3320dabeab06f2 +dist/2025-09-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=dbdd4f2cb5cacdf2656f83f0dc0b2101613cc344819e9ba8e790406e17d16b16 +dist/2025-09-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=a6dd7f0416ceea63ac723d4aeaf9cbd8d7ed8ed7d5b8925b3317cee75b9138df +dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=424eabcd66e922cb61757842c46afd298cac2e1ff809b593f6f409732261f4a3 +dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=7ac3a7e79c5b3c498daad88a6f926544eaf59d04711cf20ba05c1391544a4335 +dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=9e21d985a6702a96161aeb9ea6d1e12eb52136c7433b2ca5597c07b85a954939 +dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69658c2818ff575eefbda5e64a2a6f253ce21f587a72afb2727466a923ec508f +dist/2025-09-16/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=25da1a37707d9dbac16d91f5177eaa5244f4280758f3b5a0bfbb09b5ae190720 +dist/2025-09-16/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=52f6a0752e9db84c0efa49826988dd64f32930799ce2e057b3a6a20a5c696181 +dist/2025-09-16/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9f4f18ca2d1d4d7e8785f3ae61084aeaee7581d7eac2c7c883557cf30888cb57 +dist/2025-09-16/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=2ef831047ada8f706fa30a655e8a2b17c15c1f10e65c66a0d3577085ff1e80c2 +dist/2025-09-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=9420edabe9112cb1ab9fee01dea1bdb30a866b4633205f287767c07fb57f4630 +dist/2025-09-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=ed7b43b375dc7c30e1bd1add31940192978ad86c5c6684b54b24252117e92008 +dist/2025-09-16/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=cbb03936548c947633b7dff7952653aef98ae25d1ff79b8f8549e87158b6cac6 +dist/2025-09-16/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=c957ec9bc4b1345bc805b506caeeee9350e9f07d31d4177796f461cce7e7a341 +dist/2025-09-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=46fd5976d8bd59a89ebd2c74cc246b9727516b28cb9b1a839ac06340d738a4bf +dist/2025-09-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=a7640744bef500db2e7ebaafc4c93e73acb31b61faf47decef61ed46db73c001 +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=537dd37985108561d6e0afe76238193fa33f1e600aba44b484a15d1f40d68142 +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=bda3e2c4b93d864dd75bf64e08ba3d2ac9719581fb890c62073078d2005bd634 +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=3edbf40890f0f52cb61c0ec8665a43d230e6e148dd4afbdbd7ca8ad53a0a2b8d +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=a515cc391e794e397ce34eb994f3a1c35cff7e7e31d54a859141000a52397c70 +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=d45fbe65a55b3010fd8994d3effec67f96d86593d37b6fefeb956f4a6b282e50 +dist/2025-09-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=13f9c87c6bed3b905ec7564fb79517e891b4a70d6c5191a876844199780f7a81 +dist/2025-09-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=e55f12443bf8c44e27d585bc1c38472e3175bb9d7913af55ab3bcd8f23498146 +dist/2025-09-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=5cde9db69b110f1766da147105e3a8d879dd36c69b2367416228024d183b12b0 +dist/2025-09-16/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3fb23f12e07d3b4ef59a637fe68c2ad1799aead28c65cf3d5d136dfea4c12eb9 +dist/2025-09-16/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=999b7f7813d0d868bbda410fa37d26ba737d443a99ad74d8c2b0ecbc24fb1af3 +dist/2025-09-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=12e756fe1f5b57a752916b7397b981e288cc30b5861b16c5a710778c372be42a +dist/2025-09-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=0d0ad94937379ac571397b7f10ec5aa20cccf5401aae16ad4d18582dc609055e +dist/2025-09-16/rust-std-beta-sparcv9-sun-solaris.tar.gz=4bbe087dae754754f4dc1c05aaf664c5e0dd4429932feba88aab744e7c5b7472 +dist/2025-09-16/rust-std-beta-sparcv9-sun-solaris.tar.xz=dfa49be70f7ee3989cec7f634cf84e3b418f48882af8b69540e41f2ffb8cc216 +dist/2025-09-16/rust-std-beta-thumbv6m-none-eabi.tar.gz=598622e28c6ce111f4d47e2172a0657c3b0ca62c42895836376b1959fc2e094a +dist/2025-09-16/rust-std-beta-thumbv6m-none-eabi.tar.xz=359bb98d293e1cea22a505377ce49ba95095c735b50b7d404ce4f36d84bdfec4 +dist/2025-09-16/rust-std-beta-thumbv7em-none-eabi.tar.gz=d1f994c835b1d72a665eeb7aa4683a09ac60c1977766b066c817c3eb37ad3a4a +dist/2025-09-16/rust-std-beta-thumbv7em-none-eabi.tar.xz=22e8605af621866d82f2bdcd8089a561e10f4055624aa6dff5d704b953b7d547 +dist/2025-09-16/rust-std-beta-thumbv7em-none-eabihf.tar.gz=8e862615db8daf2c063d27f1860bd083fadefd459634e61b946ca05b8747308d +dist/2025-09-16/rust-std-beta-thumbv7em-none-eabihf.tar.xz=8c9b3d2913242cd2e7fc690e02bd28690fa50b7278befa8b57ec9b7eec4f34e4 +dist/2025-09-16/rust-std-beta-thumbv7m-none-eabi.tar.gz=fa79d4e07630821149b151bc5673205a479570bfd971e66e874e75b5046bdfc5 +dist/2025-09-16/rust-std-beta-thumbv7m-none-eabi.tar.xz=f6f3c14f35d3b5fd01a6244f802d99e261e529bc6d4a6c5749b1cfccd524c16b +dist/2025-09-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=194bc6660b3d4809d5f709e7f82159141e90b31d2318cd550b4deab65e108fe6 +dist/2025-09-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=36534004068562d8678a3cd73f8f82b50406aad6daeecf348246375da3bae720 +dist/2025-09-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=622ec13126461d4d6c1f7eb3fc387279c03ffbb96fdbbfcc7c22c2433e62232d +dist/2025-09-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=a8162987ddefbde68e2931fc824371aa71d595106488a48732b67ec45f36ac4a +dist/2025-09-16/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=6d7f31ee7fd8633d8497cddfbe05a1ca064c4d45f50066e86cd82fe4b40b93d5 +dist/2025-09-16/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=9b3309e290007406d410b8ee86ecef887d5c48b515b11cf7827baef23a0c4a7d +dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=74fd7db50be0b77e7a44d1a32afc76f2a438fb789ea32f3ce1ceff00ccbf030c +dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=e7736bc6c78eba1947ca6ec4ae5d875de192f44755ade737ce1e367f294576d8 +dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=d8905fddbae4ae3e39439fe5234cd05454034d9f2a847056766bbe41126405f1 +dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=94628c4c60615b15f1c5b331a803d4d1963289b770ba54adc4458e52d17397fe +dist/2025-09-16/rust-std-beta-wasm32-unknown-emscripten.tar.gz=68c53c1069b29461573c68b5df7ae2e30b4b7dd682cde70f26a200854525c012 +dist/2025-09-16/rust-std-beta-wasm32-unknown-emscripten.tar.xz=cc1a4d61bc45832fa1ae19ecc1347d084249f1be3553fb33d33f0e5d8df5fe5d +dist/2025-09-16/rust-std-beta-wasm32-unknown-unknown.tar.gz=a33ed15817407053144b8a6041dab287a390b3338dafcd1b02418b3dbe18b024 +dist/2025-09-16/rust-std-beta-wasm32-unknown-unknown.tar.xz=f0df12d2767da7528c614f5bdf6a9c6bec831b4020eed357409d3fc7fb0c869c +dist/2025-09-16/rust-std-beta-wasm32-wasip1.tar.gz=86634e652b087947b914b590a2e978ef1d29d09b69afff63a682f26b6dcac41d +dist/2025-09-16/rust-std-beta-wasm32-wasip1.tar.xz=04e2a9c6914b17664443b674827ab706869a81200c885e97779df0da98682612 +dist/2025-09-16/rust-std-beta-wasm32-wasip1-threads.tar.gz=3fef167485111064b1d468e5664d9173e24dbf20406165f92293f304457aeee0 +dist/2025-09-16/rust-std-beta-wasm32-wasip1-threads.tar.xz=7e12cabce073a54fbd4c97d3169e34e4beb3872a161c7c082e148b0d4adb2f7b +dist/2025-09-16/rust-std-beta-wasm32-wasip2.tar.gz=3b8f3e6d4ce34bc8c5300b77bdf875b04a69f87f73d930439bacf56f061f667f +dist/2025-09-16/rust-std-beta-wasm32-wasip2.tar.xz=056ad523469276f90f185b72696b20c6b47f57b5721544a20f6e765cc51769fc +dist/2025-09-16/rust-std-beta-wasm32v1-none.tar.gz=fee626762c4bee195d800883ba15d890604280f0cddb08aa64a6199fc4591635 +dist/2025-09-16/rust-std-beta-wasm32v1-none.tar.xz=7bc289363efb2d5555e9742bf619decc2454cb784c133db55a71be4c0aed9f90 +dist/2025-09-16/rust-std-beta-x86_64-apple-darwin.tar.gz=51cf2f8f249da5df653efb073c81047583bc7bf952a4b03d6d05c9fecb7fa0c7 +dist/2025-09-16/rust-std-beta-x86_64-apple-darwin.tar.xz=4e380037df6b548916136138069e76139dbc069688ec717632c30a07854d0739 +dist/2025-09-16/rust-std-beta-x86_64-apple-ios.tar.gz=b232b73befda81ffaf0d1db7838e2057c503cf2f4f1e95f0706cfd0faf77d853 +dist/2025-09-16/rust-std-beta-x86_64-apple-ios.tar.xz=1431fa936f5909e4e92894c7e2074d3db879c10cf3f2344b050f9c77965d1373 +dist/2025-09-16/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=fb0a1f0228c051a85440933358f7c00d47c4ce44a15a0b0025b00331ec53f876 +dist/2025-09-16/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b725c62998a3b28caa1f89549230ff275af854a3d04cdb6562f19be7e8a1af31 +dist/2025-09-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=b9588bd0c684a50e0d73717f5ae5c2f0e36a90052126d2c4a539e5a116eeb4e0 +dist/2025-09-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=70affff2a14340109f86ec585b65bed16e77612ac7b939336245cc15f7f6c300 +dist/2025-09-16/rust-std-beta-x86_64-linux-android.tar.gz=fb9fc9bbfef414092ad1082d7529fa2efc52adc849a7f45da3d5688d5f6df1d2 +dist/2025-09-16/rust-std-beta-x86_64-linux-android.tar.xz=3fd9b4d89e7ee604f842f7915b90bb02a0c44f8a4694a2d10f94efe7bbf0840c +dist/2025-09-16/rust-std-beta-x86_64-pc-solaris.tar.gz=caa39b90ac5ff710cc76828ca52c784e48518b9c3f1c58cb6f6603a7d05f87b7 +dist/2025-09-16/rust-std-beta-x86_64-pc-solaris.tar.xz=6034b44e5e7bca888027a21d8a4b1229c08fd22b744b83ab817d487aa5e6db56 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=6e7a9aa27a85a09c603fb624ea1cc56120ccbf5b4fed1be8d0097232cd1bf849 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=00f6c500331f2f75ba9c56f896db1420c353e8c0fae450da6b5806794cd58fc7 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=9279908bfa629467d619143e5e0abbcec7a843dddd0f6737994f636edb171e90 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=f1eca139e01d2a8a2627c064f3cc14d7a2016c50738fdc19d3d586f225066f79 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=1fdcf7de3772c24733474e5c0f3e64b56ca627e5a235b890ba0efa2265648d79 +dist/2025-09-16/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=23f9e2447316fda77b7a5af90c160c89d9f5ed735c7d5715cc2850b92fd1cfe6 +dist/2025-09-16/rust-std-beta-x86_64-unknown-freebsd.tar.gz=8dbdbe296c35e64170b9d1e7361a90aa260e456ea7ae4bd969db1dbcad976532 +dist/2025-09-16/rust-std-beta-x86_64-unknown-freebsd.tar.xz=9469e49e425349514f2bd224ccc64903c163bb481a425e01122bd3bf00ebc90d +dist/2025-09-16/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=6e97622b123772e4deaf91b81d1925fe2d39b87f567b96437c03c16a0982b709 +dist/2025-09-16/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=0affcbb44870daa9410887cea10844ad1f48b4e1aec053274e86e39b42aba360 +dist/2025-09-16/rust-std-beta-x86_64-unknown-illumos.tar.gz=3023abaa7f221946e1e9cd40d4a607e8c57bddf8a250a27e0d58dd95a51ef877 +dist/2025-09-16/rust-std-beta-x86_64-unknown-illumos.tar.xz=1e76ba54bdd6673428efae1407e0e5991115f59885159e68e9d63cdfda9ca7dc +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=92db1c0d785820c128bf4ad05b567b17871d2f01ef902052a90839e3fe744979 +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=233d981cbd309a03b16c5a80037faf992c47548cedf5ab4593db41554ffb8525 +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=fe3fd22ad099bae73ffcf1a4881ee2f2c520c6108ac27ca0c64fc5111ec02230 +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=027738f65f61fb77ceff38d9342915ca8344e0a1323e7659a1a5159c99c4a811 +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=e6527497065541fc4701e71efd0a896a8048b653454a75f27765e5b7b6ac748d +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=807862fb874b7bee60b2740ed2df2454d8be50b0877d34b7bea796cfda69d583 +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=17259bb2f4bb1183ecb187296ae9afef58aa2f8e816d2764caf48aa3900fd66c +dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=e459cff284cd0ee388ab65c945bfca4c64b32fd268ee66c2cd8abc325580ed12 +dist/2025-09-16/rust-std-beta-x86_64-unknown-netbsd.tar.gz=5a60ff084d1da42324d6956510a68b3b83a47b432b48e2228e58f52dc8c01b69 +dist/2025-09-16/rust-std-beta-x86_64-unknown-netbsd.tar.xz=9d6823b8b1605f748f1d7af5c52bed1dd926a1d5fbd01ea9a8f939f3648b7800 +dist/2025-09-16/rust-std-beta-x86_64-unknown-none.tar.gz=57b0a2838c59feb0808462fc043c9a85a292f0025104dd6de3c5e78d4d71894d +dist/2025-09-16/rust-std-beta-x86_64-unknown-none.tar.xz=e5a5cd9c861b29d11ae110dd4b239d5069dd0aac57202bfa440e15869f5c7e9e +dist/2025-09-16/rust-std-beta-x86_64-unknown-redox.tar.gz=f9cdee694af41422f785126fda566891357295b5fae56268188bbf2978b92089 +dist/2025-09-16/rust-std-beta-x86_64-unknown-redox.tar.xz=8c7668ceb1611dafd9bb9ffa6de9a11e39d049cebeba05e2dfa889e69d94a54c +dist/2025-09-16/rust-std-beta-x86_64-unknown-uefi.tar.gz=33045879d1aebfb17faf93bd471bb4c4ee3b9a787c57704814ab2dd301ac8ba6 +dist/2025-09-16/rust-std-beta-x86_64-unknown-uefi.tar.xz=28018cd9cd16e428790600decff5c7df749fe500861ecd3853895ebe69fb7100 +dist/2025-09-16/cargo-beta-aarch64-apple-darwin.tar.gz=f0642e83a5a6c8654d724e4929c0e58a4c07c330eae58fc4794ab94721b2732c +dist/2025-09-16/cargo-beta-aarch64-apple-darwin.tar.xz=13cd17e3f35cc0214b25b65463b2394f3642ff8acf4e13af20b442b0100556a3 +dist/2025-09-16/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=fa047b7d7ad4ab64b85ca7beef052a66a89c60f976b099364eb3acfd2867c3fc +dist/2025-09-16/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=df3a9254c4f329454dae9428d88f6c3e69ee8a120bf2eb380193eee63620ed69 +dist/2025-09-16/cargo-beta-aarch64-pc-windows-msvc.tar.gz=e5b608ae84d9258bccee0ecbefaefbaf34b989cd656f096692ea84c6f8d78645 +dist/2025-09-16/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8ad0c0d49f7f6ebc5cce4a2b76036c2d0eb8adb38ce11125e2b36a1291b8ebd7 +dist/2025-09-16/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=f454f83f4ffe0095d3285011b3abae11b0331d87d398ff95622e9091ee09826a +dist/2025-09-16/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=29c83085c7d51874e943b429999cf7709c0cdc422b1254a5e587aecd653430b4 +dist/2025-09-16/cargo-beta-aarch64-unknown-linux-musl.tar.gz=8f85db99809ae593abb4806ffced52abf048dfae81891ab68ef4c83f11f03fb2 +dist/2025-09-16/cargo-beta-aarch64-unknown-linux-musl.tar.xz=e5f004172331f658c3027084950360e1d60bd0cf3cca83fa43cf7fc251cefd37 +dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=1aae91a92e1d41e9c53ede795f91e7dccd3dea687d84151e507f4d3af089f15a +dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=369b8686197e4be3883c3225bb9c186b17839552c91117750abf428255df9c8f +dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=b2e9a3c467ca2847f4ef55241b05a4f5151ca2608e05a43e5101c62d9d6a399d +dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=aaf6bfeb90e732627ae98f4b86083b3a902e31a951b98b3b5e94b67ffa6771a8 +dist/2025-09-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=75bcce21bcd655a537b77aeca644f5279ace4f782a97d1e82de3cbe76a7df6ee +dist/2025-09-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=287800d221906551a50922caf0637049f3490e17c65d62119c6a26ce48d5ffa8 +dist/2025-09-16/cargo-beta-i686-pc-windows-gnu.tar.gz=89a6059faab9a3e912dc2baae766ed232d38c240c90f503bb2b486225457e8f5 +dist/2025-09-16/cargo-beta-i686-pc-windows-gnu.tar.xz=96e5b7238f543edbcfb16022ec6aa6d3643add1f7b4b0febc3e35ff9d173c075 +dist/2025-09-16/cargo-beta-i686-pc-windows-msvc.tar.gz=39ed55c1619ade6fc49fefa5ba5bfbb67aa34e53d35384a35c37d0681596b9ba +dist/2025-09-16/cargo-beta-i686-pc-windows-msvc.tar.xz=d9ce7d301af311d58d1b4342855b70dfbe0fa8bb365b78bd83822e58a7ce9086 +dist/2025-09-16/cargo-beta-i686-unknown-linux-gnu.tar.gz=2dc0a357f58462c5474cb5c83445bb17d22450056fc77d3a92c844f104e1c96e +dist/2025-09-16/cargo-beta-i686-unknown-linux-gnu.tar.xz=c2e4f00fc345a77da5f13642d6b65a77df553ac0cb596fa34f837d76fac460c8 +dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=e1b5e490a00eecf93d7c591628c8d231eadb8c68104978b623fc16c5369248e8 +dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=c2f91d72d2977168eb12179abd98b4d18f67de4ed455856f7af18a860ff5b1c5 +dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=7fa229d54c917a4872efbc2e9eb9181f5b1133aa44508548e94e4529ab099cd4 +dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=359d7ec4bc7e0eed1c936bff9cee56bc3a132a488499cb83a8e7561222893c66 +dist/2025-09-16/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=fe514bf5afccb535517decb4c3120375eefc36def2190d60f4f0f6d796af1b79 +dist/2025-09-16/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=d3d1307f3f60e9d8ee9f199441185bcb52a7bf5de460302291b178ef282a457e +dist/2025-09-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=e7c77c9baf683994bf180b8906d55a2117f5bff85fec6c602a6f1912c39b2817 +dist/2025-09-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=207e6fe0baedb7f19e8a0437e24cfb9b46d4131a141863c93a52d00f1b049d8d +dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=87433380a70642842f7dcf4a4c8614cbc136a18198837e631dce419e99ae71b8 +dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=207106c6e7c129fe19940da029360f8ce42f29468836a094a2b02156121888ed +dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=ad90e19faff850cbb03eb04195943a9f65169d6a7b030422f0310f8c053e61c3 +dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=7abcb3c3cf3710fcf41d67664137bd0c823792a70cbd82004e0cbbef58446f44 +dist/2025-09-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=7acc6031840a56c47dd2d52a6ce169663ffadb108e92743b22a6dd9a7227baa4 +dist/2025-09-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=a2ae500b6c44abeb6cbb42a07a37a8e0ded707fdc1e3f4d6159aaec404912f5c +dist/2025-09-16/cargo-beta-s390x-unknown-linux-gnu.tar.gz=3a69ae63bde95a6dd4020395b90e821e4342fa1b45b00d12ea30f3b1c643ef59 +dist/2025-09-16/cargo-beta-s390x-unknown-linux-gnu.tar.xz=231b1b052018ab851c57563d3c3b4a943cc01f99e3ca6795dfb6a1315d2577c8 +dist/2025-09-16/cargo-beta-sparcv9-sun-solaris.tar.gz=41677b7f137d6509bf7e0fa2eaeefd91d03316e566136d37d006fd98a2a4c28d +dist/2025-09-16/cargo-beta-sparcv9-sun-solaris.tar.xz=f5b4057e69c50258c3edf00dd71f47951833ae892b121641d8d3a0bd38991838 +dist/2025-09-16/cargo-beta-x86_64-apple-darwin.tar.gz=edfe3b23fe5824b5ae763871f133cce684ace0999afd38e9a7b2a08f17b12ac0 +dist/2025-09-16/cargo-beta-x86_64-apple-darwin.tar.xz=173ec4d3c129530c33623f2ec6a5fdc5d739ecfd24f7372f3713ea94aeab8eb1 +dist/2025-09-16/cargo-beta-x86_64-pc-solaris.tar.gz=fe0f57ea7eafb5e157a04cd753b4f6b733245fa8e9baddccf581cec0a7ea2ed4 +dist/2025-09-16/cargo-beta-x86_64-pc-solaris.tar.xz=61ac8a524964f2179c8195d821382597bc8641eace9ba1c27e81453ab8c347e0 +dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnu.tar.gz=44200f95def8558a8b7b85c11533841786d3fd17331e13056dd7ce25de667b2c +dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnu.tar.xz=7144031f2f69bb3bba08cca81e15dc557424c096f9555678b1bd1dd5f4891360 +dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=a7a9c76ec0cb87a725c44336cad0182cbf2c1e06d19cbfa0311501541c08c852 +dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=0b66de9c68f0ec42a410a898468dd67f147284911803207053a01fb2d29b65d7 +dist/2025-09-16/cargo-beta-x86_64-pc-windows-msvc.tar.gz=de26ef4d9091775cceb21af53cb1177922f8eb93763c0e333e59205dcb05ffa5 +dist/2025-09-16/cargo-beta-x86_64-pc-windows-msvc.tar.xz=e6823ffc56d1136d02384acd09e73b6e45ee197c2126b49aa95df832704b9d24 +dist/2025-09-16/cargo-beta-x86_64-unknown-freebsd.tar.gz=dd0656bae2fbf483ebe641ed952499f0127897b09fe14273046cc8e0c7611825 +dist/2025-09-16/cargo-beta-x86_64-unknown-freebsd.tar.xz=6c8b65ac66bf730f9c5bb7caffc75ab1912439d033130438d98ebdaa1a2b922a +dist/2025-09-16/cargo-beta-x86_64-unknown-illumos.tar.gz=5c3f38613b4d2f26643bab1a6db5b769f58878e47168dc92bc2c7b2fe9559ae1 +dist/2025-09-16/cargo-beta-x86_64-unknown-illumos.tar.xz=046ee0c80efe70375179c95461af5724cb00eb9ecc1d995e4a629d316d853686 +dist/2025-09-16/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=b6da1a94fa5718c5a1be4d67d6422d28e62365a433d82f11fe7f09149690e78e +dist/2025-09-16/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=5b8aeabb11e88e4cb02c766c11c0d3d826ded4d08874a11127d8f73f033b0072 +dist/2025-09-16/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00f191b30c29d46e503bfdc49c112ac5295bb67caa091333b0caf210e08d3f01 +dist/2025-09-16/cargo-beta-x86_64-unknown-linux-musl.tar.xz=750060cc199fac6990597a9859234392f4c0a5405d87d1234fc7990032b4c138 +dist/2025-09-16/cargo-beta-x86_64-unknown-netbsd.tar.gz=12513081e2bd88c666881e77e3c4935c710cd6132d9ec48cf9049ac7ece5dd9f +dist/2025-09-16/cargo-beta-x86_64-unknown-netbsd.tar.xz=b1338ed261e33b0fa3e8a63c8930835d87d352ec10011bd4d626c44fa0b0392b +dist/2025-09-16/clippy-beta-aarch64-apple-darwin.tar.gz=668e7fb88b52ad92634fc4d39885843b4893fbb9f34062e8c4fa870f0e71fbbe +dist/2025-09-16/clippy-beta-aarch64-apple-darwin.tar.xz=a0fbf1903d1a95c6ca98ce98a3e639110022480d56c20e175e4fadf211baadda +dist/2025-09-16/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=6593c10385d78ba68b38b8815e5c7aead991d83d9f689a42f4a2911a5f7f0450 +dist/2025-09-16/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=856303f96ed6bd1be89295dffccfc944cd70ce3d1921afc9366f19c6ac800b60 +dist/2025-09-16/clippy-beta-aarch64-pc-windows-msvc.tar.gz=e60f30cba9fe154e7446cf5b7114e7f8c153937eb58cca4cb24dad1b8dd453af +dist/2025-09-16/clippy-beta-aarch64-pc-windows-msvc.tar.xz=24ae9f98df0f2320271b8250234f571b64a4b5ce983a083f45966e58f39b1c94 +dist/2025-09-16/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=aeaf3ed45a8feda550b2043fcbc55ca9fa3eb95141dfecabb794fa9003d76a3b +dist/2025-09-16/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=3187bb767e36aee12059f1d2b77697aa57f71a3c478930c4901dfcd25d414369 +dist/2025-09-16/clippy-beta-aarch64-unknown-linux-musl.tar.gz=c2c23a91b2cccd4978fe612f22c33773833c87719259bd0d501e5a2523f3c689 +dist/2025-09-16/clippy-beta-aarch64-unknown-linux-musl.tar.xz=b7902a5d4dafd1301fb573148b6d1164b9365e976a9019151b66aa93b88e93bf +dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=69e95f21ef2f59df25ee56c2dc10ed5306ca5b41299acea22d2d87d967d17575 +dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=24343efbed86314a6c292659ee0625cdc30bd655eec8009d8e2209a659dcda12 +dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=404b0db1d121ad8fb1a43ecadaa84a79f976a68dbf088ed47fb31245e293445e +dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=f4fbf3a39e1b5d61a481109da644e44e58371c00a3224b187dfbe39827615a33 +dist/2025-09-16/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=fabfcb98b0d9d69e5d022e40ab572d2e84c604dc8d4ba2c88d44501c2a7390ff +dist/2025-09-16/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=8c289d02256ff36412231b320c723becc8d83d5acf9c2325541367eb66f6443a +dist/2025-09-16/clippy-beta-i686-pc-windows-gnu.tar.gz=13838c1fa366173219023000810ba180899b843f7d5c54ffb415c7a517f5af80 +dist/2025-09-16/clippy-beta-i686-pc-windows-gnu.tar.xz=a86b22e78175f89ff2b4dd40b9fbe91b4447914b226d7ef7d020903ed2c9581f +dist/2025-09-16/clippy-beta-i686-pc-windows-msvc.tar.gz=fc2a9397912c6651e04dca0475dc74fcb9a50f370a0ef7f9c7987158dfc58d55 +dist/2025-09-16/clippy-beta-i686-pc-windows-msvc.tar.xz=bf4be32251bac244540759795afe760be13a134580cae8e3fd5956d8ed45b254 +dist/2025-09-16/clippy-beta-i686-unknown-linux-gnu.tar.gz=10580cdb4078d6a27e511ef71ed1a50f67202c1ba145fe315b63f2786ecf6428 +dist/2025-09-16/clippy-beta-i686-unknown-linux-gnu.tar.xz=5ef51556bc3b002a97e7b9f092ce280ee3b5c4a6b02a8d382d87a3f56d90eb04 +dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=34756f99178d5be61df2375f4161aacfb05fbe4d38e9259bb7a01f71e842d67d +dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=1d10a5f1ac3bb2bbd84c421cdd1978865fccd214c08a341c7b6527c6674205bb +dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=c0fc0dcc1a78960b53de22703e7764bb64bf35762127a8f272b45e95e64c7bc1 +dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f41d1ac85d5714c6fbab9986ced2c80bafdf8251f37f16a5a9da994356b5912e +dist/2025-09-16/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=6f2cae468cc556a4083771c6e3e610f759cad00b7af7255db32d461d6e4f3dcd +dist/2025-09-16/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=6df81ef270b67457b96ae04da2801c2a80f9604df9c902e74140ab4b154a10ab +dist/2025-09-16/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=fa4b89d3144ae42ac8c69f85f7b63f46cbbaefa1c3063f719a75dbf8e3ec39b2 +dist/2025-09-16/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=944976f337f4c27176ac614abc918a2bb037d30c554ba5e92e180d7247089cb9 +dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=30da372a7d750fc5e8509cd2265522b7d3d24ab8c37af24076fd0c6f48d47ea4 +dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=dfc5382049b525b461b5bd343f214f357bd3cf1a66d4d226658538639f4ca85a +dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=f5f500c286fc90f4b7808d45a77beaecd7ae3d5c99522dbc80f09132f078fbe3 +dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=5a5da7891fae2f8fd1fba6a537cb3f26cf0aa73f0e36d01181fa20a82be3536c +dist/2025-09-16/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=538b09d45dbcfed24f521a29f5107a1b39efd8c3217991c21eb6c55603ab267c +dist/2025-09-16/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e95cc43b991ab4d0f16c593171231bc134538f64ca40ddcdcbf5d2b73bce3307 +dist/2025-09-16/clippy-beta-s390x-unknown-linux-gnu.tar.gz=37b1903fc1e58f57574a2a6ad23014443d72d6e8aec35df0168028acc813c8ba +dist/2025-09-16/clippy-beta-s390x-unknown-linux-gnu.tar.xz=04d65883b79cda42a26c0581349fbeb7023a25bb73db2e525483fc4895386e97 +dist/2025-09-16/clippy-beta-sparcv9-sun-solaris.tar.gz=057cb0d5ba11a7679a17d87304d1301cf583c86ad2faa23fc449d3cedf0ea1be +dist/2025-09-16/clippy-beta-sparcv9-sun-solaris.tar.xz=8cf1abf779a8a5a18561f643a8fff9863909be7c3f8bc84be2d817fc262a1215 +dist/2025-09-16/clippy-beta-x86_64-apple-darwin.tar.gz=a1301c459894d6d9837b98ec8af238b26c401b860a78d458e34c3d747a8b5de3 +dist/2025-09-16/clippy-beta-x86_64-apple-darwin.tar.xz=af863a3fcae2193f8cc26d9b62854bcba6e029b0bef0f2151321bbabfc931c3a +dist/2025-09-16/clippy-beta-x86_64-pc-solaris.tar.gz=5a3176859e8f783d8bf687d578100dabdd8196e52290a9de6b6902463b4f193e +dist/2025-09-16/clippy-beta-x86_64-pc-solaris.tar.xz=93e37f354b89c94434c3c294cc54522ed503687ef62bb70a146196262993ce1c +dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnu.tar.gz=6403ea6cc8c3c3f83f29d894153ba3bc956b19fc213c11ed13d1117620fa543b +dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnu.tar.xz=a9ed248496eacebd88e33715b30253d9d2730087cff24427b34cf07b2eb89a1f +dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=5a72c9e26e4d59d013243d0d2416fe5280f2eb915f760470b4501731d8e8e05e +dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=078dd02a254accc28ee8b26a5e4b3349f013c629bd1da49948f0071184727ab9 +dist/2025-09-16/clippy-beta-x86_64-pc-windows-msvc.tar.gz=288ff79cc4cc4aec96d6ecd92c733e18aca2c846c87359e77d825cf57817c1e0 +dist/2025-09-16/clippy-beta-x86_64-pc-windows-msvc.tar.xz=fbc1421027dc77265be5d106d6db139a6a33b4e5ade0b1eba17e17a4ea59483f +dist/2025-09-16/clippy-beta-x86_64-unknown-freebsd.tar.gz=1fc82034c6b8b38d60788ea3addaeea8ef4448d467def0a92bea750d060c4d39 +dist/2025-09-16/clippy-beta-x86_64-unknown-freebsd.tar.xz=3a3b7d4f98df124bc7c73ae46f0c776320c1a92c0d1dd7d7caa0d138e7068a3f +dist/2025-09-16/clippy-beta-x86_64-unknown-illumos.tar.gz=f02880e995ed24f200b5c1711f2951e7eaeecc4ab144e50d866f11959e8fbeec +dist/2025-09-16/clippy-beta-x86_64-unknown-illumos.tar.xz=a99652b13a6c3570bcdc41638a59b6d68b76562000ceb60a57128ee5065778f1 +dist/2025-09-16/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=657275ab960c8c65b55b22bdbff5040440a039c9631017645a37506771f3d443 +dist/2025-09-16/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=4ababcc7ffc0976218e62bd55666ff06e01350ecc790ae06effb2767521e169c +dist/2025-09-16/clippy-beta-x86_64-unknown-linux-musl.tar.gz=5c454d363e6f8615aaf4d93e39306972e65a544f3a973c034333022aee321f33 +dist/2025-09-16/clippy-beta-x86_64-unknown-linux-musl.tar.xz=327cb34aff228c3fbc3efb389ddab0b50e5e135145602a8f9e5227fb70a462a8 +dist/2025-09-16/clippy-beta-x86_64-unknown-netbsd.tar.gz=87426803e7fc0bebdec6ae46f8ce536d947bdc57294e592599cb54d9d98d3d50 +dist/2025-09-16/clippy-beta-x86_64-unknown-netbsd.tar.xz=021d69fe47201dc89f394d084b70491d15718b24ceeba56e7cda18e3572f0309 +dist/2025-09-16/rustfmt-nightly-aarch64-apple-darwin.tar.gz=fa289216a17ce0b4fce43862f80087e4bcdaae7b20eac1f3776488b3986db45c +dist/2025-09-16/rustfmt-nightly-aarch64-apple-darwin.tar.xz=1dade784b9caf54bc3ec5c9021d7c4ed1307f11f71d12af46961926a4ad6f7d4 +dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=0f221f2e4d5bece40307c4f7b095dd377ffadce916750c27bd7a2d5663eb6b37 +dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=3d7cdda977ddd4a49f27a2fcf9e0027ce9aebcc5f250e25c3788b6bb5169e8b0 +dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=28a44723d3c4da225592786db74f58af4af952b13112469910b5a2f58a7eb20f +dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=7b4b9f2804488f90bdc9b4f5ac19aaaa9b82cff02c86b95aa0b7df0c805502b5 +dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=df6b42adce548127a2a549bc7b6e574de86c22533641c5bc725c1d5ad62af651 +dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=07d680aa64743ec6e8c417ff14747567fa6056738d6ed8c06db2c63c544f5201 +dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=66262bcc6e4fdffef1e9966bedaae64f27169980987425323fbf3a73ad46792d +dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f8125405f6437be0357eb594fc74842d6995e113b2475fd8fef6f778dddba539 +dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=bcf9fdad0b5209b1e12fd81a18927698f468995e708dd56e8212f977d4ac39a8 +dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=f7a7289e5f48ecf9ddbb214e6ab47280789a14065960f40a92d8dde3e1df57b4 +dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=e463b2bd6236463c68b2d0377bb33adff0daf17fc47dfe8f0857043b793a847d +dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=96c15e4bbfb17be75003ada804b2da5bd750889c783e110a5a3481f045ecbfc7 +dist/2025-09-16/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=6e53b146000b91f569aa5807e69dca726068d2c23e4a44c344592ef7a96927ec +dist/2025-09-16/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=a59f630b27fb33d188ba0dfcd3563a69bced49dfbc0fc1545b0c750bed41506f +dist/2025-09-16/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=ab6b4c2728dc0381f92af8b9f9c730507709e40ca7da89700bfca9b7adb93034 +dist/2025-09-16/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=71950a1d4c6b04868cec2fcdd7c80bbdc675ed5c25917c774e3b6445bdff21c3 +dist/2025-09-16/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=fd25c154f34b662d69a6d5cace59ebd605a1c4085a14ff8b8d597f5cb7324e95 +dist/2025-09-16/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=15a2a897028e11992d2cae90d2a00f730a65f8b62ad500ff82c2fa83767b866e +dist/2025-09-16/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=9516f97a5807b07d37e95a258b9cd60305c2b0429911c2425716e7f77a556eb2 +dist/2025-09-16/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=f665d43854449cb4ade4c518671ac5fef4a9640d276ff7d90c51c1bed08f9909 +dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5de565b08f2641f3a7b58f79f5c63905859d39573f105ba05addcd4db5cb30de +dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=0f3d7e4b91b6cab8ec9c534ae0f82ba79c57d621f25baa2b408bd2844edbc017 +dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=7a33a965a41fd3958df003506da405a42cd459bc8689aea530b4a66122eccd3f +dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=b38a0cd88bec44e60b52e414237f50352900afb66e3f2b829acf92de5c060e3c +dist/2025-09-16/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=64cc62b309d4be3b004356637d726776c6765cee590cb0ca244e2bc3feb6368a +dist/2025-09-16/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=bf873d8101d8f2f3574387011749b3375298c7a828ba1ebed91536adf50be1be +dist/2025-09-16/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=3fba5ef7cdf564801de103e7724ac0d9096cdfd8340c75df09bc0ddc1e71a74f +dist/2025-09-16/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=c5a8af0f0689aabd52a337eb11a601877cd9f74efa2734d872f2752413551aea +dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=4f1d6e182fbe1fc1a87949651e64a7f6896c3b359b7937b02d2c02b8e9db952e +dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=29f7583b6f0af1239194c8d936a9f7e38f58920f6a4888d26ea1a48ab8c72235 +dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=f937a74b730cc1d064e0b4be538fa5bd51f636f8a5979367cff3a611d7893f45 +dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=d208b1998db3a896ea9c7c79ded0ad6ca4de452d3b6e696ffeeca44fe9fbc58b +dist/2025-09-16/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=6816dc3cdd53c883a7cad8e7237c1e22264dfdf6e1a8033b41887a52cd43a8bc +dist/2025-09-16/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=904b26d880f6b364458e9d0f682cab3a136b3498f27c913d6f422de6fa822e60 +dist/2025-09-16/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=373a93410cc2fae30b952b036487417ec9e6211cd2e1980e60352329444a4376 +dist/2025-09-16/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=8e1e328f2312cf458f8d7288624c11cc5f39bd7c8feef62147216689a5c28a13 +dist/2025-09-16/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=8f22b6753dcad78a46cdc98251b27672bfa94f2ee11a655705fd7fa8a469ae82 +dist/2025-09-16/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=b719b7167321d4be13eaea674f713269c35e4d34dcecaca38e32cb72aa8632c4 +dist/2025-09-16/rustfmt-nightly-x86_64-apple-darwin.tar.gz=63006d28e754c6e6afc5cea25527d4ea628ba084f0af52a36b676faf73f22e07 +dist/2025-09-16/rustfmt-nightly-x86_64-apple-darwin.tar.xz=b74a4e9726b5acf7133511b855088aa3ca9eaf5e5cd73a6d3b054e8a263ed6f1 +dist/2025-09-16/rustfmt-nightly-x86_64-pc-solaris.tar.gz=a3625dc34b971fd11e3d2f895a4933f4ec6b1e01475385cfd02e4eded528a99f +dist/2025-09-16/rustfmt-nightly-x86_64-pc-solaris.tar.xz=1309352fa233debe6b1a06664da7f8d6db9e8b18afb60ca5709ca6a5ec657198 +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=b765f3a632f74d7624ad10afb1875716b836dd6e5836736fbed6ce5fe7b00594 +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=b74f1b6e563790926629952d25199eed14fa15e94845c962c79ac56df64cd18e +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=365e182e871e46e9f54b2265996c4531ae44b5f93a2208a5debcff5367026692 +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=34712b98cd806caf8507b3afb292cd7bbf41599a395847336f617a9c952f911a +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=d04e6573a9253d4c5bf512f7b65415f08389c499d0024ac3990110ec1859b24e +dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=98de7fe5863ce17a6f3c35ef9baff92124c5a398a008d80394a1ddc61fd29390 +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=01f052f3ec99702f7747610c3a5fd0a440a7a38bc5f4da93be9e6db48b599f3e +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=38dcd9d9fedce55d75ea7151937cbdc4f6f76d92eb8039840e520faaa870182f +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=0341b4b7e5287aecafb3097334eeff773c83d5267c3a1c6edcea6c6ae1ee29fd +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=42ac68f632ca2d78b9b4647bde709eab84765f4376722ecb560d099cde89c7f8 +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=af7491f1d5fee8a52768397966b75ca4104400e7023f373dd8b188aab4ae1b35 +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=38cae1811a0e18ddaf094d3931d8d532c5eaba03fa2cc1149380ff9393e8f84a +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=631cf4d825237406f2992f44f26086672886b61fac0d7ff7a4991b25ec756ebb +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=ee52ab0c86918b2a155098cac489f5e639c0abd7064539d0e8a6a7502ca33c54 +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=67de842ff1f8cf99b0ad88ecefc17fa36359fa718e3fc04f243ad8c1595987bd +dist/2025-09-16/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=349480a812b9861112e80ab86d3e80318d239af5212b314b3a7299dbbaffbf8e +dist/2025-09-16/rustc-nightly-aarch64-apple-darwin.tar.gz=fe1ffcb90bdca92a61470c4f7cdf7bcdb4e7bf7c685ac0b92eb3a22509d88963 +dist/2025-09-16/rustc-nightly-aarch64-apple-darwin.tar.xz=b55d2837dcd2bdfbe8444e29d0f36ea584451c4f0b7fb7e9bcd77279e8cd820c +dist/2025-09-16/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=c303271dfc8ccd2c997e5ad88e2c3fbab6b9a188331217dbd46a6d96a53852ff +dist/2025-09-16/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=0d82ddfbeaf9380773bc91f294651609bc928cf53ce95fa89fc4a0f04e54ac67 +dist/2025-09-16/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=6a8a14c5180e4cbd23bf144cf11dec5f47b769a717aeac03546d5cda83b766ab +dist/2025-09-16/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=915239fd57032010740ba9aebea3e018581993d2ae5d2ebab9ca42d73e48077d +dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=932a75ac114cb08c0eef0ef2189b463885a6d64334e25899ff386196ec59fc4e +dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=fcff7229b11ec8925d39830ce62892265f655ff272d9e3a167f102cb0cd8f098 +dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=3ae873418d17f15d46a1de95e945aa1e00d737b688e196d565031947b9dc420d +dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=036eb7c219c6e1c447c5e6ee6d4635dcbcf4c1274c5a14f0dbe5eaee3f175f1b +dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=16484c845c672c775970f0108a8c336a11d2a2e4dd5f76bb5d1b74da1e436484 +dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=9004db0b31113fa8ef0cd44318d0df62e76b8d30ac2a6332f6d483513e4ee7dd +dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=6b3c245279a006b0516df26ca686f56cdf6233740d8c8b18bc19c5aefa84dbad +dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=ecd58877e63d7d209a67ccb5a6e7693af38f2e249ce04001605ac49fcec45edf +dist/2025-09-16/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=d5370d72328bd22b2fc79661061352c99d3288604bd1ed58ae2b798586db5f70 +dist/2025-09-16/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=5b8a6f255601c33bfd215b646b8ff164390e1eb7df69aeaf7be65d97dd9f426d +dist/2025-09-16/rustc-nightly-i686-pc-windows-gnu.tar.gz=74ff396b8dfb28aa91692aced5ffa76f3e270d4c5a2e47b12eda5c4534e92bf3 +dist/2025-09-16/rustc-nightly-i686-pc-windows-gnu.tar.xz=953e50c365d084ffeac61d1279f89943e81b43922c6721f5e55f211d0fc61902 +dist/2025-09-16/rustc-nightly-i686-pc-windows-msvc.tar.gz=c3485374a990da572cab859f6cadbdf252d32e07d550e0f20fcee24be543050c +dist/2025-09-16/rustc-nightly-i686-pc-windows-msvc.tar.xz=ea4afaf63f5b5c92f7feea4b82ae751f6f8bf8f54126d7007bc72d4815352628 +dist/2025-09-16/rustc-nightly-i686-unknown-linux-gnu.tar.gz=0635e9a84313f572d1883841f91bb49c7e7fed9a6dc5db751f00e7b00f140ce2 +dist/2025-09-16/rustc-nightly-i686-unknown-linux-gnu.tar.xz=8904638b6ab37416eedacfcb03c7b87fdcbe1fcd0e3a80e0e5f410c671959d44 +dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=3fab80f207dd5e8f5c276deb11512d55b5e97b3dffe44c1f0249e0c331ce2b68 +dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=95dd7df11dd2b9f27f8fc9e88f37ada794f9e0443cf1291c554f47485eee84dd +dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=a4e7d3c55c7acce10b1f0b59afb9e70d32c651b87a4d1381e945fc07543e474d +dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=f2ca377351093829123525578451c60987c3943be1783e396ab3d5f34e7735cd +dist/2025-09-16/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=b7e5d9c1ecde1b69b17d29a3ac6d15af0e734a7666381f1adefd0bc31ea2c397 +dist/2025-09-16/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=1c18dca6d3ac47b8223ab1e67e94640f402ba8f2ab787b38ba85c49ca8143acb +dist/2025-09-16/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=0850c609f864638538f4a960ba34307045d74d10d462949e9728b2e14cf5eafc +dist/2025-09-16/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=ed4433fd1004935913d5a48faf78bcc4d2517f45e08032995414c69e4ede78ef +dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9f54367ce8c0f2f1cbb29f84e403a8aebf9a3ec7d2675faa744e8c28b2adcd0f +dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=c1ebb094ca29b4fbb30326ae9ef99804d9f6ecee0bcb5633ce0236ea90058a13 +dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=c39f9dd4ad6f7939d114a9204a72cc22cf9a3d97ef3b496eff2bd78f55ff4e1d +dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=cf218f8da409b2cdfe3820db1ce882e5d10f8a24a77b600cee9f00e85e747d13 +dist/2025-09-16/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=b64731d52f06f0b08fcc6dd64e9319d91fde2e48fd71d2b193f32ff770b81357 +dist/2025-09-16/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=07fac144d37f87e5f7b3a9521ef79789d7ab33cd529bb27c1b95238a28602857 +dist/2025-09-16/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=727ca4ef70eb8cae09f73762202aee2b7998bc97c000571223991347a5408712 +dist/2025-09-16/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=787ae447f764bf727c7debf6543b1ec22ebcf463832eb4d1279ec0f6824c2955 +dist/2025-09-16/rustc-nightly-sparcv9-sun-solaris.tar.gz=9f80d6add413e65dc6ab0e3d44b62f24134c6b3ee0bcc604ab66b3fdcd4fa0fe +dist/2025-09-16/rustc-nightly-sparcv9-sun-solaris.tar.xz=3075e68b1f8a7b7a1c9489afdc2c9a38b1f0107865229497b2c9a7215853ef08 +dist/2025-09-16/rustc-nightly-x86_64-apple-darwin.tar.gz=685ffc70ff08c696321ebae272d09ba7f9e62f221929fa703e8cf21ba790df58 +dist/2025-09-16/rustc-nightly-x86_64-apple-darwin.tar.xz=29bd3bbb0f082cebf2dfef6d89a50dc5f33be231fe9d3e5bd2bb9b0b9bf53f90 +dist/2025-09-16/rustc-nightly-x86_64-pc-solaris.tar.gz=720e21f5ece47547b4cd91d5be89d67ce5334fa23a70921e7d60b0642b53a2d2 +dist/2025-09-16/rustc-nightly-x86_64-pc-solaris.tar.xz=d1e4d96e6f390ab2b6b1f435f5be61a69e01555f5bb66d58b2571f363cce8d26 +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=2e1a315af7faa1f67c35e927fd0f3a0c96fecf0da1a2b3269ced7846d99d9100 +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=7cb11ec687244e19a31996a3a802a8d0851cecd444abc5a8e65a10a037f67f4f +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=89010bc8a19cfafa6bc9714dd90cdcbb31cb85362846b8072cb41a3e8e7583ee +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=e84050c777e73941cb28f39e72a992b6a4a63100541f5b3fb288cf91fa1b0bd2 +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=ffd857605275d71bf7e09eff94bc5fbc9cef222b1c076f1b7aee72f980e4c470 +dist/2025-09-16/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=f28f28f07e98cb1bb43e93501cb43bd88b91b9913257f4de5c7154f0f9653d41 +dist/2025-09-16/rustc-nightly-x86_64-unknown-freebsd.tar.gz=66fe447d3f4526514b146633375efd40373dc28fe0262302be75afdf736986c2 +dist/2025-09-16/rustc-nightly-x86_64-unknown-freebsd.tar.xz=4d929f5079cd7a1c878631288765441aed538956d496881c89465aede623d94a +dist/2025-09-16/rustc-nightly-x86_64-unknown-illumos.tar.gz=feed1caa5d31ab01cd4dc3c4b6b893c5d291fca9c470430f83c2cc90d26418b5 +dist/2025-09-16/rustc-nightly-x86_64-unknown-illumos.tar.xz=2f2b4e9e9a42f255cf66565012c63b2b2c0a13309dbce94d5135cd3280a8fc67 +dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=f96e122b71d41b4889b18a0cee173822d509d8be9eaf28a3fec111df1a5dc5be +dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=ee8914df087f4e20c322851f322220e2f4885a316627c464881d086024e84b54 +dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b226b4edc64f4ed91a9cb616600ece61c12f5da72ca4b62f13669e849de7ebe5 +dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=9a3d98e0fec50ab589027f1d5973ec583b062581b1a1cd59470bb4fb6c51c463 +dist/2025-09-16/rustc-nightly-x86_64-unknown-netbsd.tar.gz=bd0d47aaa630abc01d2f36f9c2a99577254aa3428abf1d666d5520c4fa990844 +dist/2025-09-16/rustc-nightly-x86_64-unknown-netbsd.tar.xz=863edf8589fe1f3f1728222ee49960457d9edd2abc521557f28562e546e27b81 From 97f64374a9f34012c8884dbd629a896ec6ed8475 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Fri, 26 Sep 2025 16:30:08 -0700 Subject: [PATCH 323/537] formatting_options: fix alternate docs 0b/0o mixup The descriptions of the alternate forms of Octal and Binary were swapped in the doc comment for FormattingOptions::alternate(). --- library/core/src/fmt/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index b6de89253089..fcd2e52101ff 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -386,8 +386,8 @@ impl FormattingOptions { /// used. The alternate forms are: /// - [`Debug`] : pretty-print the [`Debug`] formatting (adds linebreaks and indentation) /// - [`LowerHex`] as well as [`UpperHex`] - precedes the argument with a `0x` - /// - [`Octal`] - precedes the argument with a `0b` - /// - [`Binary`] - precedes the argument with a `0o` + /// - [`Octal`] - precedes the argument with a `0o` + /// - [`Binary`] - precedes the argument with a `0b` #[unstable(feature = "formatting_options", issue = "118117")] pub const fn alternate(&mut self, alternate: bool) -> &mut Self { if alternate { From bb48c162b62ce20c5f51b6a435ca2ba7bb918d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 24 Sep 2025 23:25:29 +0000 Subject: [PATCH 324/537] Simplify logic slightly --- compiler/rustc_parse/src/parser/expr.rs | 37 +++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2f4158450d83..8046abcd70bd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3612,20 +3612,36 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1) } + fn is_likely_struct_lit(&self) -> bool { + // `{ ident, ` and `{ ident: ` cannot start a block. + self.look_ahead(1, |t| t.is_ident()) + && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) + } + fn maybe_parse_struct_expr( &mut self, qself: &Option>, path: &ast::Path, ) -> Option>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - let is_ident = self.look_ahead(1, |t| t.is_ident()); - let is_comma = self.look_ahead(2, |t| t == &token::Comma); - let is_colon = self.look_ahead(2, |t| t == &token::Colon); - match (struct_allowed, is_ident, is_comma, is_colon) { - (false, true, true, _) | (false, true, _, true) => { + match (struct_allowed, self.is_likely_struct_lit()) { + // A struct literal isn't expected and one is pretty much assured not to be present. The + // only situation that isn't detected is when a struct with a single field was attempted + // in a place where a struct literal wasn't expected, but regular parser errors apply. + // Happy path. + (false, false) => None, + (true, _) => { + // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for + // any kind of recovery. Happy path. + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + Some(self.parse_expr_struct(qself.clone(), path.clone(), true)) + } + (false, true) => { // We have something like `match foo { bar,` or `match foo { bar:`, which means the // user might have meant to write a struct literal as part of the `match` - // discriminant. + // discriminant. This is done purely for error recovery. let snapshot = self.create_snapshot_for_diagnostic(); if let Err(err) = self.expect(exp!(OpenBrace)) { return Some(Err(err)); @@ -3651,15 +3667,6 @@ impl<'a> Parser<'a> { } } } - (true, _, _, _) => { - // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for - // any kind of recovery. - if let Err(err) = self.expect(exp!(OpenBrace)) { - return Some(Err(err)); - } - Some(self.parse_expr_struct(qself.clone(), path.clone(), true)) - } - (false, _, _, _) => None, } } From fe3e124e8a4e5ba3dd92b99359bd6f4905eded19 Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Fri, 26 Sep 2025 17:05:30 -0700 Subject: [PATCH 325/537] doc: fix a typo in platform-support.md --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 619eebd15bd3..67882bb38132 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -121,6 +121,7 @@ - [\*-unknown-hermit](platform-support/hermit.md) - [\*-unknown-freebsd](platform-support/freebsd.md) - [\*-unknown-managarm-mlibc](platform-support/managarm.md) + - [\*-unknown-motor](platform-support/motor.md) - [\*-unknown-netbsd\*](platform-support/netbsd.md) - [\*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-redox](platform-support/redox.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 99c8e365f5cf..b29d01a13873 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -431,7 +431,7 @@ target | std | host | notes `x86_64-unknown-l4re-uclibc` | ? | | [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc [`x86_64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | x86_64 Managarm -[`x86_64-unknown-motor`[(platform-support/motor.md) | ? | | x86_64 Motor OS +[`x86_64-unknown-motor`](platform-support/motor.md) | ? | | x86_64 Motor OS [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD [`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ | | `x86_64-uwp-windows-gnu` | ✓ | | From d8a1edc718537fc595dc731fcb89f17378de6af2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 27 Sep 2025 18:23:18 +1000 Subject: [PATCH 326/537] Use `PanicHookInfo::payload_as_str` now that it's stable in beta --- src/tools/compiletest/src/panic_hook.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/tools/compiletest/src/panic_hook.rs b/src/tools/compiletest/src/panic_hook.rs index 1661ca6dabe8..4f1e2547518f 100644 --- a/src/tools/compiletest/src/panic_hook.rs +++ b/src/tools/compiletest/src/panic_hook.rs @@ -42,7 +42,7 @@ fn custom_panic_hook(default_hook: &PanicHook, info: &panic::PanicHookInfo<'_>) let thread = thread::current().name().unwrap_or("(test runner)").to_owned(); let location = get_location(info); - let payload = payload_as_str(info).unwrap_or("Box"); + let payload = info.payload_as_str().unwrap_or("Box"); let backtrace = Backtrace::capture(); writeln!(out, "\nthread '{thread}' panicked at {location}:\n{payload}").unwrap(); @@ -72,19 +72,6 @@ fn get_location<'a>(info: &'a PanicHookInfo<'_>) -> &'a dyn Display { } } -/// FIXME(Zalathar): Replace with `PanicHookInfo::payload_as_str` when that's -/// stable in beta. -fn payload_as_str<'a>(info: &'a PanicHookInfo<'_>) -> Option<&'a str> { - let payload = info.payload(); - if let Some(s) = payload.downcast_ref::<&str>() { - Some(s) - } else if let Some(s) = payload.downcast_ref::() { - Some(s) - } else { - None - } -} - fn rust_backtrace_full() -> bool { static RUST_BACKTRACE_FULL: LazyLock = LazyLock::new(|| matches!(env::var("RUST_BACKTRACE").as_deref(), Ok("full"))); From 95c146a0c1ff987c8263a2ddb7dced4e5b545842 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 26 Sep 2025 15:55:42 +0200 Subject: [PATCH 327/537] Fix tracking issue number for feature(macro_attr) The ability to define an attribute macro with `macro_rules!` is tracked at https://github.com/rust-lang/rust/issues/143547, not https://github.com/rust-lang/rust/issues/83527 --- compiler/rustc_feature/src/unstable.rs | 2 +- tests/ui/feature-gates/feature-gate-macro-attr.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6ef0df72365e..158cf8d2db32 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -554,7 +554,7 @@ declare_features! ( /// Allows fused `loop`/`match` for direct intraprocedural jumps. (incomplete, loop_match, "1.90.0", Some(132306)), /// Allow `macro_rules!` attribute rules - (unstable, macro_attr, "1.91.0", Some(83527)), + (unstable, macro_attr, "1.91.0", Some(143547)), /// Allow `macro_rules!` derive rules (unstable, macro_derive, "1.91.0", Some(143549)), /// Give access to additional metadata about declarative macro meta-variables. diff --git a/tests/ui/feature-gates/feature-gate-macro-attr.stderr b/tests/ui/feature-gates/feature-gate-macro-attr.stderr index b58418527c5b..75bc93e80271 100644 --- a/tests/ui/feature-gates/feature-gate-macro-attr.stderr +++ b/tests/ui/feature-gates/feature-gate-macro-attr.stderr @@ -4,7 +4,7 @@ error[E0658]: `macro_rules!` attributes are unstable LL | macro_rules! myattr { attr() {} => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #83527 for more information + = note: see issue #143547 for more information = help: add `#![feature(macro_attr)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date From 7c00bccd3b3eb6717e3c801123107962e671e48f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 29 Mar 2025 00:53:59 +0100 Subject: [PATCH 328/537] Implement RFC 3631 --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 - compiler/rustc_passes/messages.ftl | 9 + compiler/rustc_passes/src/check_attr.rs | 53 ++- compiler/rustc_passes/src/errors.rs | 14 +- compiler/rustc_span/src/symbol.rs | 4 + library/alloc/src/lib.rs | 29 +- library/core/src/lib.rs | 69 ++-- library/std/src/lib.rs | 16 +- src/librustdoc/clean/cfg.rs | 30 ++ src/librustdoc/clean/inline.rs | 15 +- src/librustdoc/clean/mod.rs | 10 +- src/librustdoc/clean/types.rs | 306 +++++++++++++----- src/librustdoc/doctest/rust.rs | 11 +- src/librustdoc/formats/cache.rs | 2 - src/librustdoc/passes/propagate_doc_cfg.rs | 136 +++++--- src/librustdoc/visit_ast.rs | 27 -- 16 files changed, 521 insertions(+), 212 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9ab5b0b35472..fe9cc8e61ed5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -182,8 +182,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( "experimental" { - cfg => doc_cfg - cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 870e0a90b542..19014f37c662 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -143,6 +143,15 @@ passes_doc_attribute_not_attribute = passes_doc_cfg_hide_takes_list = `#[doc(cfg_hide(...))]` takes a list of attributes +passes_doc_auto_cfg_expects_hide_or_show = + `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` + +passes_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` only expects a list of items + +passes_doc_auto_cfg_wrong_literal = + `expected boolean for #[doc(auto_cfg = ...)]` + passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 007353f136d5..3dc232a35ec3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1160,16 +1160,43 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. - /// - fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) { - if meta.meta_item_list().is_none() { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocCfgHideTakesList, - ); + /// Check that the `#![doc(auto_cfg(..))]` attribute has expected input. + fn check_doc_auto_cfg(&self, meta: &MetaItemInner, hir_id: HirId) { + let MetaItemInner::MetaItem(meta) = meta else { + unreachable!(); + }; + match &meta.kind { + MetaItemKind::Word => {} + MetaItemKind::NameValue(lit) => { + if !matches!(lit.kind, LitKind::Bool(_)) { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgWrongLiteral, + ); + } + } + MetaItemKind::List(list) => { + for item in list { + let Some(attr_name) = item.name() else { continue }; + if attr_name != sym::hide && attr_name != sym::show { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgExpectsHideOrShow, + ); + } else if item.meta_item_list().is_none() { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgHideShowExpectsList { attr_name: attr_name.as_str() }, + ); + } + } + } } } @@ -1245,10 +1272,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_attr_crate_level(attr, style, meta, hir_id); } - Some(sym::cfg_hide) => { - if self.check_attr_crate_level(attr, style, meta, hir_id) { - self.check_doc_cfg_hide(meta, hir_id); - } + Some(sym::auto_cfg) => { + self.check_doc_auto_cfg(meta, hir_id); } Some(sym::inline | sym::no_inline) => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cfd6b9e6dffa..6cc0bd6ce48b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -309,8 +309,18 @@ pub(crate) struct DocTestLiteral; pub(crate) struct DocTestTakesList; #[derive(LintDiagnostic)] -#[diag(passes_doc_cfg_hide_takes_list)] -pub(crate) struct DocCfgHideTakesList; +#[diag(passes_doc_auto_cfg_wrong_literal)] +pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_expects_hide_or_show)] +pub(crate) struct DocAutoCfgExpectsHideOrShow; + +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_hide_show_expects_list)] +pub(crate) struct DocAutoCfgHideShowExpectsList<'a> { + pub attr_name: &'a str, +} #[derive(LintDiagnostic)] #[diag(passes_doc_test_unknown_any)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index faf32523baae..e80a98994dbb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -545,6 +545,7 @@ symbols! { attributes, audit_that, augmented_assignments, + auto_cfg, auto_traits, autodiff, autodiff_forward, @@ -1149,6 +1150,8 @@ symbols! { hashset_iter_ty, hexagon_target_feature, hidden, + hidden_cfg, + hide, hint, homogeneous_aggregate, host, @@ -1987,6 +1990,7 @@ symbols! { shl_assign, shorter_tail_lifetimes, should_panic, + show, shr, shr_assign, sig_dfl, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cba1ce40f75d..243fdc2e8436 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -64,14 +64,27 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] -#![doc(cfg_hide( - not(test), - no_global_oom_handling, - not(no_global_oom_handling), - not(no_rc), - not(no_sync), - target_has_atomic = "ptr" -))] +#![cfg_attr( + bootstrap, + doc(cfg_hide( + not(test), + no_global_oom_handling, + not(no_global_oom_handling), + not(no_rc), + not(no_sync), + target_has_atomic = "ptr" + )) +)] +#![cfg_attr( + not(bootstrap), + doc(auto_cfg(hide( + test, + no_global_oom_handling, + no_rc, + no_sync, + target_has_atomic = "ptr" + ))) +)] #![doc(rust_logo)] #![feature(rustdoc_internals)] #![no_std] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5d52bfb1b125..32a3d6c7042a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -51,27 +51,54 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![doc(cfg_hide( - no_fp_fmt_parse, - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64", - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr", - target_has_atomic_equal_alignment = "8", - target_has_atomic_equal_alignment = "16", - target_has_atomic_equal_alignment = "32", - target_has_atomic_equal_alignment = "64", - target_has_atomic_equal_alignment = "ptr", - target_has_atomic_load_store = "8", - target_has_atomic_load_store = "16", - target_has_atomic_load_store = "32", - target_has_atomic_load_store = "64", - target_has_atomic_load_store = "ptr", -))] +#![cfg_attr( + bootstrap, + doc(cfg_hide( + no_fp_fmt_parse, + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + )) +)] +#![cfg_attr( + not(bootstrap), + doc(auto_cfg(hide( + no_fp_fmt_parse, + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + ))) +)] #![no_core] #![rustc_coherence_is_core] #![rustc_preserve_ub_checks] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 233e41aa3453..93c91b615258 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -235,7 +235,21 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling)))] +#![cfg_attr( + bootstrap, + doc(cfg_hide( + not(test), + no_global_oom_handling, + not(no_global_oom_handling) + )) +)] +#![cfg_attr( + not(bootstrap), + doc(auto_cfg(hide( + test, + no_global_oom_handling, + ))) +)] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 8feca1367fc9..aa614b73dea7 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -256,6 +256,36 @@ impl Cfg { fn omit_preposition(&self) -> bool { matches!(self, Cfg::True | Cfg::False) } + + pub(crate) fn strip_hidden(&self, hidden: &FxHashSet) -> Option { + match self { + Self::True | Self::False => Some(self.clone()), + Self::Cfg(..) => { + if !hidden.contains(self) { + Some(self.clone()) + } else { + None + } + } + Self::Not(cfg) => { + if let Some(cfg) = cfg.strip_hidden(hidden) { + Some(Self::Not(Box::new(cfg))) + } else { + None + } + } + Self::Any(cfgs) => { + let cfgs = + cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::>(); + if cfgs.is_empty() { None } else { Some(Self::Any(cfgs)) } + } + Self::All(cfgs) => { + let cfgs = + cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::>(); + if cfgs.is_empty() { None } else { Some(Self::All(cfgs)) } + } + } + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8461e15c6c3f..8ffa6033c9b0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,10 +19,10 @@ use tracing::{debug, trace}; use super::{Item, extract_cfg_from_attrs}; use crate::clean::{ - self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item, - clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig, - clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics, - clean_variant_def, utils, + self, Attributes, CfgInfo, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, + clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, + clean_poly_fn_sig, clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, + clean_ty_generics, clean_variant_def, utils, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -409,6 +409,7 @@ pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, old_attrs: &[hir::Attribute], new_attrs: Option<(&[hir::Attribute], Option)>, + cfg_info: &mut CfgInfo, ) -> (clean::Attributes, Option>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export @@ -423,12 +424,12 @@ pub(crate) fn merge_attrs( } else { Attributes::from_hir(&both) }, - extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(both.iter(), cx.tcx, cfg_info), ) } else { ( Attributes::from_hir(old_attrs), - extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, cfg_info), ) } } @@ -604,7 +605,7 @@ pub(crate) fn build_impl( }); } - let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); + let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default()); trace!("merged_attrs={merged_attrs:?}"); trace!( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0afb969d5c84..c6339dd47559 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -212,18 +212,10 @@ fn generate_item_with_correct_attrs( // We only keep the item's attributes. target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect() }; - let cfg = extract_cfg_from_attrs( - attrs.iter().map(move |(attr, _)| match attr { - Cow::Borrowed(attr) => *attr, - Cow::Owned(attr) => attr, - }), - cx.tcx, - &cx.cache.hidden_cfg, - ); let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); let name = renamed.or(Some(name)); - let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg); + let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, None); // FIXME (GuillaumeGomez): Should we also make `inline_stmt_id` a `Vec` instead of an `Option`? item.inner.inline_stmt_id = import_ids.first().copied(); item diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ff513c71035d..63e8357801c0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,7 +6,8 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_ast::ast::{LitKind, MetaItemInner, MetaItemKind}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -467,7 +468,7 @@ impl Item { name, kind, Attributes::from_hir(hir_attrs), - extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), + None, ) } @@ -902,30 +903,6 @@ impl ItemKind { | AttributeItem => [].iter(), } } - - /// Returns `true` if this item does not appear inside an impl block. - pub(crate) fn is_non_assoc(&self) -> bool { - matches!( - self, - StructItem(_) - | UnionItem(_) - | EnumItem(_) - | TraitItem(_) - | ModuleItem(_) - | ExternCrateItem { .. } - | FunctionItem(_) - | TypeAliasItem(_) - | StaticItem(_) - | ConstantItem(_) - | TraitAliasItem(_) - | ForeignFunctionItem(_, _) - | ForeignStaticItem(_, _) - | ForeignTypeItem - | MacroItem(_) - | ProcMacroItem(_) - | PrimitiveItem(_) - ) - } } #[derive(Clone, Debug)] @@ -945,14 +922,85 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( .flatten() } +#[derive(Clone, Debug)] +pub(crate) struct CfgInfo { + hidden_cfg: FxHashSet, + current_cfg: Cfg, + doc_auto_cfg_active: bool, + parent_is_doc_cfg: bool, +} + +impl Default for CfgInfo { + fn default() -> Self { + Self { + hidden_cfg: [ + Cfg::Cfg(sym::test, None), + Cfg::Cfg(sym::doc, None), + Cfg::Cfg(sym::doctest, None), + ] + .into_iter() + .collect(), + current_cfg: Cfg::True, + doc_auto_cfg_active: true, + parent_is_doc_cfg: false, + } + } +} + +fn show_hide_show_conflict_error( + tcx: TyCtxt<'_>, + item_span: rustc_span::Span, + previous: rustc_span::Span, +) { + let mut diag = tcx.sess.dcx().struct_span_err( + item_span, + format!( + "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item" + ), + ); + diag.span_note(previous, "first change was here"); + diag.emit(); +} + +fn handle_auto_cfg_hide_show( + tcx: TyCtxt<'_>, + cfg_info: &mut CfgInfo, + sub_attr: &MetaItemInner, + is_show: bool, + new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, + new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, +) { + if let MetaItemInner::MetaItem(item) = sub_attr + && let MetaItemKind::List(items) = &item.kind + { + for item in items { + // Cfg parsing errors should already have been reported in `rustc_passes::check_attr`. + if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) { + if is_show { + if let Some(span) = new_hide_attrs.get(&(key, value)) { + show_hide_show_conflict_error(tcx, item.span(), *span); + } else { + new_show_attrs.insert((key, value), item.span()); + } + cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value)); + } else { + if let Some(span) = new_show_attrs.get(&(key, value)) { + show_hide_show_conflict_error(tcx, item.span(), *span); + } else { + new_hide_attrs.insert((key, value), item.span()); + } + cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value)); + } + } + } + } +} + pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator + Clone>( attrs: I, tcx: TyCtxt<'_>, - hidden_cfg: &FxHashSet, + cfg_info: &mut CfgInfo, ) -> Option> { - let doc_cfg_active = tcx.features().doc_cfg(); - let doc_auto_cfg_active = tcx.features().doc_auto_cfg(); - fn single(it: T) -> Option { let mut iter = it.into_iter(); let item = iter.next()?; @@ -962,56 +1010,168 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator Some(item) } - let mut cfg = if doc_cfg_active || doc_auto_cfg_active { - let mut doc_cfg = attrs - .clone() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|attr| attr.has_name(sym::cfg)) - .peekable(); - if doc_cfg.peek().is_some() && doc_cfg_active { - let sess = tcx.sess; + let mut new_show_attrs = FxHashMap::default(); + let mut new_hide_attrs = FxHashMap::default(); - doc_cfg.fold(Cfg::True, |mut cfg, item| { - if let Some(cfg_mi) = - item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess)) - { - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => { - sess.dcx().span_err(e.span, e.msg); + let mut doc_cfg = attrs + .clone() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes. + if doc_cfg.peek().is_some() { + let sess = tcx.sess; + // We overwrite existing `cfg`. + if !cfg_info.parent_is_doc_cfg { + cfg_info.current_cfg = Cfg::True; + cfg_info.parent_is_doc_cfg = true; + } + for attr in doc_cfg { + if let Some(cfg_mi) = + attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess)) + { + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg_info.current_cfg &= new_cfg, + Err(e) => { + sess.dcx().span_err(e.span, e.msg); + } + } + } + } + } else { + cfg_info.parent_is_doc_cfg = false; + } + + let mut changed_auto_active_status = None; + + // First we get all `doc(auto_cfg)` attributes. + for attr in attrs.clone() { + if let Some(ident) = attr.ident() + && ident.name == sym::doc + && let Some(attrs) = attr.meta_item_list() + { + for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) { + let MetaItemInner::MetaItem(attr) = attr else { + continue; + }; + match &attr.kind { + MetaItemKind::Word => { + if let Some(first_change) = changed_auto_active_status { + if !cfg_info.doc_auto_cfg_active { + tcx.sess.dcx().struct_span_err( + vec![first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ).emit(); + return None; + } + } else { + changed_auto_active_status = Some(attr.span); + } + cfg_info.doc_auto_cfg_active = true; + } + MetaItemKind::NameValue(lit) => { + if let LitKind::Bool(value) = lit.kind { + if let Some(first_change) = changed_auto_active_status { + if cfg_info.doc_auto_cfg_active != value { + tcx.sess.dcx().struct_span_err( + vec![first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ).emit(); + return None; + } + } else { + changed_auto_active_status = Some(attr.span); + } + cfg_info.doc_auto_cfg_active = value; + } + } + MetaItemKind::List(sub_attrs) => { + if let Some(first_change) = changed_auto_active_status { + if !cfg_info.doc_auto_cfg_active { + tcx.sess.dcx().struct_span_err( + vec![first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ).emit(); + return None; + } + } else { + changed_auto_active_status = Some(attr.span); + } + // Whatever happens next, the feature is enabled again. + cfg_info.doc_auto_cfg_active = true; + for sub_attr in sub_attrs.iter() { + if let Some(ident) = sub_attr.ident() + && (ident.name == sym::show || ident.name == sym::hide) + { + handle_auto_cfg_hide_show( + tcx, + cfg_info, + &sub_attr, + ident.name == sym::show, + &mut new_show_attrs, + &mut new_hide_attrs, + ); + } } } } - cfg - }) - } else if doc_auto_cfg_active { - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because - // `doc(cfg())` overrides `cfg()`). - attrs - .clone() - .filter(|attr| attr.has_name(sym::cfg_trace)) - .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else { - Cfg::True - } - } else { - Cfg::True - }; - - // treat #[target_feature(enable = "feat")] attributes as if they were - // #[doc(cfg(target_feature = "feat"))] attributes as well - if let Some(features) = - find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features) - { - for (feature, _) in features { - cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); + } } } - if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) } + // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because + // `doc(cfg())` overrides `cfg()`). + for attr in attrs { + let Some(ident) = attr.ident() else { continue }; + match ident.name { + sym::cfg | sym::cfg_trace if !cfg_info.parent_is_doc_cfg => { + if let Some(attr) = single(attr.meta_item_list()?) + && let Ok(new_cfg) = Cfg::parse(&attr) + { + cfg_info.current_cfg &= new_cfg; + } + } + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well + sym::target_feature + if let Some(attrs) = attr.meta_item_list() => + { + for attr in attrs { + if attr.has_name(sym::enable) && attr.value_str().is_some() { + // Clone `enable = "feat"`, change to `target_feature = "feat"`. + // Unwrap is safe because `value_str` succeeded above. + let mut meta = attr.meta_item().unwrap().clone(); + meta.path = + ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); + + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { + cfg_info.current_cfg &= feat_cfg; + } + } + } + } + _ => {} + } + } + + // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing + // to be done here. + if !cfg_info.doc_auto_cfg_active && !cfg_info.parent_is_doc_cfg { + None + } else if cfg_info.parent_is_doc_cfg { + if cfg_info.current_cfg == Cfg::True { + None + } else { + Some(Arc::new(cfg_info.current_cfg.clone())) + } + } else { + // Since we always want to collect all `cfg` items, we remove the hidden ones afterward. + match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) { + None | Some(Cfg::True) => None, + Some(cfg) => Some(Arc::new(cfg)), + } + } } pub(crate) trait NestedAttributesExt { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index f5ec828187a5..b9367b880057 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -5,7 +5,6 @@ use std::env; use std::sync::Arc; use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; use rustc_middle::hir::nested_filter; @@ -15,7 +14,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym}; use super::{DocTestVisitor, ScrapedDocTest}; -use crate::clean::{Attributes, extract_cfg_from_attrs}; +use crate::clean::{Attributes, CfgInfo, extract_cfg_from_attrs}; use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine}; struct RustCollector { @@ -120,9 +119,11 @@ impl HirCollector<'_> { nested: F, ) { let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some(ref cfg) = - extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default()) - && !cfg.matches(&self.tcx.sess.psess) + if let Some(ref cfg) = extract_cfg_from_attrs( + ast_attrs.iter(), + self.tcx, + &mut CfgInfo::default(), + ) && !cfg.matches(&self.tcx.sess.psess) { return; } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 29b4c4caaf86..a19d254ea95f 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -125,8 +125,6 @@ pub(crate) struct Cache { /// /// Links are indexed by the DefId of the item they document. pub(crate) intra_doc_links: FxHashMap>, - /// Cfg that have been hidden via #![doc(cfg_hide(...))] - pub(crate) hidden_cfg: FxHashSet, /// Contains the list of `DefId`s which have been inlined. It is used when generating files /// to check if a stripped item should get its file generated or not: if it's inside a diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index eddafa9ba8e4..957a1f56c718 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -2,11 +2,15 @@ use std::sync::Arc; +use rustc_ast::token::{Token, TokenKind}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_hir::def_id::LocalDefId; +use rustc_hir::{AttrArgs, Attribute}; +use rustc_span::symbol::sym; use crate::clean::cfg::Cfg; use crate::clean::inline::{load_attrs, merge_attrs}; -use crate::clean::{Crate, Item, ItemKind}; +use crate::clean::{CfgInfo, Crate, Item, ItemKind}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; @@ -18,70 +22,119 @@ pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { }; pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { - CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr) + CfgPropagator { parent_cfg: None, parent: None, cx, cfg_info: CfgInfo::default() } + .fold_crate(cr) } struct CfgPropagator<'a, 'tcx> { parent_cfg: Option>, parent: Option, cx: &'a mut DocContext<'tcx>, + cfg_info: CfgInfo, +} + +fn should_retain(token: &TokenTree) -> bool { + // We only keep `doc(cfg)` items. + matches!( + token, + TokenTree::Token( + Token { + kind: TokenKind::Ident( + ident, + _, + ), + .. + }, + _, + ) if *ident == sym::cfg, + ) +} + +fn filter_tokens_from_list(args_tokens: &TokenStream) -> Vec { + let mut tokens = Vec::with_capacity(args_tokens.len()); + let mut skip_next_delimited = false; + for token in args_tokens.iter() { + match token { + TokenTree::Delimited(..) => { + if !skip_next_delimited { + tokens.push(token.clone()); + } + skip_next_delimited = false; + } + token if should_retain(token) => { + skip_next_delimited = false; + tokens.push(token.clone()); + } + _ => { + skip_next_delimited = true; + } + } + } + tokens +} + +// We only care about `#[cfg()]` and `#[doc(cfg())]`, we discard everything else. +fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { + for attr in new_attrs { + if attr.is_doc_comment() { + continue; + } + let mut attr = attr.clone(); + if let Attribute::Unparsed(ref mut normal) = attr + && let [ident] = &*normal.path.segments + { + let ident = ident.name; + if ident == sym::doc + && let AttrArgs::Delimited(args) = &mut normal.args + { + let tokens = filter_tokens_from_list(&args.tokens); + args.tokens = TokenStream::new(tokens); + attrs.push(attr); + } else if ident == sym::cfg_trace { + // If it's a `cfg()` attribute, we keep it. + attrs.push(attr); + } + } + } } impl CfgPropagator<'_, '_> { // Some items need to merge their attributes with their parents' otherwise a few of them // (mostly `cfg` ones) will be missing. fn merge_with_parent_attributes(&mut self, item: &mut Item) { - let check_parent = match &item.kind { - // impl blocks can be in different modules with different cfg and we need to get them - // as well. - ItemKind::ImplItem(_) => false, - kind if kind.is_non_assoc() => true, - _ => return, - }; - - let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) else { - return; - }; - - if check_parent { - let expected_parent = self.cx.tcx.opt_local_parent(def_id); - // If parents are different, it means that `item` is a reexport and we need - // to compute the actual `cfg` by iterating through its "real" parents. - if self.parent.is_some() && self.parent == expected_parent { - return; + let mut attrs = Vec::new(); + // We only need to merge an item attributes with its parent's in case it's an impl as an + // impl might not be defined in the same module as the item it implements. + // + // Otherwise, `cfg_info` already tracks everything we need so nothing else to do! + if matches!(item.kind, ItemKind::ImplItem(_)) + && let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) + { + let mut next_def_id = def_id; + while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) { + let x = load_attrs(self.cx, parent_def_id.to_def_id()); + add_only_cfg_attributes(&mut attrs, x); + next_def_id = parent_def_id; } } - let mut attrs = Vec::new(); - let mut next_def_id = def_id; - while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) { - attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id())); - next_def_id = parent_def_id; - } - - let (_, cfg) = - merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None))); + let (_, cfg) = merge_attrs( + self.cx, + item.attrs.other_attrs.as_slice(), + Some((&attrs, None)), + &mut self.cfg_info, + ); item.inner.cfg = cfg; } } impl DocFolder for CfgPropagator<'_, '_> { fn fold_item(&mut self, mut item: Item) -> Option { + let old_cfg_info = self.cfg_info.clone(); let old_parent_cfg = self.parent_cfg.clone(); self.merge_with_parent_attributes(&mut item); - - let new_cfg = match (self.parent_cfg.take(), item.inner.cfg.take()) { - (None, None) => None, - (Some(rc), None) | (None, Some(rc)) => Some(rc), - (Some(mut a), Some(b)) => { - let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc)); - *Arc::make_mut(&mut a) &= b; - Some(a) - } - }; - self.parent_cfg = new_cfg.clone(); - item.inner.cfg = new_cfg; + self.parent_cfg = item.inner.cfg.clone(); let old_parent = if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) { @@ -90,6 +143,7 @@ impl DocFolder for CfgPropagator<'_, '_> { self.parent.take() }; let result = self.fold_item_recur(item); + self.cfg_info = old_cfg_info; self.parent_cfg = old_parent_cfg; self.parent = old_parent; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index cd28322f5901..ac67871b0cb7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,6 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{Symbol, kw, sym}; use tracing::debug; -use crate::clean::cfg::Cfg; use crate::clean::utils::{inherits_doc_hidden, should_ignore_res}; use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain}; use crate::core; @@ -178,32 +177,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - self.cx.cache.hidden_cfg = self - .cx - .tcx - .hir_attrs(CRATE_HIR_ID) - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) - .filter(|attr| attr.has_name(sym::cfg_hide)) - .flat_map(|attr| { - attr.meta_item_list() - .unwrap_or(&[]) - .iter() - .filter_map(|attr| { - Cfg::parse(attr) - .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg)) - .ok() - }) - .collect::>() - }) - .chain([ - Cfg::Cfg(sym::test, None), - Cfg::Cfg(sym::doc, None), - Cfg::Cfg(sym::doctest, None), - ]) - .collect(); - self.cx.cache.exact_paths = self.exact_paths; top_level_module } From 6537278e114a98ea6f2c80d7d7ffacb2868be770 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 29 Mar 2025 00:54:22 +0100 Subject: [PATCH 329/537] Update rustdoc tests --- tests/rustdoc-ui/cfg-hide-show-conflict.rs | 2 ++ .../rustdoc-ui/cfg-hide-show-conflict.stderr | 14 +++++++++ tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs | 5 +-- .../feature-gate-doc_cfg_hide.stderr | 11 +++---- tests/rustdoc-ui/invalid-cfg.rs | 2 +- tests/rustdoc-ui/lints/doc_cfg_hide.rs | 9 ++---- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 31 ++++++------------- tests/rustdoc/doc-cfg/doc-cfg-hide.rs | 8 ++--- .../rustdoc/doc-cfg/doc-cfg-implicit-gate.rs | 2 +- tests/rustdoc/doc_auto_cfg_reexports.rs | 21 +++++++++++++ 10 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 tests/rustdoc-ui/cfg-hide-show-conflict.rs create mode 100644 tests/rustdoc-ui/cfg-hide-show-conflict.stderr create mode 100644 tests/rustdoc/doc_auto_cfg_reexports.rs diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.rs b/tests/rustdoc-ui/cfg-hide-show-conflict.rs new file mode 100644 index 000000000000..a8a50fe15c7e --- /dev/null +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.rs @@ -0,0 +1,2 @@ +#![doc(auto_cfg(hide(target_os = "linux")))] +#![doc(auto_cfg(show(windows, target_os = "linux")))] //~ ERROR diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr new file mode 100644 index 000000000000..d2d0564606a5 --- /dev/null +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -0,0 +1,14 @@ +error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item + --> $DIR/cfg-hide-show-conflict.rs:2:31 + | +LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] + | ^^^^^^^^^^^^^^^^^^^ + | +note: first change was here + --> $DIR/cfg-hide-show-conflict.rs:1:22 + | +LL | #![doc(auto_cfg(hide(target_os = "linux")))] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs index 17812018b9b7..e49285a01b81 100644 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs +++ b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs @@ -1,5 +1,6 @@ -#![doc(cfg_hide(test))] -//~^ ERROR `#[doc(cfg_hide)]` is experimental +// FIXME: Remove this file once feature is removed + +#![doc(cfg_hide(test))] //~ ERROR #[cfg(not(test))] pub fn public_fn() {} diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr index 55135986ffe7..b3eee2af7f73 100644 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr @@ -1,13 +1,10 @@ -error[E0658]: `#[doc(cfg_hide)]` is experimental - --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 +error: unknown `doc` attribute `cfg_hide` + --> $DIR/feature-gate-doc_cfg_hide.rs:3:8 | LL | #![doc(cfg_hide(test))] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | - = note: see issue #43781 for more information - = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: `#[deny(invalid_doc_attributes)]` on by default error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/rustdoc-ui/invalid-cfg.rs b/tests/rustdoc-ui/invalid-cfg.rs index d237b8605c06..aff36286c535 100644 --- a/tests/rustdoc-ui/invalid-cfg.rs +++ b/tests/rustdoc-ui/invalid-cfg.rs @@ -1,4 +1,4 @@ #![feature(doc_cfg)] #[doc(cfg = "x")] //~ ERROR not followed by parentheses #[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates -struct S {} +pub struct S {} diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.rs b/tests/rustdoc-ui/lints/doc_cfg_hide.rs index 9a8bce2a92aa..abf563184790 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.rs +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.rs @@ -1,7 +1,2 @@ -#![feature(doc_cfg_hide)] - -#![doc(cfg_hide = "test")] //~ ERROR -#![doc(cfg_hide)] //~ ERROR - -#[doc(cfg_hide(doc))] //~ ERROR -pub fn foo() {} +#![doc(auto_cfg(hide = "test"))] //~ ERROR +#![doc(auto_cfg(hide))] //~ ERROR diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index 0c9d0879b0ac..bb0e52eb666a 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,27 +1,16 @@ -error: this attribute can only be applied at the crate level - --> $DIR/doc_cfg_hide.rs:6:7 +error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items + --> $DIR/doc_cfg_hide.rs:1:8 | -LL | #[doc(cfg_hide(doc))] - | ^^^^^^^^^^^^^ +LL | #![doc(auto_cfg(hide = "test"))] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: read for more information = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute + +error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items + --> $DIR/doc_cfg_hide.rs:2:8 | -LL | #![doc(cfg_hide(doc))] - | + +LL | #![doc(auto_cfg(hide))] + | ^^^^^^^^^^^^^^ -error: `#[doc(cfg_hide(...))]` takes a list of attributes - --> $DIR/doc_cfg_hide.rs:3:8 - | -LL | #![doc(cfg_hide = "test")] - | ^^^^^^^^^^^^^^^^^ - -error: `#[doc(cfg_hide(...))]` takes a list of attributes - --> $DIR/doc_cfg_hide.rs:4:8 - | -LL | #![doc(cfg_hide)] - | ^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs index ceb1f99fae0d..cf906ede7e13 100644 --- a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs +++ b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs @@ -1,7 +1,7 @@ #![crate_name = "oud"] -#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)] +#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide, no_core)] -#![doc(cfg_hide(feature = "solecism"))] +#![doc(auto_cfg(hide(feature = "solecism")))] //@ has 'oud/struct.Solecism.html' //@ count - '//*[@class="stab portability"]' 0 @@ -18,7 +18,7 @@ pub struct Scribacious; //@ has 'oud/struct.Hyperdulia.html' //@ count - '//*[@class="stab portability"]' 1 -//@ matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +//@ matches - '//*[@class="stab portability"]' 'crate features hyperdulia only' //@ compile-flags:--cfg feature="hyperdulia" #[cfg(feature = "solecism")] #[cfg(feature = "hyperdulia")] @@ -26,7 +26,7 @@ pub struct Hyperdulia; //@ has 'oud/struct.Oystercatcher.html' //@ count - '//*[@class="stab portability"]' 1 -//@ matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only' +//@ matches - '//*[@class="stab portability"]' 'crate features oystercatcher only' //@ compile-flags:--cfg feature="oystercatcher" #[cfg(all(feature = "solecism", feature = "oystercatcher"))] pub struct Oystercatcher; diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs index b5b8d0f427bf..27923893bdda 100644 --- a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs +++ b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs @@ -2,6 +2,6 @@ #![crate_name = "xenogenous"] //@ has 'xenogenous/struct.Worricow.html' -//@ count - '//*[@class="stab portability"]' 0 +//@ count - '//*[@class="stab portability"]' 1 #[cfg(feature = "worricow")] pub struct Worricow; diff --git a/tests/rustdoc/doc_auto_cfg_reexports.rs b/tests/rustdoc/doc_auto_cfg_reexports.rs new file mode 100644 index 000000000000..f226c52e2ebf --- /dev/null +++ b/tests/rustdoc/doc_auto_cfg_reexports.rs @@ -0,0 +1,21 @@ +// Checks that `cfg` are correctly applied on inlined reexports. + +#![crate_name = "foo"] + +// Check with `std` item. +//@ has 'foo/index.html' '//*[@class="stab portability"]' 'Non-moustache' +//@ has 'foo/struct.C.html' '//*[@class="stab portability"]' \ +// 'Available on non-crate feature moustache only.' +#[cfg(not(feature = "moustache"))] +pub use std::cell::RefCell as C; + +// Check with local item. +mod x { + pub struct B; +} + +//@ has 'foo/index.html' '//*[@class="stab portability"]' 'Non-pistache' +//@ has 'foo/struct.B.html' '//*[@class="stab portability"]' \ +// 'Available on non-crate feature pistache only.' +#[cfg(not(feature = "pistache"))] +pub use crate::x::B; From 2d82c99f1e4a4e50b47f75d767b0d1d957357c1a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Apr 2025 17:01:00 +0200 Subject: [PATCH 330/537] Add "global" rustdoc test for RFC 3631 --- tests/rustdoc/doc_auto_cfg.rs | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/rustdoc/doc_auto_cfg.rs diff --git a/tests/rustdoc/doc_auto_cfg.rs b/tests/rustdoc/doc_auto_cfg.rs new file mode 100644 index 000000000000..cb7c0e3f5950 --- /dev/null +++ b/tests/rustdoc/doc_auto_cfg.rs @@ -0,0 +1,80 @@ +// Test covering RFC 3631 features. + +#![crate_name = "foo"] +#![feature(no_core)] +#![no_core] +#![no_std] + +#![doc(auto_cfg(hide(feature = "hidden")))] + +//@ has 'foo/index.html' +//@ !has - '//*[@class="stab portability"]' 'Non-moustache' +//@ has - '//*[@class="stab portability"]' 'Non-pistache' +//@ count - '//*[@class="stab portability"]' 1 + +//@ has 'foo/m/index.html' +//@ count - '//*[@title="Available on non-crate feature `hidden` only"]' 2 +#[cfg(not(feature = "hidden"))] +pub mod m { + //@ count 'foo/m/struct.A.html' '//*[@class="stab portability"]' 0 + pub struct A; + + //@ has 'foo/m/inner/index.html' '//*[@class="stab portability"]' 'Available on non-crate feature hidden only.' + #[doc(auto_cfg(show(feature = "hidden")))] + pub mod inner { + //@ has 'foo/m/inner/struct.B.html' '//*[@class="stab portability"]' 'Available on non-crate feature hidden only.' + pub struct B; + + //@ count 'foo/m/inner/struct.A.html' '//*[@class="stab portability"]' 0 + #[doc(auto_cfg(hide(feature = "hidden")))] + pub struct A; + } + + //@ has 'foo/m/struct.B.html' '//*[@class="stab portability"]' 'Available on non-crate feature hidden only.' + #[doc(auto_cfg(show(feature = "hidden")))] + pub struct B; +} + +//@ count 'foo/n/index.html' '//*[@title="Available on non-crate feature `moustache` only"]' 3 +//@ count - '//dl/dt' 4 +#[cfg(not(feature = "moustache"))] +#[doc(auto_cfg = false)] +pub mod n { + // Should not have `moustache` listed. + //@ count 'foo/n/struct.X.html' '//*[@class="stab portability"]' 0 + pub struct X; + + // Should re-enable `auto_cfg` and make `moustache` listed. + //@ has 'foo/n/struct.Y.html' '//*[@class="stab portability"]' \ + // 'Available on non-crate feature moustache only.' + #[doc(auto_cfg)] + pub struct Y; + + // Should re-enable `auto_cfg` and make `moustache` listed for itself + // and for `Y`. + //@ has 'foo/n/inner/index.html' '//*[@class="stab portability"]' \ + // 'Available on non-crate feature moustache only.' + #[doc(auto_cfg = true)] + pub mod inner { + //@ has 'foo/n/inner/struct.Y.html' '//*[@class="stab portability"]' \ + // 'Available on non-crate feature moustache only.' + pub struct Y; + } + + // Should re-enable `auto_cfg` and make `moustache` listed. + //@ has 'foo/n/struct.Z.html' '//*[@class="stab portability"]' \ + // 'Available on non-crate feature moustache only.' + #[doc(auto_cfg(hide(feature = "hidden")))] + pub struct Z; +} + +// Checking inheritance. +//@ has 'foo/o/index.html' '//*[@class="stab portability"]' \ +// 'Available on non-crate feature pistache only.' +#[doc(cfg(not(feature = "pistache")))] +pub mod o { + //@ has 'foo/o/struct.A.html' '//*[@class="stab portability"]' \ + // 'Available on non-crate feature pistache and non-crate feature tarte only.' + #[doc(cfg(not(feature = "tarte")))] + pub struct A; +} From 63aefe0737d0df886955f5a3aa68db865cd97f1b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Apr 2025 17:24:28 +0200 Subject: [PATCH 331/537] Strenghten checks for `doc(auto_cfg(show/hide))` attributes --- compiler/rustc_passes/messages.ftl | 3 +++ compiler/rustc_passes/src/check_attr.rs | 15 ++++++++++++++- compiler/rustc_passes/src/errors.rs | 6 ++++++ library/alloc/src/lib.rs | 1 - library/std/src/lib.rs | 8 +------- tests/rustdoc-ui/lints/doc_cfg_hide.rs | 1 + tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 8 +++++++- 7 files changed, 32 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 19014f37c662..8326ddaf194d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -149,6 +149,9 @@ passes_doc_auto_cfg_expects_hide_or_show = passes_doc_auto_cfg_hide_show_expects_list = `#![doc(auto_cfg({$attr_name}(...)))]` only expects a list of items +passes_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items + passes_doc_auto_cfg_wrong_literal = `expected boolean for #[doc(auto_cfg = ...)]` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3dc232a35ec3..38b67e2f9dc5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1187,7 +1187,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span, errors::DocAutoCfgExpectsHideOrShow, ); - } else if item.meta_item_list().is_none() { + } else if let Some(list) = item.meta_item_list() { + for item in list { + if item.meta_item_list().is_some() { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + item.span(), + errors::DocAutoCfgHideShowUnexpectedItem { + attr_name: attr_name.as_str(), + }, + ); + } + } + } else { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 6cc0bd6ce48b..1d2428c4f9a0 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -322,6 +322,12 @@ pub(crate) struct DocAutoCfgHideShowExpectsList<'a> { pub attr_name: &'a str, } +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_hide_show_unexpected_item)] +pub(crate) struct DocAutoCfgHideShowUnexpectedItem<'a> { + pub attr_name: &'a str, +} + #[derive(LintDiagnostic)] #[diag(passes_doc_test_unknown_any)] pub(crate) struct DocTestUnknownAny { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 243fdc2e8436..dc5d243e8823 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -78,7 +78,6 @@ #![cfg_attr( not(bootstrap), doc(auto_cfg(hide( - test, no_global_oom_handling, no_rc, no_sync, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 93c91b615258..ecd354f599e4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -243,13 +243,7 @@ not(no_global_oom_handling) )) )] -#![cfg_attr( - not(bootstrap), - doc(auto_cfg(hide( - test, - no_global_oom_handling, - ))) -)] +#![cfg_attr(not(bootstrap), doc(auto_cfg(hide(no_global_oom_handling))))] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.rs b/tests/rustdoc-ui/lints/doc_cfg_hide.rs index abf563184790..4f2625d00ce4 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.rs +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.rs @@ -1,2 +1,3 @@ #![doc(auto_cfg(hide = "test"))] //~ ERROR #![doc(auto_cfg(hide))] //~ ERROR +#![doc(auto_cfg(hide(not(windows))))] //~ ERROR diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index bb0e52eb666a..22501d63c3fb 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -12,5 +12,11 @@ error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items LL | #![doc(auto_cfg(hide))] | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/values items + --> $DIR/doc_cfg_hide.rs:3:22 + | +LL | #![doc(auto_cfg(hide(not(windows))))] + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors From 4847eaf6d25473ad1b8dab4d8d6cd62520f55e0e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Apr 2025 17:49:08 +0200 Subject: [PATCH 332/537] Remove useless code in `propagate_doc_cfg.rs` --- src/librustdoc/passes/propagate_doc_cfg.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 957a1f56c718..1425687cd269 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,14 +1,10 @@ //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items. -use std::sync::Arc; - use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_hir::def_id::LocalDefId; use rustc_hir::{AttrArgs, Attribute}; use rustc_span::symbol::sym; -use crate::clean::cfg::Cfg; use crate::clean::inline::{load_attrs, merge_attrs}; use crate::clean::{CfgInfo, Crate, Item, ItemKind}; use crate::core::DocContext; @@ -22,13 +18,10 @@ pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { }; pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { - CfgPropagator { parent_cfg: None, parent: None, cx, cfg_info: CfgInfo::default() } - .fold_crate(cr) + CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr) } struct CfgPropagator<'a, 'tcx> { - parent_cfg: Option>, - parent: Option, cx: &'a mut DocContext<'tcx>, cfg_info: CfgInfo, } @@ -131,21 +124,11 @@ impl CfgPropagator<'_, '_> { impl DocFolder for CfgPropagator<'_, '_> { fn fold_item(&mut self, mut item: Item) -> Option { let old_cfg_info = self.cfg_info.clone(); - let old_parent_cfg = self.parent_cfg.clone(); self.merge_with_parent_attributes(&mut item); - self.parent_cfg = item.inner.cfg.clone(); - let old_parent = - if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) { - self.parent.replace(def_id) - } else { - self.parent.take() - }; let result = self.fold_item_recur(item); self.cfg_info = old_cfg_info; - self.parent_cfg = old_parent_cfg; - self.parent = old_parent; Some(result) } From 18df897221c57941956f77ef1f92261cf983577d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Apr 2025 16:18:27 +0200 Subject: [PATCH 333/537] Remove ui test for doc_cfg feature gate --- tests/ui/feature-gates/feature-gate-doc_cfg.rs | 6 +++++- tests/ui/feature-gates/feature-gate-doc_cfg.stderr | 13 ------------- 2 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-doc_cfg.stderr diff --git a/tests/ui/feature-gates/feature-gate-doc_cfg.rs b/tests/ui/feature-gates/feature-gate-doc_cfg.rs index b12b8a105718..83053e8c8bfd 100644 --- a/tests/ui/feature-gates/feature-gate-doc_cfg.rs +++ b/tests/ui/feature-gates/feature-gate-doc_cfg.rs @@ -1,2 +1,6 @@ -#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental +//@ build-pass + +// FIXME: Remove this test once `doc_cfg` feature is completely removed. + +#[doc(cfg(unix))] fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-doc_cfg.stderr b/tests/ui/feature-gates/feature-gate-doc_cfg.stderr deleted file mode 100644 index 5315aaeeb3ed..000000000000 --- a/tests/ui/feature-gates/feature-gate-doc_cfg.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: `#[doc(cfg)]` is experimental - --> $DIR/feature-gate-doc_cfg.rs:1:1 - | -LL | #[doc(cfg(unix))] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #43781 for more information - = help: add `#![feature(doc_cfg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. From d6ba93a3fee59a08820ee09ab7b3096ccfe99219 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Apr 2025 17:07:21 +0200 Subject: [PATCH 334/537] Remove `doc_cfg` related content from rustdoc book unstable features chapter --- src/doc/rustdoc/src/unstable-features.md | 82 ------------------------ 1 file changed, 82 deletions(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 4327a80cd083..a8856c2ecc77 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -56,88 +56,6 @@ It is also not emitted for foreign items, aliases, extern crates and imports. These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler and enabled with a `#![feature(...)]` attribute in your crate. -### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present - - * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) - -You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on. -This has two effects: - -1. doctests will only run on the appropriate platforms, and -2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining - that the item is only available on certain platforms. - -`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc]. -For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the -documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that -the item is supposed to be used on Windows. For example: - -```rust -#![feature(doc_cfg)] - -/// Token struct that can only be used on Windows. -#[cfg(any(windows, doc))] -#[doc(cfg(windows))] -pub struct WindowsToken; - -/// Token struct that can only be used on Unix. -#[cfg(any(unix, doc))] -#[doc(cfg(unix))] -pub struct UnixToken; - -/// Token struct that is only available with the `serde` feature -#[cfg(feature = "serde")] -#[doc(cfg(feature = "serde"))] -#[derive(serde::Deserialize)] -pub struct SerdeToken; -``` - -In this sample, the tokens will only appear on their respective platforms, but they will both appear -in documentation. - -`#[doc(cfg(...))]` was introduced to be used by the standard library and currently requires the -`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable -Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. - -### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]` - - * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) - -`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add -`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the -previous source code: - -```rust -#![feature(doc_auto_cfg)] - -/// Token struct that can only be used on Windows. -#[cfg(any(windows, doc))] -pub struct WindowsToken; - -/// Token struct that can only be used on Unix. -#[cfg(any(unix, doc))] -pub struct UnixToken; - -/// Token struct that is only available with the `serde` feature -#[cfg(feature = "serde")] -#[derive(serde::Deserialize)] -pub struct SerdeToken; -``` - -It'll render almost the same, the difference being that `doc` will also be displayed. To fix this, -you can use `doc_cfg_hide`: - -```rust -#![feature(doc_cfg_hide)] -#![doc(cfg_hide(doc))] -``` - -And `doc` won't show up anymore! - -[cfg-doc]: ./advanced-features.md -[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html -[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781 - ### Adding your trait to the "Notable traits" dialog * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040) From bb34332858fa6c675cbbaf421ad3986df22d86ef Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Apr 2025 11:53:49 +0200 Subject: [PATCH 335/537] Update book for `doc_cfg` feature --- src/doc/rustdoc/src/unstable-features.md | 268 +++++++++++++++++++++++ 1 file changed, 268 insertions(+) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index a8856c2ecc77..cfa1936f3d7f 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -719,3 +719,271 @@ pass `--doctest-build-arg ARG` for each argument `ARG`. ## `--generate-macro-expansion`: Generate macros expansion toggles in source code This flag enables the generation of toggles to expand macros in the HTML source code pages. + +## `#[doc(cfg)]` + +This feature aims at providing rustdoc users the possibility to add visual markers to the rendered documentation to know under which conditions an item is available (currently possible through the following unstable features: `doc_cfg`, `doc_auto_cfg` and `doc_cfg_hide`). + +It does not aim to allow having a same item with different `cfg`s to appear more than once in the generated documentation. + +It does not aim to document items which are *inactive* under the current configuration (i.e., “`cfg`ed out”). + +This features adds the following attributes: + + * `#[doc(auto_cfg)]`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]` + * `#[doc(cfg(...))]` + * `#![doc(auto_cfg(hide(...)))]` / `#[doc(auto_cfg(show(...)))]` + +All of these attributes can be added to a module or to the crate root, and they will be inherited by the child items unless another attribute overrides it. This is why "opposite" attributes like `auto_cfg(hide(...))` and `auto_cfg(show(...))` are provided: they allow a child item to override its parent. + +### `#[doc(auto_cfg)`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]` + +By default, `#[doc(auto_cfg)]` is enabled at the crate-level. When it's enabled, Rustdoc will automatically display `cfg(...)` compatibility information as-if the same `#[doc(cfg(...))]` had been specified. + +This attribute impacts the item on which it is used and its descendants. + +So if we take back the previous example: + +```rust +#[cfg(feature = "futures-io")] +pub mod futures {} +``` + +There's no need to "duplicate" the `cfg` into a `doc(cfg())` to make Rustdoc display it. + +In some situations, the detailed conditional compilation rules used to implement the feature might not serve as good documentation (for example, the list of supported platforms might be very long, and it might be better to document them in one place). To turn it off, add the `#[doc(auto_cfg = false)]` attribute on the item. + +If no argument is specified (ie `#[doc(auto_cfg)]`), it's the same as writing `#[doc(auto_cfg = true)]`. + +### `#[doc(cfg(...))]` + +This attribute provides a standardized format to override `#[cfg()]` attributes to document conditionally available items. Example: + +```rust,ignore (nightly) +// the "real" cfg condition +#[cfg(feature = "futures-io")] +// the `doc(cfg())` so it's displayed to the readers +#[doc(cfg(feature = "futures-io"))] +pub mod futures {} +``` + +It will display in the documentation for this module: + +```text +This is supported on feature="futures-io" only. +``` + +You can use it to display information in generated documentation, whether or not there is a `#[cfg()]` attribute: + +```rust,ignore (nightly) +#[doc(cfg(feature = "futures-io"))] +pub mod futures {} +``` + +It will be displayed exactly the same as the previous code. + +This attribute has the same syntax as conditional compilation, but it only causes documentation to be added. This means `#[doc(cfg(not(windows)))]` will not cause your docs to be hidden on non-windows targets, even though `#[cfg(not(windows))]` does do that. + +If `doc(auto_cfg)` is enabled on the item, `doc(cfg)` will override it anyway so in the two previous examples, even if the `doc(auto_cfg)` feature was enabled, it would still display the same thing. + +This attribute works on modules and on items. + +### `#[doc(auto_cfg(hide(...)))]` + +This attribute is used to prevent some `cfg` to be generated in the visual markers. It only applies to `#[doc(auto_cfg = true)]`, not to `#[doc(cfg(...))]`. So in the previous example: + +```rust,ignore (nightly) +#[cfg(any(unix, feature = "futures-io"))] +pub mod futures {} +``` + +It currently displays both `unix` and `feature = "futures-io"` into the documentation, which is not great. To prevent the `unix` cfg to ever be displayed, you can use this attribute at the crate root level: + +```rust,ignore (nightly) +#![doc(auto_cfg(hide(unix)))] +``` + +Or directly on a given item/module as it covers any of the item's descendants: + +```rust,ignore (nightly) +#[doc(auto_cfg(hide(unix)))] +#[cfg(any(unix, feature = "futures-io"))] +pub mod futures { + // `futures` and all its descendants won't display "unix" in their cfgs. +} +``` + +Then, the `unix` cfg will never be displayed into the documentation. + +Rustdoc currently hides `doc` and `doctest` attributes by default and reserves the right to change the list of "hidden by default" attributes. + +The attribute accepts only a list of identifiers or key/value items. So you can write: + +```rust,ignore (nightly) +#[doc(auto_cfg(hide(unix, doctest, feature = "something")))] +#[doc(auto_cfg(hide()))] +``` + +But you cannot write: + +```rust,ignore (nightly) +#[doc(auto_cfg(hide(not(unix))))] +``` + +So if we use `doc(auto_cfg(hide(unix)))`, it means it will hide all mentions of `unix`: + +```rust,ignore (nightly) +#[cfg(unix)] // nothing displayed +#[cfg(any(unix))] // nothing displayed +#[cfg(any(unix, windows))] // only `windows` displayed +``` + +However, it only impacts the `unix` cfg, not the feature: + +```rust,ignore (nightly) +#[cfg(feature = "unix")] // `feature = "unix"` is displayed +``` + +If `cfg_auto(show(...))` and `cfg_auto(hide(...))` are used to show/hide a same `cfg` on a same item, it'll emit an error. Example: + +```rust,ignore (nightly) +#[doc(auto_cfg(hide(unix)))] +#[doc(auto_cfg(show(unix)))] // Error! +pub fn foo() {} +``` + +Using this attribute will re-enable `auto_cfg` if it was disabled at this location: + +```rust,ignore (nightly) +#[doc(auto_cfg = false)] // Disabling `auto_cfg` +pub fn foo() {} +``` + +And using `doc(auto_cfg)` will re-enable it: + +```rust,ignore (nightly) +#[doc(auto_cfg = false)] // Disabling `auto_cfg` +pub mod module { + #[doc(auto_cfg(hide(unix)))] // `auto_cfg` is re-enabled. + pub fn foo() {} +} +``` + +However, using `doc(auto_cfg = ...)` and `doc(auto_cfg(...))` on the same item will emit an error: + +```rust,ignore (nightly) +#[doc(auto_cfg = false)] +#[doc(auto_cfg(hide(unix)))] // error +pub fn foo() {} +``` + +The reason behind this is that `doc(auto_cfg = ...)` enables or disables the feature, whereas `doc(auto_cfg(...))` enables it unconditionally, making the first attribute to appear useless as it will be overidden by the next `doc(auto_cfg)` attribute. + +### `#[doc(auto_cfg(show(...)))]` + +This attribute does the opposite of `#[doc(auto_cfg(hide(...)))]`: if you used `#[doc(auto_cfg(hide(...)))]` and want to revert its effect on an item and its descendants, you can use `#[doc(auto_cfg(show(...)))]`. +It only applies to `#[doc(auto_cfg = true)]`, not to `#[doc(cfg(...))]`. + +For example: + +```rust,ignore (nightly) +#[doc(auto_cfg(hide(unix)))] +#[cfg(any(unix, feature = "futures-io"))] +pub mod futures { + // `futures` and all its descendants won't display "unix" in their cfgs. + #[doc(auto_cfg(show(unix)))] + pub mod child { + // `child` and all its descendants will display "unix" in their cfgs. + } +} +``` + +The attribute accepts only a list of identifiers or key/value items. So you can write: + +```rust,ignore (nightly) +#[doc(auto_cfg(show(unix, doctest, feature = "something")))] +#[doc(auto_cfg(show()))] +``` + +But you cannot write: + +```rust,ignore (nightly) +#[doc(auto_cfg(show(not(unix))))] +``` + +If `auto_cfg(show(...))` and `auto_cfg(hide(...))` are used to show/hide a same `cfg` on a same item, it'll emit an error. Example: + +```rust,ignore (nightly) +#[doc(auto_cfg(show(unix)))] +#[doc(auto_cfg(hide(unix)))] // Error! +pub fn foo() {} +``` + +Using this attribute will re-enable `auto_cfg` if it was disabled at this location: + +```rust,ignore (nightly) +#[doc(auto_cfg = false)] // Disabling `auto_cfg` +#[doc(auto_cfg(show(unix)))] // `auto_cfg` is re-enabled. +pub fn foo() {} +``` + +## Inheritance + +Rustdoc merges `cfg` attributes from parent modules to its children. For example, in this case, the module `non_unix` will describe the entire compatibility matrix for the module, and not just its directly attached information: + +```rust,ignore (nightly) +#[doc(cfg(any(windows, unix)))] +pub mod desktop { + #[doc(cfg(not(unix)))] + pub mod non_unix { + // ... + } +} +``` + +This code will display: + +```text +Available on (Windows or Unix) and non-Unix only. +``` + +### Re-exports and inlining + +`cfg` attributes of a re-export are never merged with the re-exported item(s) attributes except if the re-export has the `#[doc(inline)]` attribute. In this case, the `cfg` of the re-exported item will be merged with the re-export's. + +When talking about "attributes merge", we mean that if the re-export has `#[cfg(unix)]` and the re-exported item has `#[cfg(feature = "foo")]`, you will only see `cfg(unix)` on the re-export and only `cfg(feature = "foo")` on the re-exported item, unless the re-export has `#[doc(inline)]`, then you will only see the re-exported item with both `cfg(unix)` and `cfg(feature = "foo")`. + +Example: + +```rust,ignore (nightly) +#[doc(cfg(any(windows, unix)))] +pub mod desktop { + #[doc(cfg(not(unix)))] + pub mod non_unix { + // code + } +} + +#[doc(cfg(target_os = "freebsd"))] +pub use desktop::non_unix as non_unix_desktop; +#[doc(cfg(target_os = "macos"))] +#[doc(inline)] +pub use desktop::non_unix as inlined_non_unix_desktop; +``` + +In this example, `non_unix_desktop` will only display `cfg(target_os = "freeebsd")` and not display any `cfg` from `desktop::non_unix`. + +On the contrary, `inlined_non_unix_desktop` will have cfgs from both the re-export and the re-exported item. + +So that also means that if a crate re-exports a foreign item, unless it has `#[doc(inline)]`, the `cfg` and `doc(cfg)` attributes will not be visible: + +```rust,ignore (nightly) +// dep: +#[cfg(feature = "a")] +pub struct S; + +// crate using dep: + +// There will be no mention of `feature = "a"` in the documentation. +pub use dep::S as Y; +``` From ed05315867b7dd17a456beaabc3faf36357f9447 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Apr 2025 12:02:48 +0200 Subject: [PATCH 336/537] Rename `CfgInfo::doc_auto_cfg_active` into `auto_cfg_active` --- src/librustdoc/clean/types.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 63e8357801c0..2ec97a57087a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -926,7 +926,7 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( pub(crate) struct CfgInfo { hidden_cfg: FxHashSet, current_cfg: Cfg, - doc_auto_cfg_active: bool, + auto_cfg_active: bool, parent_is_doc_cfg: bool, } @@ -941,7 +941,7 @@ impl Default for CfgInfo { .into_iter() .collect(), current_cfg: Cfg::True, - doc_auto_cfg_active: true, + auto_cfg_active: true, parent_is_doc_cfg: false, } } @@ -1058,7 +1058,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator match &attr.kind { MetaItemKind::Word => { if let Some(first_change) = changed_auto_active_status { - if !cfg_info.doc_auto_cfg_active { + if !cfg_info.auto_cfg_active { tcx.sess.dcx().struct_span_err( vec![first_change, attr.span], "`auto_cfg` was disabled and enabled more than once on the same item", @@ -1068,12 +1068,12 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } else { changed_auto_active_status = Some(attr.span); } - cfg_info.doc_auto_cfg_active = true; + cfg_info.auto_cfg_active = true; } MetaItemKind::NameValue(lit) => { if let LitKind::Bool(value) = lit.kind { if let Some(first_change) = changed_auto_active_status { - if cfg_info.doc_auto_cfg_active != value { + if cfg_info.auto_cfg_active != value { tcx.sess.dcx().struct_span_err( vec![first_change, attr.span], "`auto_cfg` was disabled and enabled more than once on the same item", @@ -1083,12 +1083,12 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } else { changed_auto_active_status = Some(attr.span); } - cfg_info.doc_auto_cfg_active = value; + cfg_info.auto_cfg_active = value; } } MetaItemKind::List(sub_attrs) => { if let Some(first_change) = changed_auto_active_status { - if !cfg_info.doc_auto_cfg_active { + if !cfg_info.auto_cfg_active { tcx.sess.dcx().struct_span_err( vec![first_change, attr.span], "`auto_cfg` was disabled and enabled more than once on the same item", @@ -1099,7 +1099,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator changed_auto_active_status = Some(attr.span); } // Whatever happens next, the feature is enabled again. - cfg_info.doc_auto_cfg_active = true; + cfg_info.auto_cfg_active = true; for sub_attr in sub_attrs.iter() { if let Some(ident) = sub_attr.ident() && (ident.name == sym::show || ident.name == sym::hide) @@ -1157,7 +1157,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing // to be done here. - if !cfg_info.doc_auto_cfg_active && !cfg_info.parent_is_doc_cfg { + if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg { None } else if cfg_info.parent_is_doc_cfg { if cfg_info.current_cfg == Cfg::True { From c06a076634e4feab47e133fe6325af9659bab082 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Apr 2025 14:32:31 +0200 Subject: [PATCH 337/537] Put back the `doc_cfg` code behind a nightly feature --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + src/librustdoc/passes/propagate_doc_cfg.rs | 6 +++++- tests/rustdoc-ui/cfg-hide-show-conflict.rs | 1 + tests/rustdoc-ui/cfg-hide-show-conflict.stderr | 4 ++-- tests/rustdoc-ui/lints/doc_cfg_hide.rs | 1 + tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 6 +++--- tests/rustdoc/doc-auto-cfg.rs | 2 +- tests/rustdoc/doc-cfg/doc-cfg-hide.rs | 2 +- tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs | 1 + tests/rustdoc/doc_auto_cfg.rs | 5 +---- tests/rustdoc/doc_auto_cfg_reexports.rs | 1 + tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs | 2 +- .../doc_auto_cfg-reexport-foreign-113982.rs | 2 +- .../glob-reexport-attribute-merge-doc-auto-cfg.rs | 2 +- tests/ui/feature-gates/feature-gate-doc_cfg.rs | 6 +----- tests/ui/feature-gates/feature-gate-doc_cfg.stderr | 13 +++++++++++++ 16 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-doc_cfg.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index fe9cc8e61ed5..35531378784b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -182,6 +182,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( "experimental" { + cfg => doc_cfg masked => doc_masked notable_trait => doc_notable_trait } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 1425687cd269..802f2fbe569c 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -18,7 +18,11 @@ pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { }; pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { - CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr) + if cx.tcx.features().doc_cfg() { + CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr) + } else { + cr + } } struct CfgPropagator<'a, 'tcx> { diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.rs b/tests/rustdoc-ui/cfg-hide-show-conflict.rs index a8a50fe15c7e..8e98b95c85bb 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.rs +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.rs @@ -1,2 +1,3 @@ +#![feature(doc_cfg)] #![doc(auto_cfg(hide(target_os = "linux")))] #![doc(auto_cfg(show(windows, target_os = "linux")))] //~ ERROR diff --git a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr index d2d0564606a5..22231e82cd7b 100644 --- a/tests/rustdoc-ui/cfg-hide-show-conflict.stderr +++ b/tests/rustdoc-ui/cfg-hide-show-conflict.stderr @@ -1,11 +1,11 @@ error: same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item - --> $DIR/cfg-hide-show-conflict.rs:2:31 + --> $DIR/cfg-hide-show-conflict.rs:3:31 | LL | #![doc(auto_cfg(show(windows, target_os = "linux")))] | ^^^^^^^^^^^^^^^^^^^ | note: first change was here - --> $DIR/cfg-hide-show-conflict.rs:1:22 + --> $DIR/cfg-hide-show-conflict.rs:2:22 | LL | #![doc(auto_cfg(hide(target_os = "linux")))] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.rs b/tests/rustdoc-ui/lints/doc_cfg_hide.rs index 4f2625d00ce4..397b21393e5c 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.rs +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.rs @@ -1,3 +1,4 @@ +#![feature(doc_cfg)] #![doc(auto_cfg(hide = "test"))] //~ ERROR #![doc(auto_cfg(hide))] //~ ERROR #![doc(auto_cfg(hide(not(windows))))] //~ ERROR diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index 22501d63c3fb..0e9db5a30d83 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,5 +1,5 @@ error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items - --> $DIR/doc_cfg_hide.rs:1:8 + --> $DIR/doc_cfg_hide.rs:2:8 | LL | #![doc(auto_cfg(hide = "test"))] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | #![doc(auto_cfg(hide = "test"))] = note: `#[deny(invalid_doc_attributes)]` on by default error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items - --> $DIR/doc_cfg_hide.rs:2:8 + --> $DIR/doc_cfg_hide.rs:3:8 | LL | #![doc(auto_cfg(hide))] | ^^^^^^^^^^^^^^ error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/values items - --> $DIR/doc_cfg_hide.rs:3:22 + --> $DIR/doc_cfg_hide.rs:4:22 | LL | #![doc(auto_cfg(hide(not(windows))))] | ^^^^^^^^^^^^ diff --git a/tests/rustdoc/doc-auto-cfg.rs b/tests/rustdoc/doc-auto-cfg.rs index b3fe8922fd78..e56cf18d08a0 100644 --- a/tests/rustdoc/doc-auto-cfg.rs +++ b/tests/rustdoc/doc-auto-cfg.rs @@ -1,4 +1,4 @@ -#![feature(doc_auto_cfg)] +#![feature(doc_cfg)] #![crate_name = "foo"] //@ has foo/fn.foo.html diff --git a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs index cf906ede7e13..e919206d3a47 100644 --- a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs +++ b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs @@ -1,5 +1,5 @@ #![crate_name = "oud"] -#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide, no_core)] +#![feature(doc_cfg)] #![doc(auto_cfg(hide(feature = "solecism")))] diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs index 27923893bdda..9ae8b8fca4f7 100644 --- a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs +++ b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs @@ -1,4 +1,5 @@ //@ compile-flags:--cfg feature="worricow" +#![feature(doc_cfg)] #![crate_name = "xenogenous"] //@ has 'xenogenous/struct.Worricow.html' diff --git a/tests/rustdoc/doc_auto_cfg.rs b/tests/rustdoc/doc_auto_cfg.rs index cb7c0e3f5950..19ef174c1778 100644 --- a/tests/rustdoc/doc_auto_cfg.rs +++ b/tests/rustdoc/doc_auto_cfg.rs @@ -1,10 +1,7 @@ // Test covering RFC 3631 features. #![crate_name = "foo"] -#![feature(no_core)] -#![no_core] -#![no_std] - +#![feature(doc_cfg)] #![doc(auto_cfg(hide(feature = "hidden")))] //@ has 'foo/index.html' diff --git a/tests/rustdoc/doc_auto_cfg_reexports.rs b/tests/rustdoc/doc_auto_cfg_reexports.rs index f226c52e2ebf..f6315e9d49dd 100644 --- a/tests/rustdoc/doc_auto_cfg_reexports.rs +++ b/tests/rustdoc/doc_auto_cfg_reexports.rs @@ -1,6 +1,7 @@ // Checks that `cfg` are correctly applied on inlined reexports. #![crate_name = "foo"] +#![feature(doc_cfg)] // Check with `std` item. //@ has 'foo/index.html' '//*[@class="stab portability"]' 'Non-moustache' diff --git a/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs b/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs index f85d7b236372..f24ebcd52acb 100644 --- a/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs +++ b/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs @@ -1,6 +1,6 @@ // Regression test for . -#![feature(doc_auto_cfg)] +#![feature(doc_cfg)] #![crate_type = "lib"] #![crate_name = "foo"] diff --git a/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs b/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs index 76b25127a9c6..f8ec4afc0313 100644 --- a/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs +++ b/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs @@ -1,7 +1,7 @@ //@ aux-build: issue-113982-doc_auto_cfg-reexport-foreign.rs // https://github.com/rust-lang/rust/issues/113982 -#![feature(no_core, doc_auto_cfg)] +#![feature(no_core, doc_cfg)] #![no_core] #![crate_name = "foo"] diff --git a/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs index d0a2165ec8ab..0aed2b0c4620 100644 --- a/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs +++ b/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs @@ -2,7 +2,7 @@ // the reexported item whereas glob reexports do with the `doc_auto_cfg` feature. #![crate_name = "foo"] -#![feature(doc_auto_cfg)] +#![feature(doc_cfg)] //@ has 'foo/index.html' // There are two items. diff --git a/tests/ui/feature-gates/feature-gate-doc_cfg.rs b/tests/ui/feature-gates/feature-gate-doc_cfg.rs index 83053e8c8bfd..213a5a8c5a98 100644 --- a/tests/ui/feature-gates/feature-gate-doc_cfg.rs +++ b/tests/ui/feature-gates/feature-gate-doc_cfg.rs @@ -1,6 +1,2 @@ -//@ build-pass - -// FIXME: Remove this test once `doc_cfg` feature is completely removed. - -#[doc(cfg(unix))] +#[doc(cfg(unix))] //~ ERROR fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-doc_cfg.stderr b/tests/ui/feature-gates/feature-gate-doc_cfg.stderr new file mode 100644 index 000000000000..5315aaeeb3ed --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-doc_cfg.stderr @@ -0,0 +1,13 @@ +error[E0658]: `#[doc(cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:1:1 + | +LL | #[doc(cfg(unix))] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 1561efe41afe40c1afaf3d11316ef754d9a8f9a9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 May 2025 17:14:46 +0200 Subject: [PATCH 338/537] Add code documentation, improve code and improve error message --- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 9 +++------ src/librustdoc/clean/types.rs | 13 +++++++++++++ src/librustdoc/passes/propagate_doc_cfg.rs | 14 +++++++++----- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 4 ++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 8326ddaf194d..a9a0f6d8b516 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -147,7 +147,7 @@ passes_doc_auto_cfg_expects_hide_or_show = `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` passes_doc_auto_cfg_hide_show_expects_list = - `#![doc(auto_cfg({$attr_name}(...)))]` only expects a list of items + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items passes_doc_auto_cfg_hide_show_unexpected_item = `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 38b67e2f9dc5..c521467b556c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItem, MetaItemInner, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -1161,10 +1161,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Check that the `#![doc(auto_cfg(..))]` attribute has expected input. - fn check_doc_auto_cfg(&self, meta: &MetaItemInner, hir_id: HirId) { - let MetaItemInner::MetaItem(meta) = meta else { - unreachable!(); - }; + fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) { match &meta.kind { MetaItemKind::Word => {} MetaItemKind::NameValue(lit) => { @@ -1286,7 +1283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::auto_cfg) => { - self.check_doc_auto_cfg(meta, hir_id); + self.check_doc_auto_cfg(i_meta, hir_id); } Some(sym::inline | sym::no_inline) => { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2ec97a57087a..545f1ef6da4a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -922,11 +922,19 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( .flatten() } +/// This type keeps track of (doc) cfg information as we go down the item tree. #[derive(Clone, Debug)] pub(crate) struct CfgInfo { + /// List of `doc(auto_cfg(hide(...)))` cfgs. hidden_cfg: FxHashSet, + /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while + /// taking into account the `hidden_cfg` information. current_cfg: Cfg, + /// Whether the `doc(auto_cfg())` feature is enabled or not at this point. auto_cfg_active: bool, + /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`, + /// instead we will concatenate with it. However, if it's not the case, we need to overwrite + /// `current_cfg`. parent_is_doc_cfg: bool, } @@ -962,6 +970,11 @@ fn show_hide_show_conflict_error( diag.emit(); } +/// This function checks if a same `cfg` is present in both `auto_cfg(hide(...))` and +/// `auto_cfg(show(...))` on the same item. If so, it emits an error. +/// +/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs` +/// and in `new_hide_attrs` arguments. fn handle_auto_cfg_hide_show( tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 802f2fbe569c..ea77065ac079 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -30,7 +30,8 @@ struct CfgPropagator<'a, 'tcx> { cfg_info: CfgInfo, } -fn should_retain(token: &TokenTree) -> bool { +/// Returns true if the provided `token` is a `cfg` ident. +fn is_cfg_token(token: &TokenTree) -> bool { // We only keep `doc(cfg)` items. matches!( token, @@ -47,7 +48,9 @@ fn should_retain(token: &TokenTree) -> bool { ) } -fn filter_tokens_from_list(args_tokens: &TokenStream) -> Vec { +/// We only want to keep `#[cfg()]` and `#[doc(cfg())]` attributes so we rebuild a vec of +/// `TokenTree` with only the tokens we're interested into. +fn filter_non_cfg_tokens_from_list(args_tokens: &TokenStream) -> Vec { let mut tokens = Vec::with_capacity(args_tokens.len()); let mut skip_next_delimited = false; for token in args_tokens.iter() { @@ -58,7 +61,7 @@ fn filter_tokens_from_list(args_tokens: &TokenStream) -> Vec { } skip_next_delimited = false; } - token if should_retain(token) => { + token if is_cfg_token(token) => { skip_next_delimited = false; tokens.push(token.clone()); } @@ -70,7 +73,8 @@ fn filter_tokens_from_list(args_tokens: &TokenStream) -> Vec { tokens } -// We only care about `#[cfg()]` and `#[doc(cfg())]`, we discard everything else. +/// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from +/// it and put them into `attrs`. fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { for attr in new_attrs { if attr.is_doc_comment() { @@ -84,7 +88,7 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) if ident == sym::doc && let AttrArgs::Delimited(args) = &mut normal.args { - let tokens = filter_tokens_from_list(&args.tokens); + let tokens = filter_non_cfg_tokens_from_list(&args.tokens); args.tokens = TokenStream::new(tokens); attrs.push(attr); } else if ident == sym::cfg_trace { diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index 0e9db5a30d83..9e820a77b5e5 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,4 +1,4 @@ -error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items +error: `#![doc(auto_cfg(hide(...)))]` expects a list of items --> $DIR/doc_cfg_hide.rs:2:8 | LL | #![doc(auto_cfg(hide = "test"))] @@ -6,7 +6,7 @@ LL | #![doc(auto_cfg(hide = "test"))] | = note: `#[deny(invalid_doc_attributes)]` on by default -error: `#![doc(auto_cfg(hide(...)))]` only expects a list of items +error: `#![doc(auto_cfg(hide(...)))]` expects a list of items --> $DIR/doc_cfg_hide.rs:3:8 | LL | #![doc(auto_cfg(hide))] From 553308b11503eafac6341b82f345bd62b09ba317 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 29 May 2025 18:39:08 +0200 Subject: [PATCH 339/537] Improve code and better check `doc(cfg(...))` attributes --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 23 ++++- compiler/rustc_span/src/symbol.rs | 1 - src/librustdoc/clean/inline.rs | 4 + src/librustdoc/clean/types.rs | 89 +++++++++++-------- tests/rustdoc-ui/doc-cfg.rs | 9 ++ tests/rustdoc-ui/doc-cfg.stderr | 74 ++++++++++----- tests/rustdoc-ui/feature-gate-doc_cfg.rs | 6 ++ tests/rustdoc-ui/feature-gate-doc_cfg.stderr | 63 +++++++++++++ tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs | 8 -- .../feature-gate-doc_cfg_hide.stderr | 10 --- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 2 +- 13 files changed, 213 insertions(+), 79 deletions(-) create mode 100644 tests/rustdoc-ui/feature-gate-doc_cfg.rs create mode 100644 tests/rustdoc-ui/feature-gate-doc_cfg.stderr delete mode 100644 tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs delete mode 100644 tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 35531378784b..608ccfefeb69 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -183,6 +183,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( "experimental" { cfg => doc_cfg + auto_cfg => doc_cfg masked => doc_masked notable_trait => doc_notable_trait } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a9a0f6d8b516..a5ff169e638c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -150,7 +150,7 @@ passes_doc_auto_cfg_hide_show_expects_list = `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items passes_doc_auto_cfg_hide_show_unexpected_item = - `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items passes_doc_auto_cfg_wrong_literal = `expected boolean for #[doc(auto_cfg = ...)]` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c521467b556c..88b49c781e75 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1176,7 +1176,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } MetaItemKind::List(list) => { for item in list { - let Some(attr_name) = item.name() else { continue }; + let Some(attr_name) = item.name() else { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgExpectsHideOrShow, + ); + continue; + }; if attr_name != sym::hide && attr_name != sym::show { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1195,6 +1203,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr_name: attr_name.as_str(), }, ); + } else if match item { + MetaItemInner::Lit(_) => true, + // We already checked above that it's not a list. + MetaItemInner::MetaItem(meta) => meta.path.segments.len() != 1, + } { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + item.span(), + errors::DocAutoCfgHideShowUnexpectedItem { + attr_name: attr_name.as_str(), + }, + ); } } } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e80a98994dbb..18c3faed9329 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1150,7 +1150,6 @@ symbols! { hashset_iter_ty, hexagon_target_feature, hidden, - hidden_cfg, hide, hint, homogeneous_aggregate, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8ffa6033c9b0..8beea0580de2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -605,6 +605,10 @@ pub(crate) fn build_impl( }); } + // In here, we pass an empty `CfgInfo` because the computation of `cfg` happens later, so it + // doesn't matter at this point. + // + // We need to pass this empty `CfgInfo` because `merge_attrs` is used when computing the `cfg`. let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default()); trace!("merged_attrs={merged_attrs:?}"); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 545f1ef6da4a..605b77109a06 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -970,8 +970,10 @@ fn show_hide_show_conflict_error( diag.emit(); } -/// This function checks if a same `cfg` is present in both `auto_cfg(hide(...))` and -/// `auto_cfg(show(...))` on the same item. If so, it emits an error. +/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument. +/// +/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and +/// `auto_cfg(show(...))` on the same item and emits an error if it's the case. /// /// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs` /// and in `new_hide_attrs` arguments. @@ -1023,6 +1025,31 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator Some(item) } + fn check_changed_auto_active_status( + changed_auto_active_status: &mut Option, + attr: &ast::MetaItem, + cfg_info: &mut CfgInfo, + tcx: TyCtxt<'_>, + new_value: bool, + ) -> bool { + if let Some(first_change) = changed_auto_active_status { + if cfg_info.auto_cfg_active != new_value { + tcx.sess + .dcx() + .struct_span_err( + vec![*first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ) + .emit(); + return true; + } + } else { + *changed_auto_active_status = Some(attr.span); + } + cfg_info.auto_cfg_active = new_value; + false + } + let mut new_show_attrs = FxHashMap::default(); let mut new_hide_attrs = FxHashMap::default(); @@ -1070,49 +1097,39 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator }; match &attr.kind { MetaItemKind::Word => { - if let Some(first_change) = changed_auto_active_status { - if !cfg_info.auto_cfg_active { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; } - cfg_info.auto_cfg_active = true; } MetaItemKind::NameValue(lit) => { if let LitKind::Bool(value) = lit.kind { - if let Some(first_change) = changed_auto_active_status { - if cfg_info.auto_cfg_active != value { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + value, + ) { + return None; } - cfg_info.auto_cfg_active = value; } } MetaItemKind::List(sub_attrs) => { - if let Some(first_change) = changed_auto_active_status { - if !cfg_info.auto_cfg_active { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; } - // Whatever happens next, the feature is enabled again. - cfg_info.auto_cfg_active = true; for sub_attr in sub_attrs.iter() { if let Some(ident) = sub_attr.ident() && (ident.name == sym::show || ident.name == sym::hide) diff --git a/tests/rustdoc-ui/doc-cfg.rs b/tests/rustdoc-ui/doc-cfg.rs index 14943bbc3418..9840c305290a 100644 --- a/tests/rustdoc-ui/doc-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg.rs @@ -8,4 +8,13 @@ //~^^ WARN unexpected `cfg` condition name: `bar` #[doc(cfg())] //~ ERROR #[doc(cfg(foo, bar))] //~ ERROR +#[doc(auto_cfg(42))] //~ ERROR +#[doc(auto_cfg(hide(true)))] //~ ERROR +#[doc(auto_cfg(hide(42)))] //~ ERROR +#[doc(auto_cfg(hide("a")))] //~ ERROR +#[doc(auto_cfg(hide(foo::bar)))] //~ ERROR +// Shouldn't lint +#[doc(auto_cfg(hide(windows)))] +#[doc(auto_cfg(hide(feature = "windows")))] +#[doc(auto_cfg(hide(foo)))] pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 1233ee010de2..36ca18eed8fc 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -1,3 +1,55 @@ +error: `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` + --> $DIR/doc-cfg.rs:11:7 + | +LL | #[doc(auto_cfg(42))] + | ^^^^^^^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:12:21 + | +LL | #[doc(auto_cfg(hide(true)))] + | ^^^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:13:21 + | +LL | #[doc(auto_cfg(hide(42)))] + | ^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:14:21 + | +LL | #[doc(auto_cfg(hide("a")))] + | ^^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:15:21 + | +LL | #[doc(auto_cfg(hide(foo::bar)))] + | ^^^^^^^^ + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg.rs:6:11 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `bar` + --> $DIR/doc-cfg.rs:6:21 + | +LL | #[doc(cfg(foo), cfg(bar))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(bar)` + = note: see for more information about checking conditional configuration + error: `cfg` predicate is not specified --> $DIR/doc-cfg.rs:3:7 | @@ -22,25 +74,5 @@ error: multiple `cfg` predicates are specified LL | #[doc(cfg(foo, bar))] | ^^^ -warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg.rs:6:11 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: expected names are: `FALSE` and `test` and 31 more - = help: to expect this configuration use `--check-cfg=cfg(foo)` - = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition name: `bar` - --> $DIR/doc-cfg.rs:6:21 - | -LL | #[doc(cfg(foo), cfg(bar))] - | ^^^ - | - = help: to expect this configuration use `--check-cfg=cfg(bar)` - = note: see for more information about checking conditional configuration - -error: aborting due to 4 previous errors; 2 warnings emitted +error: aborting due to 9 previous errors; 2 warnings emitted diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg.rs b/tests/rustdoc-ui/feature-gate-doc_cfg.rs new file mode 100644 index 000000000000..b474a1524bc1 --- /dev/null +++ b/tests/rustdoc-ui/feature-gate-doc_cfg.rs @@ -0,0 +1,6 @@ +#![doc(auto_cfg)] //~ ERROR +#![doc(auto_cfg(false))] //~ ERROR +#![doc(auto_cfg(true))] //~ ERROR +#![doc(auto_cfg(hide(feature = "solecism")))] //~ ERROR +#![doc(auto_cfg(show(feature = "bla")))] //~ ERROR +#![doc(cfg(feature = "solecism"))] //~ ERROR diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg.stderr b/tests/rustdoc-ui/feature-gate-doc_cfg.stderr new file mode 100644 index 000000000000..68a86c1abb77 --- /dev/null +++ b/tests/rustdoc-ui/feature-gate-doc_cfg.stderr @@ -0,0 +1,63 @@ +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:1:1 + | +LL | #![doc(auto_cfg)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:2:1 + | +LL | #![doc(auto_cfg(false))] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:3:1 + | +LL | #![doc(auto_cfg(true))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:4:1 + | +LL | #![doc(auto_cfg(hide(feature = "solecism")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:5:1 + | +LL | #![doc(auto_cfg(show(feature = "bla")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:6:1 + | +LL | #![doc(cfg(feature = "solecism"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs deleted file mode 100644 index e49285a01b81..000000000000 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs +++ /dev/null @@ -1,8 +0,0 @@ -// FIXME: Remove this file once feature is removed - -#![doc(cfg_hide(test))] //~ ERROR - -#[cfg(not(test))] -pub fn public_fn() {} -#[cfg(test)] -pub fn internal_use_only() {} diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr deleted file mode 100644 index b3eee2af7f73..000000000000 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unknown `doc` attribute `cfg_hide` - --> $DIR/feature-gate-doc_cfg_hide.rs:3:8 - | -LL | #![doc(cfg_hide(test))] - | ^^^^^^^^^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error - diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index 9e820a77b5e5..c63c8d607fa0 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -12,7 +12,7 @@ error: `#![doc(auto_cfg(hide(...)))]` expects a list of items LL | #![doc(auto_cfg(hide))] | ^^^^^^^^^^^^^^ -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/values items +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items --> $DIR/doc_cfg_hide.rs:4:22 | LL | #![doc(auto_cfg(hide(not(windows))))] From fccba2c341b65b62f513c0b7ee8842f134f3cbcd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 29 May 2025 21:54:16 +0200 Subject: [PATCH 340/537] Remove `doc_cfg_hide` feature --- compiler/rustc_feature/src/unstable.rs | 2 -- compiler/rustc_span/src/symbol.rs | 1 - library/alloc/src/lib.rs | 2 +- library/core/src/lib.rs | 2 +- library/std/src/lib.rs | 3 ++- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6ef0df72365e..4dc961cb9277 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -476,8 +476,6 @@ declare_features! ( (unstable, doc_auto_cfg, "1.58.0", Some(43781)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), - /// Allows `#[doc(cfg_hide(...))]`. - (unstable, doc_cfg_hide, "1.57.0", Some(43781)), /// Allows `#[doc(masked)]`. (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows features to allow target_feature to better interact with traits. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 18c3faed9329..79f00e2e94de 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -878,7 +878,6 @@ symbols! { doc_alias, doc_auto_cfg, doc_cfg, - doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dc5d243e8823..24d7e6216a0d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -207,7 +207,7 @@ // // Rustdoc features: #![feature(doc_cfg)] -#![feature(doc_cfg_hide)] +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] // Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]` // blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 32a3d6c7042a..b1e559065fe4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -161,6 +161,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -176,7 +177,6 @@ #![feature(deprecated_suggestion)] #![feature(derive_const)] #![feature(doc_cfg)] -#![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] #![feature(extern_types)] #![feature(f16)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ecd354f599e4..ff997ff7603b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -278,6 +278,8 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] +#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] @@ -293,7 +295,6 @@ #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] -#![feature(doc_cfg_hide)] #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] From a7ed9bf6c7473827b7c876679a2a633facec09b8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 2 Jun 2025 22:19:33 +0200 Subject: [PATCH 341/537] fmt --- library/alloc/src/lib.rs | 7 +------ library/std/src/lib.rs | 6 +----- src/librustdoc/doctest/rust.rs | 8 +++----- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 24d7e6216a0d..7499db8bf2c1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -77,12 +77,7 @@ )] #![cfg_attr( not(bootstrap), - doc(auto_cfg(hide( - no_global_oom_handling, - no_rc, - no_sync, - target_has_atomic = "ptr" - ))) + doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr"))) )] #![doc(rust_logo)] #![feature(rustdoc_internals)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ff997ff7603b..c8fe5c55e970 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -237,11 +237,7 @@ #![doc(rust_logo)] #![cfg_attr( bootstrap, - doc(cfg_hide( - not(test), - no_global_oom_handling, - not(no_global_oom_handling) - )) + doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling))) )] #![cfg_attr(not(bootstrap), doc(auto_cfg(hide(no_global_oom_handling))))] // Don't link to std. We are std. diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index b9367b880057..4d3f976c2a6d 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -119,11 +119,9 @@ impl HirCollector<'_> { nested: F, ) { let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some(ref cfg) = extract_cfg_from_attrs( - ast_attrs.iter(), - self.tcx, - &mut CfgInfo::default(), - ) && !cfg.matches(&self.tcx.sess.psess) + if let Some(ref cfg) = + extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default()) + && !cfg.matches(&self.tcx.sess.psess) { return; } From ec00723ba153c72124f8271b6dc15540f23e6832 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Jun 2025 13:34:41 +0200 Subject: [PATCH 342/537] Fix autodiff feature activation --- library/std/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c8fe5c55e970..501c22cfb494 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -275,7 +275,6 @@ // stabilization was reverted after it hit beta #![cfg_attr(bootstrap, feature(doc_cfg_hide))] -#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] From 254a2139f6c4b251d9210843d2e7d7952ef9f40d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Jun 2025 17:44:14 +0200 Subject: [PATCH 343/537] Remove `cfg(bootstrap)` for `doc_cfg` feature following #141925 --- library/alloc/src/lib.rs | 17 +--------- library/core/src/lib.rs | 70 ++++++++++++---------------------------- library/std/src/lib.rs | 7 +--- 3 files changed, 23 insertions(+), 71 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7499db8bf2c1..fc3266b74793 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -64,21 +64,7 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] -#![cfg_attr( - bootstrap, - doc(cfg_hide( - not(test), - no_global_oom_handling, - not(no_global_oom_handling), - not(no_rc), - not(no_sync), - target_has_atomic = "ptr" - )) -)] -#![cfg_attr( - not(bootstrap), - doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr"))) -)] +#![doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr")))] #![doc(rust_logo)] #![feature(rustdoc_internals)] #![no_std] @@ -202,7 +188,6 @@ // // Rustdoc features: #![feature(doc_cfg)] -#![cfg_attr(bootstrap, feature(doc_cfg_hide))] // Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]` // blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b1e559065fe4..54adf97f1002 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -51,54 +51,27 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![cfg_attr( - bootstrap, - doc(cfg_hide( - no_fp_fmt_parse, - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64", - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr", - target_has_atomic_equal_alignment = "8", - target_has_atomic_equal_alignment = "16", - target_has_atomic_equal_alignment = "32", - target_has_atomic_equal_alignment = "64", - target_has_atomic_equal_alignment = "ptr", - target_has_atomic_load_store = "8", - target_has_atomic_load_store = "16", - target_has_atomic_load_store = "32", - target_has_atomic_load_store = "64", - target_has_atomic_load_store = "ptr", - )) -)] -#![cfg_attr( - not(bootstrap), - doc(auto_cfg(hide( - no_fp_fmt_parse, - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64", - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr", - target_has_atomic_equal_alignment = "8", - target_has_atomic_equal_alignment = "16", - target_has_atomic_equal_alignment = "32", - target_has_atomic_equal_alignment = "64", - target_has_atomic_equal_alignment = "ptr", - target_has_atomic_load_store = "8", - target_has_atomic_load_store = "16", - target_has_atomic_load_store = "32", - target_has_atomic_load_store = "64", - target_has_atomic_load_store = "ptr", - ))) -)] +#![doc(auto_cfg(hide( + no_fp_fmt_parse, + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", +)))] #![no_core] #![rustc_coherence_is_core] #![rustc_preserve_ub_checks] @@ -161,7 +134,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(doc_cfg_hide))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 501c22cfb494..61b7d170b8ba 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -235,11 +235,7 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![cfg_attr( - bootstrap, - doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling))) -)] -#![cfg_attr(not(bootstrap), doc(auto_cfg(hide(no_global_oom_handling))))] +#![doc(auto_cfg(hide(no_global_oom_handling)))] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind @@ -274,7 +270,6 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta -#![cfg_attr(bootstrap, feature(doc_cfg_hide))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] From 6fecff45d915b31eee3170f32fedb6db045611f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Jul 2025 17:00:21 +0200 Subject: [PATCH 344/537] Fix `tests/rustdoc/target-feature.rs` test by adding missing `#![feature(doc_cfg)]` --- tests/rustdoc/target-feature.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/rustdoc/target-feature.rs b/tests/rustdoc/target-feature.rs index 59a08a0ca949..f2686f81fbff 100644 --- a/tests/rustdoc/target-feature.rs +++ b/tests/rustdoc/target-feature.rs @@ -1,3 +1,5 @@ +#![feature(doc_cfg)] + #![crate_name = "foo"] //@ has 'foo/index.html' From ef8b2a26caccba46584e4753c3091218d4a2e17d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Jul 2025 20:05:02 +0200 Subject: [PATCH 345/537] Correctly handle target_feature in rustdoc cfg --- src/librustdoc/clean/types.rs | 37 +++++++++++------------------------ 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 605b77109a06..c8e9f3dc479f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1153,35 +1153,20 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because // `doc(cfg())` overrides `cfg()`). for attr in attrs { - let Some(ident) = attr.ident() else { continue }; - match ident.name { - sym::cfg | sym::cfg_trace if !cfg_info.parent_is_doc_cfg => { - if let Some(attr) = single(attr.meta_item_list()?) - && let Ok(new_cfg) = Cfg::parse(&attr) - { - cfg_info.current_cfg &= new_cfg; - } - } + if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well - sym::target_feature - if let Some(attrs) = attr.meta_item_list() => - { - for attr in attrs { - if attr.has_name(sym::enable) && attr.value_str().is_some() { - // Clone `enable = "feat"`, change to `target_feature = "feat"`. - // Unwrap is safe because `value_str` succeeded above. - let mut meta = attr.meta_item().unwrap().clone(); - meta.path = - ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - - if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { - cfg_info.current_cfg &= feat_cfg; - } - } - } + for (feature, _) in features { + cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); } - _ => {} + continue; + } else if !cfg_info.parent_is_doc_cfg + && let Some(ident) = attr.ident() + && matches!(ident.name, sym::cfg | sym::cfg_trace) + && let Some(attr) = single(attr.meta_item_list()?) + && let Ok(new_cfg) = Cfg::parse(&attr) + { + cfg_info.current_cfg &= new_cfg; } } From 77885fef2cd9a7f9daa4f95336f0cfdeb62b3016 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 Aug 2025 16:03:12 +0200 Subject: [PATCH 346/537] Improve code comments and extend tests for `doc_cfg` feature --- src/librustdoc/clean/types.rs | 6 ++++-- tests/rustdoc-ui/doc-cfg.rs | 2 ++ tests/rustdoc-ui/doc-cfg.stderr | 14 +++++++++++++- tests/rustdoc/doc_auto_cfg_reexports.rs | 13 +++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c8e9f3dc479f..8b8cf19d8e41 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -925,7 +925,8 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( /// This type keeps track of (doc) cfg information as we go down the item tree. #[derive(Clone, Debug)] pub(crate) struct CfgInfo { - /// List of `doc(auto_cfg(hide(...)))` cfgs. + /// List of currently active `doc(auto_cfg(hide(...)))` cfgs,minus currently active + /// `doc(auto_cfg(show(...)))` cfgs. hidden_cfg: FxHashSet, /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while /// taking into account the `hidden_cfg` information. @@ -1181,7 +1182,8 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator Some(Arc::new(cfg_info.current_cfg.clone())) } } else { - // Since we always want to collect all `cfg` items, we remove the hidden ones afterward. + // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the + // hidden ones afterward. match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) { None | Some(Cfg::True) => None, Some(cfg) => Some(Arc::new(cfg)), diff --git a/tests/rustdoc-ui/doc-cfg.rs b/tests/rustdoc-ui/doc-cfg.rs index 9840c305290a..d72643e23556 100644 --- a/tests/rustdoc-ui/doc-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg.rs @@ -13,6 +13,8 @@ #[doc(auto_cfg(hide(42)))] //~ ERROR #[doc(auto_cfg(hide("a")))] //~ ERROR #[doc(auto_cfg(hide(foo::bar)))] //~ ERROR +#[doc(auto_cfg = 42)] //~ ERROR +#[doc(auto_cfg = "a")] //~ ERROR // Shouldn't lint #[doc(auto_cfg(hide(windows)))] #[doc(auto_cfg(hide(feature = "windows")))] diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 36ca18eed8fc..13f62e50d907 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -30,6 +30,18 @@ error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value item LL | #[doc(auto_cfg(hide(foo::bar)))] | ^^^^^^^^ +error: `expected boolean for #[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg.rs:16:7 + | +LL | #[doc(auto_cfg = 42)] + | ^^^^^^^^^^^^^ + +error: `expected boolean for #[doc(auto_cfg = ...)]` + --> $DIR/doc-cfg.rs:17:7 + | +LL | #[doc(auto_cfg = "a")] + | ^^^^^^^^^^^^^^ + warning: unexpected `cfg` condition name: `foo` --> $DIR/doc-cfg.rs:6:11 | @@ -74,5 +86,5 @@ error: multiple `cfg` predicates are specified LL | #[doc(cfg(foo, bar))] | ^^^ -error: aborting due to 9 previous errors; 2 warnings emitted +error: aborting due to 11 previous errors; 2 warnings emitted diff --git a/tests/rustdoc/doc_auto_cfg_reexports.rs b/tests/rustdoc/doc_auto_cfg_reexports.rs index f6315e9d49dd..ecfe9aabcfed 100644 --- a/tests/rustdoc/doc_auto_cfg_reexports.rs +++ b/tests/rustdoc/doc_auto_cfg_reexports.rs @@ -20,3 +20,16 @@ mod x { // 'Available on non-crate feature pistache only.' #[cfg(not(feature = "pistache"))] pub use crate::x::B; + +// Now checking that `cfg`s are not applied on non-inlined reexports. +pub mod pub_sub_mod { + //@ has 'foo/pub_sub_mod/index.html' + // There should be only only item with `cfg` note. + //@ count - '//*[@class="stab portability"]' 1 + // And obviously the item should be "blabla". + //@ has - '//dt' 'blablaNon-pistache' + #[cfg(not(feature = "pistache"))] + pub fn blabla() {} + + pub use self::blabla as another; +} From 653e1036ed5a343a7be7b2a73096c138efc51523 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 22 Sep 2025 13:58:02 +0200 Subject: [PATCH 347/537] Apply first review round suggestions --- compiler/rustc_feature/src/removed.rs | 2 ++ compiler/rustc_passes/messages.ftl | 4 ++-- compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/passes/propagate_doc_cfg.rs | 14 +------------- src/librustdoc/visit_ast.rs | 2 +- tests/rustdoc-ui/doc-cfg.stderr | 6 +++--- 6 files changed, 10 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 32115535e994..71365da316ce 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -101,6 +101,8 @@ declare_features! ( Some("never properly implemented; requires significant design work"), 127655), /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), + /// Allows `#[doc(cfg_hide(...))]`. + (removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.58.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`"), 90420), diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a5ff169e638c..21fc1124c2f5 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -144,7 +144,7 @@ passes_doc_cfg_hide_takes_list = `#[doc(cfg_hide(...))]` takes a list of attributes passes_doc_auto_cfg_expects_hide_or_show = - `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` passes_doc_auto_cfg_hide_show_expects_list = `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items @@ -153,7 +153,7 @@ passes_doc_auto_cfg_hide_show_unexpected_item = `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items passes_doc_auto_cfg_wrong_literal = - `expected boolean for #[doc(auto_cfg = ...)]` + expected boolean for `#[doc(auto_cfg = ...)]` passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 79f00e2e94de..18c3faed9329 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -878,6 +878,7 @@ symbols! { doc_alias, doc_auto_cfg, doc_cfg, + doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index ea77065ac079..4bcb60a9a40d 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -33,19 +33,7 @@ struct CfgPropagator<'a, 'tcx> { /// Returns true if the provided `token` is a `cfg` ident. fn is_cfg_token(token: &TokenTree) -> bool { // We only keep `doc(cfg)` items. - matches!( - token, - TokenTree::Token( - Token { - kind: TokenKind::Ident( - ident, - _, - ), - .. - }, - _, - ) if *ident == sym::cfg, - ) + matches!(token, TokenTree::Token(Token { kind: TokenKind::Ident(sym::cfg, _,), .. }, _,),) } /// We only want to keep `#[cfg()]` and `#[doc(cfg())]` attributes so we rebuild a vec of diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ac67871b0cb7..dc9889cec219 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -9,7 +9,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; use rustc_hir::intravisit::{Visitor, walk_body, walk_item}; -use rustc_hir::{CRATE_HIR_ID, Node, find_attr}; +use rustc_hir::{Node, find_attr}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 13f62e50d907..49e8c324facf 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -1,4 +1,4 @@ -error: `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` +error: only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` --> $DIR/doc-cfg.rs:11:7 | LL | #[doc(auto_cfg(42))] @@ -30,13 +30,13 @@ error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value item LL | #[doc(auto_cfg(hide(foo::bar)))] | ^^^^^^^^ -error: `expected boolean for #[doc(auto_cfg = ...)]` +error: expected boolean for `#[doc(auto_cfg = ...)]` --> $DIR/doc-cfg.rs:16:7 | LL | #[doc(auto_cfg = 42)] | ^^^^^^^^^^^^^ -error: `expected boolean for #[doc(auto_cfg = ...)]` +error: expected boolean for `#[doc(auto_cfg = ...)]` --> $DIR/doc-cfg.rs:17:7 | LL | #[doc(auto_cfg = "a")] From 9362ab549f87e535eeba12c5d42f584ff55ff886 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Sep 2025 11:33:58 +0200 Subject: [PATCH 348/537] Improve code and fix typo --- compiler/rustc_passes/messages.ftl | 3 -- compiler/rustc_passes/src/check_attr.rs | 41 +++++++-------------- compiler/rustc_passes/src/errors.rs | 8 ++--- compiler/rustc_span/src/symbol.rs | 1 - src/doc/rustdoc/src/unstable-features.md | 42 +++++++++++----------- src/librustdoc/clean/types.rs | 10 +++--- src/librustdoc/passes/propagate_doc_cfg.rs | 3 +- 7 files changed, 43 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 21fc1124c2f5..df4016dfa1b8 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -140,9 +140,6 @@ passes_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std -passes_doc_cfg_hide_takes_list = - `#[doc(cfg_hide(...))]` takes a list of attributes - passes_doc_auto_cfg_expects_hide_or_show = only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 88b49c781e75..4ea237cfa032 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1160,7 +1160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Check that the `#![doc(auto_cfg(..))]` attribute has expected input. + /// Check that the `#![doc(auto_cfg)]` attribute has the expected input. fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) { match &meta.kind { MetaItemKind::Word => {} @@ -1176,7 +1176,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } MetaItemKind::List(list) => { for item in list { - let Some(attr_name) = item.name() else { + let Some(attr_name @ (sym::hide | sym::show)) = item.name() else { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, @@ -1185,36 +1185,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); continue; }; - if attr_name != sym::hide && attr_name != sym::show { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span, - errors::DocAutoCfgExpectsHideOrShow, - ); - } else if let Some(list) = item.meta_item_list() { + if let Some(list) = item.meta_item_list() { for item in list { - if item.meta_item_list().is_some() { + let valid = item.meta_item().is_some_and(|meta| { + meta.path.segments.len() == 1 + && matches!( + &meta.kind, + MetaItemKind::Word | MetaItemKind::NameValue(_) + ) + }); + if !valid { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, item.span(), - errors::DocAutoCfgHideShowUnexpectedItem { - attr_name: attr_name.as_str(), - }, - ); - } else if match item { - MetaItemInner::Lit(_) => true, - // We already checked above that it's not a list. - MetaItemInner::MetaItem(meta) => meta.path.segments.len() != 1, - } { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - item.span(), - errors::DocAutoCfgHideShowUnexpectedItem { - attr_name: attr_name.as_str(), - }, + errors::DocAutoCfgHideShowUnexpectedItem { attr_name }, ); } } @@ -1223,7 +1208,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { INVALID_DOC_ATTRIBUTES, hir_id, meta.span, - errors::DocAutoCfgHideShowExpectsList { attr_name: attr_name.as_str() }, + errors::DocAutoCfgHideShowExpectsList { attr_name }, ); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 1d2428c4f9a0..f0726014e0af 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -318,14 +318,14 @@ pub(crate) struct DocAutoCfgExpectsHideOrShow; #[derive(LintDiagnostic)] #[diag(passes_doc_auto_cfg_hide_show_expects_list)] -pub(crate) struct DocAutoCfgHideShowExpectsList<'a> { - pub attr_name: &'a str, +pub(crate) struct DocAutoCfgHideShowExpectsList { + pub attr_name: Symbol, } #[derive(LintDiagnostic)] #[diag(passes_doc_auto_cfg_hide_show_unexpected_item)] -pub(crate) struct DocAutoCfgHideShowUnexpectedItem<'a> { - pub attr_name: &'a str, +pub(crate) struct DocAutoCfgHideShowUnexpectedItem { + pub attr_name: Symbol, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 18c3faed9329..cd422da0c1c8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -629,7 +629,6 @@ symbols! { cfg_emscripten_wasm_eh, cfg_eval, cfg_fmt_debug, - cfg_hide, cfg_overflow_checks, cfg_panic, cfg_relocation_model, diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index cfa1936f3d7f..04d3c0cd630f 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -720,9 +720,9 @@ pass `--doctest-build-arg ARG` for each argument `ARG`. This flag enables the generation of toggles to expand macros in the HTML source code pages. -## `#[doc(cfg)]` +## `#[doc(cfg)]` and `#[doc(auto_cfg)]` -This feature aims at providing rustdoc users the possibility to add visual markers to the rendered documentation to know under which conditions an item is available (currently possible through the following unstable features: `doc_cfg`, `doc_auto_cfg` and `doc_cfg_hide`). +This feature aims at providing rustdoc users the possibility to add visual markers to the rendered documentation to know under which conditions an item is available (currently possible through the following unstable feature: `doc_cfg`). It does not aim to allow having a same item with different `cfg`s to appear more than once in the generated documentation. @@ -736,25 +736,6 @@ This features adds the following attributes: All of these attributes can be added to a module or to the crate root, and they will be inherited by the child items unless another attribute overrides it. This is why "opposite" attributes like `auto_cfg(hide(...))` and `auto_cfg(show(...))` are provided: they allow a child item to override its parent. -### `#[doc(auto_cfg)`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]` - -By default, `#[doc(auto_cfg)]` is enabled at the crate-level. When it's enabled, Rustdoc will automatically display `cfg(...)` compatibility information as-if the same `#[doc(cfg(...))]` had been specified. - -This attribute impacts the item on which it is used and its descendants. - -So if we take back the previous example: - -```rust -#[cfg(feature = "futures-io")] -pub mod futures {} -``` - -There's no need to "duplicate" the `cfg` into a `doc(cfg())` to make Rustdoc display it. - -In some situations, the detailed conditional compilation rules used to implement the feature might not serve as good documentation (for example, the list of supported platforms might be very long, and it might be better to document them in one place). To turn it off, add the `#[doc(auto_cfg = false)]` attribute on the item. - -If no argument is specified (ie `#[doc(auto_cfg)]`), it's the same as writing `#[doc(auto_cfg = true)]`. - ### `#[doc(cfg(...))]` This attribute provides a standardized format to override `#[cfg()]` attributes to document conditionally available items. Example: @@ -927,6 +908,25 @@ Using this attribute will re-enable `auto_cfg` if it was disabled at this locati pub fn foo() {} ``` +### `#[doc(auto_cfg)`/`#[doc(auto_cfg = true)]`/`#[doc(auto_cfg = false)]` + +By default, `#[doc(auto_cfg)]` is enabled at the crate-level. When it's enabled, Rustdoc will automatically display `cfg(...)` compatibility information as-if the same `#[doc(cfg(...))]` had been specified. + +This attribute impacts the item on which it is used and its descendants. + +So if we take back the previous example: + +```rust +#[cfg(feature = "futures-io")] +pub mod futures {} +``` + +There's no need to "duplicate" the `cfg` into a `doc(cfg())` to make Rustdoc display it. + +In some situations, the detailed conditional compilation rules used to implement the feature might not serve as good documentation (for example, the list of supported platforms might be very long, and it might be better to document them in one place). To turn it off, add the `#[doc(auto_cfg = false)]` attribute on the item. + +If no argument is specified (ie `#[doc(auto_cfg)]`), it's the same as writing `#[doc(auto_cfg = true)]`. + ## Inheritance Rustdoc merges `cfg` attributes from parent modules to its children. For example, in this case, the module `non_unix` will describe the entire compatibility matrix for the module, and not just its directly attached information: diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8b8cf19d8e41..c2cf39c4be06 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -925,7 +925,7 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( /// This type keeps track of (doc) cfg information as we go down the item tree. #[derive(Clone, Debug)] pub(crate) struct CfgInfo { - /// List of currently active `doc(auto_cfg(hide(...)))` cfgs,minus currently active + /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active /// `doc(auto_cfg(show(...)))` cfgs. hidden_cfg: FxHashSet, /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while @@ -942,13 +942,11 @@ pub(crate) struct CfgInfo { impl Default for CfgInfo { fn default() -> Self { Self { - hidden_cfg: [ + hidden_cfg: FxHashSet::from_iter([ Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None), - ] - .into_iter() - .collect(), + ]), current_cfg: Cfg::True, auto_cfg_active: true, parent_is_doc_cfg: false, @@ -990,7 +988,7 @@ fn handle_auto_cfg_hide_show( && let MetaItemKind::List(items) = &item.kind { for item in items { - // Cfg parsing errors should already have been reported in `rustc_passes::check_attr`. + // FIXME: Report in case `Cfg::parse` reports an error? if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) { if is_show { if let Some(span) = new_hide_attrs.get(&(key, value)) { diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 4bcb60a9a40d..d5b20f2b9410 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -97,9 +97,8 @@ impl CfgPropagator<'_, '_> { // // Otherwise, `cfg_info` already tracks everything we need so nothing else to do! if matches!(item.kind, ItemKind::ImplItem(_)) - && let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) + && let Some(mut next_def_id) = item.item_id.as_local_def_id() { - let mut next_def_id = def_id; while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) { let x = load_attrs(self.cx, parent_def_id.to_def_id()); add_only_cfg_attributes(&mut attrs, x); From 6cccea8731c5f8540d65c2458a36655a4b8793f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Sep 2025 14:46:04 +0200 Subject: [PATCH 349/537] Remove `doc_auto_cfg` feature as well --- compiler/rustc_feature/src/removed.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 -- tests/rustdoc-gui/src/lib2/lib.rs | 1 - tests/rustdoc/doc-cfg/doc-cfg-implicit.rs | 2 +- tests/rustdoc/reexport/reexport-cfg.rs | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 71365da316ce..3c51f91331a6 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -101,6 +101,8 @@ declare_features! ( Some("never properly implemented; requires significant design work"), 127655), /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (removed, doc_auto_cfg, "1.58.0", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows `#[doc(cfg_hide(...))]`. (removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4dc961cb9277..b286ae3eb23b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -472,8 +472,6 @@ declare_features! ( (incomplete, deref_patterns, "1.79.0", Some(87121)), /// Allows deriving the From trait on single-field structs. (unstable, derive_from, "1.91.0", Some(144889)), - /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (unstable, doc_auto_cfg, "1.58.0", Some(43781)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), /// Allows `#[doc(masked)]`. diff --git a/tests/rustdoc-gui/src/lib2/lib.rs b/tests/rustdoc-gui/src/lib2/lib.rs index 8db754f91ce6..400488cbe857 100644 --- a/tests/rustdoc-gui/src/lib2/lib.rs +++ b/tests/rustdoc-gui/src/lib2/lib.rs @@ -1,7 +1,6 @@ // ignore-tidy-linelength #![feature(doc_cfg)] -#![feature(doc_auto_cfg)] pub mod another_folder; pub mod another_mod; diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs index 69b10867ee3a..c092675ee5cf 100644 --- a/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs +++ b/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs @@ -1,5 +1,5 @@ #![crate_name = "funambulism"] -#![feature(doc_auto_cfg, doc_cfg)] +#![feature(doc_cfg)] //@ has 'funambulism/struct.Disorbed.html' //@ count - '//*[@class="stab portability"]' 1 diff --git a/tests/rustdoc/reexport/reexport-cfg.rs b/tests/rustdoc/reexport/reexport-cfg.rs index 73b668243166..b624e5acf502 100644 --- a/tests/rustdoc/reexport/reexport-cfg.rs +++ b/tests/rustdoc/reexport/reexport-cfg.rs @@ -2,7 +2,7 @@ // include `cfg`s from the previous chained items. #![crate_name = "foo"] -#![feature(doc_auto_cfg, doc_cfg)] +#![feature(doc_cfg)] mod foo { #[cfg(not(feature = "foo"))] From 660a3486fc6da2c3599a167d73d849178f98bc17 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 27 Sep 2025 13:37:29 +0200 Subject: [PATCH 350/537] Skip stack overflow handler for panic=immediate-abort std installs guard pages and a signal handler to ensure that stackoverflows 1) terminate abruptly and 2) print an nice message. Even for panic=immediate-abort, 1) is desirable, we don't want silent data corruption there. But 2) is completely unnecessary, as users deliberately *don't* want nice messages, they want minimum binary size. Therefore, skip the entire guard signal handler setup, which saves a lot of bytes. I tested this with a hello world binary using fat LTO, build-std, panic=immediate-abort, opt-level=s, strip=debuginfo. `size` reports significant savings: ``` text data bss dec hex filename 15252 1032 104 16388 4004 tiny-before 6881 964 48 7893 1ed5 tiny-after2 ``` `nm -U` goes from 71 to 56, getting rid of a bunch of stack overflow related symbols. The disk size goes from `31k` to `24k`. The impact on the error message is minimal, as the message was already missing. before: ``` fish: Job 1, './tiny-so-before' terminated by signal SIGABRT (Abort) ``` after: ``` fish: Job 1, './tiny-so-after' terminated by signal SIGSEGV (Address boundary error) ``` --- library/std/src/sys/pal/unix/stack_overflow.rs | 12 +++++++++++- library/std/src/sys/pal/windows/mod.rs | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0d2100d66bc0..08a3cee64bab 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -148,6 +148,13 @@ mod imp { let mut guard_page_range = unsafe { install_main_guard() }; + // Even for panic=immediate-abort, installing the guard pages is important for soundness. + // That said, we do not care about giving nice stackoverflow messages via our custom + // signal handler, just exit early and let the user enjoy the segfault. + if cfg!(panic = "immediate-abort") { + return; + } + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" let mut action: sigaction = unsafe { mem::zeroed() }; for &signal in &[SIGSEGV, SIGBUS] { @@ -179,6 +186,9 @@ mod imp { /// Must be called only once #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn cleanup() { + if cfg!(panic = "immediate-abort") { + return; + } // FIXME: I probably cause more bugs than I'm worth! // see https://github.com/rust-lang/rust/issues/111272 unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) }; @@ -230,7 +240,7 @@ mod imp { /// Mutates the alternate signal stack #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn make_handler(main_thread: bool, thread_name: Option>) -> Handler { - if !NEED_ALTSTACK.load(Ordering::Acquire) { + if cfg!(panic = "immediate-abort") || !NEED_ALTSTACK.load(Ordering::Acquire) { return Handler::null(); } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3357946b8f71..b7578b01584b 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -22,7 +22,8 @@ pub mod os; pub mod pipe; pub mod time; cfg_select! { - not(target_vendor = "uwp") => { + // We don't care about printing nice error messages for panic=immediate-abort + all(not(target_vendor = "uwp"), not(panic = "immediate-abort")) => { pub mod stack_overflow; } _ => { From 07ed247d3c28670449f142b54b025fc429ac318a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 27 Sep 2025 14:40:38 +0200 Subject: [PATCH 351/537] Ignore crash test that doesn't crash on Apple platforms This wasn't caught by CI, because debug assertions aren't enabled there. --- tests/crashes/120175.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/crashes/120175.rs b/tests/crashes/120175.rs index e441454bed29..e06da5a8e0ae 100644 --- a/tests/crashes/120175.rs +++ b/tests/crashes/120175.rs @@ -1,5 +1,6 @@ //@ known-bug: #120175 //@ needs-rustc-debug-assertions +//@ ignore-apple (raw-dylib doesn't work on Apple targets yet) #![feature(extern_types)] #![feature(raw_dylib_elf)] From d42acf522ff234e187aef2de8c6903bc94efe444 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sat, 7 Jun 2025 03:24:35 +0000 Subject: [PATCH 352/537] Include additional hashes in src/stage0 This patch changes `bump-stage0` to include: * The sha256 hash of the channel manifest used to create `src/stage0`. * The rust and rustfmt git commit in `src/stage0`. * Hashes of all the artifacts, like the source tarball, in `src/stage0`. Combined this will allow for: * Projects that bootstrap their own compiler, such as Fuchsia, or users of [bootstrap], to build their compilers offline without needing to communicate with static.rust-lang.org. * Auditors to detect if the channel manifest, and all the artifacts inside the manifest, were modified after it was used to generate `src/stage0`. Furthermore, if they did find modified artifacts, they could determine if the Rust Signing Key was compromised by checking if any modified file was signed properly. Finally, it allows regeneration of `src/stage0` when specifying both the day of the build for rust, and the day of the build for rustfmt, which can allow a maintainer to regenerate `src/stage0` to verify nothing changed. [bootstrap]: https://github.com/dtolnay/bootstrap [mrustc]: https://github.com/thepowersgang/mrustc --- Cargo.lock | 2 + src/bootstrap/src/core/download.rs | 2 +- src/build_helper/src/stage0_parser.rs | 14 ++++ src/tools/bump-stage0/Cargo.toml | 2 + src/tools/bump-stage0/src/main.rs | 97 ++++++++++++++++++++++++--- 5 files changed, 105 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d4a1bf6a788..715d580e051d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,8 +334,10 @@ dependencies = [ "anyhow", "build_helper", "curl", + "hex", "indexmap", "serde", + "sha2", "toml 0.8.23", ] diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 37871f0fe1e2..a096d116e73f 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -506,7 +506,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( return Some(PathBuf::new()); } - let VersionMetadata { date, version } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?; + let VersionMetadata { date, version, .. } = dwn_ctx.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); let host = dwn_ctx.host_target; diff --git a/src/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs index 2723f4aa7b91..3f3297dcd2bb 100644 --- a/src/build_helper/src/stage0_parser.rs +++ b/src/build_helper/src/stage0_parser.rs @@ -10,6 +10,8 @@ pub struct Stage0 { #[derive(Default, Clone)] pub struct VersionMetadata { + pub channel_manifest_hash: String, + pub git_commit_hash: String, pub date: String, pub version: String, } @@ -50,9 +52,21 @@ pub fn parse_stage0_file() -> Stage0 { "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(), "nightly_branch" => stage0.config.nightly_branch = value.to_owned(), + "compiler_channel_manifest_hash" => { + stage0.compiler.channel_manifest_hash = value.to_owned() + } + "compiler_git_commit_hash" => stage0.compiler.git_commit_hash = value.to_owned(), "compiler_date" => stage0.compiler.date = value.to_owned(), "compiler_version" => stage0.compiler.version = value.to_owned(), + "rustfmt_channel_manifest_hash" => { + stage0.rustfmt.get_or_insert(VersionMetadata::default()).channel_manifest_hash = + value.to_owned(); + } + "rustfmt_git_commit_hash" => { + stage0.rustfmt.get_or_insert(VersionMetadata::default()).git_commit_hash = + value.to_owned(); + } "rustfmt_date" => { stage0.rustfmt.get_or_insert(VersionMetadata::default()).date = value.to_owned(); } diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 79097f2c1891..943b8453ef85 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -9,6 +9,8 @@ edition = "2021" anyhow = "1.0.34" build_helper = { path = "../../build_helper" } curl = "0.4.38" +hex = "0.4.3" indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } toml = "0.8.23" +sha2 = "0.10.1" diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index faed748785f4..079e7b1ce71e 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -4,6 +4,7 @@ use anyhow::{Context, Error}; use build_helper::stage0_parser::{Stage0Config, VersionMetadata, parse_stage0_file}; use curl::easy::Easy; use indexmap::IndexMap; +use sha2::{Digest, Sha256}; const PATH: &str = "src/stage0"; const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"]; @@ -13,13 +14,14 @@ struct Tool { config: Stage0Config, channel: Channel, - date: Option, + compiler_date: Option, + rustfmt_date: Option, version: [u16; 3], checksums: IndexMap, } impl Tool { - fn new(date: Option) -> Result { + fn new(compiler_date: Option, rustfmt_date: Option) -> Result { let channel = match std::fs::read_to_string("src/ci/channel")?.trim() { "stable" => Channel::Stable, "beta" => Channel::Beta, @@ -38,7 +40,14 @@ impl Tool { let existing = parse_stage0_file(); - Ok(Self { channel, version, date, config: existing.config, checksums: IndexMap::new() }) + Ok(Self { + channel, + version, + compiler_date, + rustfmt_date, + config: existing.config, + checksums: IndexMap::new(), + }) } fn update_stage0_file(mut self) -> Result<(), Error> { @@ -78,10 +87,21 @@ impl Tool { file_content.push_str("\n"); let compiler = self.detect_compiler()?; + file_content.push_str(&format!( + "compiler_channel_manifest_hash={}\n", + compiler.channel_manifest_hash + )); + file_content.push_str(&format!("compiler_git_commit_hash={}\n", compiler.git_commit_hash)); file_content.push_str(&format!("compiler_date={}\n", compiler.date)); file_content.push_str(&format!("compiler_version={}\n", compiler.version)); if let Some(rustfmt) = self.detect_rustfmt()? { + file_content.push_str(&format!( + "rustfmt_channel_manifest_hash={}\n", + rustfmt.channel_manifest_hash + )); + file_content + .push_str(&format!("rustfmt_git_commit_hash={}\n", rustfmt.git_commit_hash)); file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date)); file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version)); } @@ -112,9 +132,16 @@ impl Tool { Channel::Nightly => "beta".to_string(), }; - let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?; + let (manifest, manifest_hash) = + fetch_manifest(&self.config, &channel, self.compiler_date.as_deref())?; self.collect_checksums(&manifest, COMPILER_COMPONENTS)?; Ok(VersionMetadata { + channel_manifest_hash: manifest_hash, + git_commit_hash: manifest.pkg["rust"] + .git_commit_hash + .as_ref() + .expect("invalid git_commit_hash") + .into(), date: manifest.date, version: if self.channel == Channel::Nightly { "beta".to_string() @@ -138,9 +165,19 @@ impl Tool { return Ok(None); } - let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?; + let (manifest, manifest_hash) = + fetch_manifest(&self.config, "nightly", self.rustfmt_date.as_deref())?; self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?; - Ok(Some(VersionMetadata { date: manifest.date, version: "nightly".into() })) + Ok(Some(VersionMetadata { + channel_manifest_hash: manifest_hash, + git_commit_hash: manifest.pkg["rust"] + .git_commit_hash + .as_ref() + .expect("invalid git_commit_hash") + .into(), + date: manifest.date, + version: "nightly".into(), + })) } fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> { @@ -164,12 +201,29 @@ impl Tool { } } } + for artifact in manifest.artifacts.values() { + for targets in artifact.target.values() { + for target in targets { + let url = target + .url + .strip_prefix(&prefix) + .ok_or_else(|| { + anyhow::anyhow!( + "url doesn't start with dist server base: {}", + target.url + ) + })? + .to_string(); + self.checksums.insert(url, target.hash_sha256.clone()); + } + } + } Ok(()) } } fn main() -> Result<(), Error> { - let tool = Tool::new(std::env::args().nth(1))?; + let tool = Tool::new(std::env::args().nth(1), std::env::args().nth(2))?; tool.update_stage0_file()?; Ok(()) } @@ -178,18 +232,24 @@ fn fetch_manifest( config: &Stage0Config, channel: &str, date: Option<&str>, -) -> Result { +) -> Result<(Manifest, String), Error> { let url = if let Some(date) = date { format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel) } else { format!("{}/dist/channel-rust-{}.toml", config.dist_server, channel) }; + let manifest_bytes = http_get(&url)?; + + let mut sha256 = Sha256::new(); + sha256.update(&manifest_bytes); + let manifest_hash = hex::encode(sha256.finalize()); + // FIXME: on newer `toml` (>= `0.9.*`), use `toml::from_slice`. For now, we use the most recent // `toml` available in-tree which is `0.8.*`, so we have to do an additional dance here. - let response = http_get(&url)?; - let response = String::from_utf8(response)?; - Ok(toml::from_str(&response)?) + let manifest_str = String::from_utf8(manifest_bytes)?; + let manifest = toml::from_str(&manifest_str)?; + Ok((manifest, manifest_hash)) } fn http_get(url: &str) -> Result, Error> { @@ -219,11 +279,14 @@ enum Channel { struct Manifest { date: String, pkg: IndexMap, + artifacts: IndexMap, } #[derive(Debug, serde::Serialize, serde::Deserialize)] struct ManifestPackage { version: String, + #[serde(default)] + git_commit_hash: Option, target: IndexMap, } @@ -234,3 +297,15 @@ struct ManifestTargetPackage { xz_url: Option, xz_hash: Option, } + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +struct ManifestArtifact { + target: IndexMap>, +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "kebab-case")] +struct ManifestTargetArtifact { + url: String, + hash_sha256: String, +} From 76bb0d1870b0023d6184ee4b714e2cf4ad1d96d4 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 27 Sep 2025 08:45:40 -0400 Subject: [PATCH 353/537] Update stage0 per previous commmit --- src/stage0 | 1022 +++++++++++++++++++++++++++------------------------- 1 file changed, 522 insertions(+), 500 deletions(-) diff --git a/src/stage0 b/src/stage0 index 6d2f0402f4ac..556ced41d3da 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,506 +13,528 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_date=2025-09-16 +compiler_channel_manifest_hash=55f3014ea3a3b17cfa5060d9188fd13d13b065456661a3d670dd061719713f32 +compiler_git_commit_hash=bb624dcb4c8ab987e10c0808d92d76f3b84dd117 +compiler_date=2025-09-21 compiler_version=beta -rustfmt_date=2025-09-16 +rustfmt_channel_manifest_hash=2f19b9b74a17d0283264a227ed552d7df6729929fcb73b2d5bb321feed8a5c85 +rustfmt_git_commit_hash=54a8a1db604e4caff93e26e167ad4a6fde9f0681 +rustfmt_date=2025-09-27 rustfmt_version=nightly -dist/2025-09-16/rustc-beta-aarch64-apple-darwin.tar.gz=3e3fbcf51f2632b8890b38537ea5446147b85fd62b21798b4fb2a032a4abd6c9 -dist/2025-09-16/rustc-beta-aarch64-apple-darwin.tar.xz=296ef2ae4dc8b4f411423a4384821e5b8e305be809b55522a0f02c97b83ce14a -dist/2025-09-16/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=fe7026f1310a84f3490d0ffb8476bddc36992fcb2d7e450c036aae6bbbb218ef -dist/2025-09-16/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=70bd356d7f39ff1ef8511941671caae84f43d3a9ab493ed131467d27bf5c53f1 -dist/2025-09-16/rustc-beta-aarch64-pc-windows-msvc.tar.gz=9b0f42d2713c20d1df9e401410f874f04ffbff2e0c61d19d2f8689d4e55da562 -dist/2025-09-16/rustc-beta-aarch64-pc-windows-msvc.tar.xz=086ff4c532289581325b1cb5c629f899418dd392249d3c0bd2137a0d73ebccca -dist/2025-09-16/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=4860148593cc5f5662cb89c9484d71af472223b8a9f9644e6709802154e7d02d -dist/2025-09-16/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=a7f290455c134c72518267e7dfc5a51d550497ffcf539dac3b41c57486e1d370 -dist/2025-09-16/rustc-beta-aarch64-unknown-linux-musl.tar.gz=7a17d7a65ca7c933de8829e5991f991d917df7007c122fc55d64efa0fe53344a -dist/2025-09-16/rustc-beta-aarch64-unknown-linux-musl.tar.xz=6ab69fc25888475048dc5eac7adc7f6b02295dc7de7d0e92aad5ff562c500322 -dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=00ff0a967ee41642e6b316b190485a7d04c6749ff571e55cf73548b0e7d74b05 -dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=ce2c11e633e367544a70b0a3ad998a2d680277e62ece3eacbf350fa1ada6332a -dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=ded847d958f0417fba13e71ded42cee387387076b4426b2f2002d53dd998c27c -dist/2025-09-16/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=54ee1d25f57db5d1c2b153533362ecb7fd326b8dd46b8240367ea865a059ca68 -dist/2025-09-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=8f964d41f6608ba04d2d84f5532a057654f3f328b19bc6ee4b9a88f6f64dcec7 -dist/2025-09-16/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=b6a34332cb027345f54f75e03cee1c65345e8671df081e8dd23111d2233bf6e6 -dist/2025-09-16/rustc-beta-i686-pc-windows-gnu.tar.gz=760c5f1bc081a14b4df2e0c6a1ce80d96b63e15e0b751cfe535eb5775aa9e34b -dist/2025-09-16/rustc-beta-i686-pc-windows-gnu.tar.xz=4376609352714e1e30a4b0c57fe43beb2b0edccda412e18e11c3b8b3092a87d0 -dist/2025-09-16/rustc-beta-i686-pc-windows-msvc.tar.gz=3d0f08e30f4ae2cb513548f66cc6405ba0c2cc74e826c04cf0bdad3d3c14bcfa -dist/2025-09-16/rustc-beta-i686-pc-windows-msvc.tar.xz=a68b01fb491496bb2b8861af9b900a2960f4ea9f64f0946caa09c043ecb3df2f -dist/2025-09-16/rustc-beta-i686-unknown-linux-gnu.tar.gz=3b56ab8e485b3e4bd5c0f1e1ff30389acb9d0d0e0662ff834fb3a855157c965a -dist/2025-09-16/rustc-beta-i686-unknown-linux-gnu.tar.xz=fe871e45e0d987dcaa6a30df8394c54da0204965686a089d6903fff75b8a01e5 -dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=71d53cb70f1962379614c86b07fdea7c1b343587a56734d39aa7de29667d6629 -dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=658f204ab2536ad3b56f238c55c5c6cf3bd7794aceff379f0f5492d28841b5bc -dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=0fe154b5b305259a36b80b9b53894336ceba1562155c05cf92debc5d7bb7e645 -dist/2025-09-16/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=27357f4331d5c357a7b20002571276e2d77e58384095fd3a6910d44a0d85aa87 -dist/2025-09-16/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=bf87cb1717fad96abbb86091c44de6bdeed2bd60437ffa9037d27dda1c71cdbe -dist/2025-09-16/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=778d126b47dc5ef07085c5c760399130219cda6221f6f4ec57c26ebdd7e33299 -dist/2025-09-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=eae03019370901fb49b708c76d001ec9e3df27e7fa1ea9ceb2200640e9d6dfea -dist/2025-09-16/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=61c1b21acc668bdf36cbf64f2b53348d997ffc9997c6ad282d10226e86740044 -dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=057eb2050b31110529a80e27c6df0c95a14bb1f7c568b487dd3a718755a74d27 -dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=cb3078b44dbb6793ac98a28bd6bd7076c28ae13c5ddd1aa02310ec89130b6575 -dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=9a5109124546788b802be36d9415bf0d5bfcc087389156c65a2e30672e10e7b1 -dist/2025-09-16/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=6987de797339aa2f231485897b0a498a841a49f1d0b83fa7e98c0a76767cbe44 -dist/2025-09-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=17cd423d53f6d8fe53dff7abada43d545a2de14136eae7cd02b958f9fe93f5a0 -dist/2025-09-16/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=740945fe14eeea917d64ff47e997ca17be1e0f14dca30632a9fbfb560405b040 -dist/2025-09-16/rustc-beta-s390x-unknown-linux-gnu.tar.gz=52e15e3a56a16b2989b34f0a051ff06fb8dd51be3e6874c41a4ba1e2128d35ff -dist/2025-09-16/rustc-beta-s390x-unknown-linux-gnu.tar.xz=6f998aede2a805d8159f2ea63dda76a7d25eb9cdbd26863394aacfa6d80de084 -dist/2025-09-16/rustc-beta-sparcv9-sun-solaris.tar.gz=45c85ec3de0a773b2c2f4b624abe28c3a906020e1ce6ceded75c0099a1fc1899 -dist/2025-09-16/rustc-beta-sparcv9-sun-solaris.tar.xz=d811ff717ebc59aa9bc5c26ee4b8dcfdb3d2f5a1759179eccf549c8a765fb3dd -dist/2025-09-16/rustc-beta-x86_64-apple-darwin.tar.gz=d31302c29a9efe362d2be87b83b229d5369b2462cea133f9b1b4c7c4cf0f26dd -dist/2025-09-16/rustc-beta-x86_64-apple-darwin.tar.xz=b8f9f0b2e4c681da9bf7fbac2fc22ec2f44c136b368821bfea5a5ab29d85527a -dist/2025-09-16/rustc-beta-x86_64-pc-solaris.tar.gz=498902a6de8cae1494aae6223604381c4e109a38c14649f6e27b075d3f26a685 -dist/2025-09-16/rustc-beta-x86_64-pc-solaris.tar.xz=1cfaeae163fcd4dd2ff44a80c245012576ecb4257d7d763a51f2d7e58878a29b -dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnu.tar.gz=d4c6fa5158c83500d30ef44e129889408dbc49ec862c985a1c36820d3550e94d -dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnu.tar.xz=17bd90bfd6603b24d26397acac55e4b2c23b0dc574834de7bc1f8c2c720aab97 -dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=d270c52fec5ef2e9f009cc3e697b6188320fbeb5445092c7a11af67e520cc9f0 -dist/2025-09-16/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=81f91fc07821af63606268821a039578a7c9b09b8c0e96b85163831fee92e6a5 -dist/2025-09-16/rustc-beta-x86_64-pc-windows-msvc.tar.gz=233356bbd9a46168663752d7dcab67e7ae3ae732fab410bc8adb84230e22398f -dist/2025-09-16/rustc-beta-x86_64-pc-windows-msvc.tar.xz=5f33d8b3a064235c23dfd2edfa8b5f6f2c5075d26529f81881501b8323eae60d -dist/2025-09-16/rustc-beta-x86_64-unknown-freebsd.tar.gz=fda4fa10690458ee7db6081267458e47113e854d65695c95813039400772e263 -dist/2025-09-16/rustc-beta-x86_64-unknown-freebsd.tar.xz=570cd878e440b5d70a0d5fc90917b92a6b8b544a2e6844baafee1fef22d32732 -dist/2025-09-16/rustc-beta-x86_64-unknown-illumos.tar.gz=f8b7273e16de291fad24f2ebbd928b55007a75605fc25ddc35a4967f17e709f6 -dist/2025-09-16/rustc-beta-x86_64-unknown-illumos.tar.xz=77d7f5de006a9d0c56a2cf79423a5702bff445f6e34b4935326d3db30ac8b086 -dist/2025-09-16/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=f61a57a75252d63930630af7d597f3046b7f7f09691cd6ff8c3a080871fa19de -dist/2025-09-16/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=b56298c4ba7a955ecb9135bba06ff6bdb7f4df94b6d64c99460e90e5a022fb87 -dist/2025-09-16/rustc-beta-x86_64-unknown-linux-musl.tar.gz=c6fec77bf71bf35ded56cf70eca28a94e083e0af458b00ed665eedf9270abd73 -dist/2025-09-16/rustc-beta-x86_64-unknown-linux-musl.tar.xz=bce669d29a995189e9d99f686b1f9535ad82cc877a106c89af5b423bef8a9d6f -dist/2025-09-16/rustc-beta-x86_64-unknown-netbsd.tar.gz=cb1a0f5ff6d9c28b83f9c82fcfbf404b2920a7da8233d957e43fe001d5190318 -dist/2025-09-16/rustc-beta-x86_64-unknown-netbsd.tar.xz=25953b44e3b196e89b5dc6028805517f42f6367c6b990a930ba44f63dce0a855 -dist/2025-09-16/rust-std-beta-aarch64-apple-darwin.tar.gz=8ada740b1af444b98c3df74f5f810a05036b6195e6b54115a7e34bed23a30d1c -dist/2025-09-16/rust-std-beta-aarch64-apple-darwin.tar.xz=1211a726975c1a9fbd679156644b83c446cab4d6eb7728d3dc38db6c949b997f -dist/2025-09-16/rust-std-beta-aarch64-apple-ios.tar.gz=58e7ec536d9bee83dcbcdad819c4a27689f02a20acbc75ffcb6ceeec7929da4f -dist/2025-09-16/rust-std-beta-aarch64-apple-ios.tar.xz=f0afe719f83531e0c22d0621b9137d30bacd17ffcc9d0188e9cee2a71f10afa0 -dist/2025-09-16/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=e1f067b248dfcf1d6efbc589a0938ceeaa81087d041889d65b90f4f82aeb35ff -dist/2025-09-16/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=182ad0986236f21ba93d49ed3dbec72e54cbc88d18adf77848e87f497b7b2f05 -dist/2025-09-16/rust-std-beta-aarch64-apple-ios-sim.tar.gz=cd367dce5dc4a5d209db298f97070e55ec16caa8931ef17a189bf5d7f5c21212 -dist/2025-09-16/rust-std-beta-aarch64-apple-ios-sim.tar.xz=b51aba09d7ced8b69e15ec9ca381379cf9f910c1f89109c8764cc15d51fd8293 -dist/2025-09-16/rust-std-beta-aarch64-linux-android.tar.gz=89154dba00da80cd67cff7e9beb1f68721bae9686e1fcff1379a2a4f549eec79 -dist/2025-09-16/rust-std-beta-aarch64-linux-android.tar.xz=d373ed69ed30521b2f724deac051662bcc7d4a919c1ff9f56b59ef028f07dcf0 -dist/2025-09-16/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=9e84923928671f76762752a559d0e9a54f513b2f518eaad3da6f5772e46183c0 -dist/2025-09-16/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=9170e87332e2a74624fa1dbaddb725f6cb331a8f65a5b0b2781c04aa58bc48fe -dist/2025-09-16/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=929786491660eedf2cb6c02036ce560043a7bec349bde762effa53ba59d17c81 -dist/2025-09-16/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=72b395a15c0af1c92434a95010fec5435343190c3b90d55d2c7d17d3d4c6da52 -dist/2025-09-16/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=36245bab64c4757821ca0732fe88fb5620601035f50bcd2d061386903abe7027 -dist/2025-09-16/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=4c1bfe4453d36d554956f7ebb169bb81912815a28960bd7caf977940109573f1 -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=080603e3b117d3654b2e0b88ec172f4c5319ebadf9386074e7e6f0c466e9c90a -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=4ea35b78b18a121bd3b0165d9f3278f3a454e108564e02b6c7d7133a33a99788 -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=9c5b7188fed949b0462f9d6c45221b8b98e7feebdc4f8bc2d6d0d652cf3b3c24 -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=31514db13f19dea13e47b8eff9fd8daec6bd0a73816aefadb94ad4e771d6a902 -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=a540735416f0b264444281865e1ed450c5bd58275f73426191cfb547b674ea7a -dist/2025-09-16/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=9922ad22f002f5df232d8ed1dcdcd23a5e1a0a5b4b27e27c3b5fbd5b39087d03 -dist/2025-09-16/rust-std-beta-aarch64-unknown-none.tar.gz=618073f52e27d3ebd15b028398524a12e3bd91d4147e70b2160430e03ecdb178 -dist/2025-09-16/rust-std-beta-aarch64-unknown-none.tar.xz=3fa92c9383ac122c4b9ea2a00ff9f38d94b52c384b418b13ea573115daa07563 -dist/2025-09-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=33c4825523ef0e27b038111d3504cfbb4e049fcc3e136ddec186268346b647d9 -dist/2025-09-16/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=4487b93a8c7ac712328c98a660948e795e833f4edd3c92449df5472de6e320b9 -dist/2025-09-16/rust-std-beta-aarch64-unknown-uefi.tar.gz=f0c275d8bd220dc066541e6f2c7e41b6d019d698fa2b613c1f9c87ab4e29f4af -dist/2025-09-16/rust-std-beta-aarch64-unknown-uefi.tar.xz=daed68a82600fe2f3652ae87e4c491460891906fcd06ae206bc794c354771564 -dist/2025-09-16/rust-std-beta-arm-linux-androideabi.tar.gz=9fa058b5bd0ac5af231cc5ee31f67cf3f16b361a41aceb43b17c81d8e180d16e -dist/2025-09-16/rust-std-beta-arm-linux-androideabi.tar.xz=c6868144f5f5fdfc0d993f66fa91a01a91e0288014a7ab5d6233a93447508852 -dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=5cd076f756c63e54067d780167da3e35bcb04f487fefa093028b0cd3435a2fcb -dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=3322a270f3696fc2254536608ebc49e047ad59e1a01493381c9c52f813bcb8ae -dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8bed8176ed380d974c2bc6df5314ac385ca6b72a623a8d16c00b753932a64db9 -dist/2025-09-16/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=d557f55446ba39a1b3335ff1e4196ab40effa4ba42b2ce91bbde93738fd93da0 -dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=12a56e9f5c9caf4e262b9361af5ea5b62ec29b18ffdb807cda83655c531670b5 -dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=82b28e64f6278cb24573d699b14826a51be465b68cb48e767a26f1938221f5c4 -dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=a3076f1f12895062e42a8ceacd5c06a3156b5a553c708615fddb975366d9424a -dist/2025-09-16/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=4bf81edd4a193e6850bccbffb66c6005b1b99322192e87183d684dd9ec528cad -dist/2025-09-16/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=2170d924f4ccc579baf862171934029505d476170825397580154dfab860d4a8 -dist/2025-09-16/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=dc3bdf6f93b32aa19987d149ed7da7616f3785f67a63fcf1e0d1aebeb8007d67 -dist/2025-09-16/rust-std-beta-armebv7r-none-eabi.tar.gz=2863a22ce3663edd346d730cac4bbdef3b9cd2ea2cd5907dcbc61220833e24e8 -dist/2025-09-16/rust-std-beta-armebv7r-none-eabi.tar.xz=74a752daef0446ed260845b016b3e57d20de4e914102713e0c3b652329f9f6f1 -dist/2025-09-16/rust-std-beta-armebv7r-none-eabihf.tar.gz=8fc3fcf203da0fa6f321abbda405ba0121dbd898ea02513431a5ca3dd5e6e16d -dist/2025-09-16/rust-std-beta-armebv7r-none-eabihf.tar.xz=65cfd5061c4db0963b28f7bc636ece115ff7b812710ba9f902977f5014bdeafd -dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=1cb760fdde8e9d84c5caa787488f0bb05c5e649f411b666f2d6a5440126f5992 -dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=9146b64438a68c506a93ae3c4d4d1a928358b562fac3b7513a95c8098cebdae0 -dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=9df691f77c95a0bdf5c45fc546c2319863cdca4d433780fe8c7cd146496382b8 -dist/2025-09-16/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=bba043357ba6c78fd46430c169710a264109ee5dadb79b98075744bac273418c -dist/2025-09-16/rust-std-beta-armv7-linux-androideabi.tar.gz=ab5726ae0472a8563b7e1e0dd6de32e1e9ee2dca45259bd1d382a24167919c61 -dist/2025-09-16/rust-std-beta-armv7-linux-androideabi.tar.xz=5af2a58f78fcd9dbcf1fac95cb50633ab9128e1e728960c0025e310a5528326f -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=9ff1f79f8c03756b41f8386995dbb011387982a657262c013579d0866a18ff1d -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=32dd8b2be52449b4e592a87acfba122b80990d2993fa81b48b81c0de4afb1533 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=7420a4ecd9ebb55b6864a22fedec9def0585f8460eaebbcd9e236cac2ae0a6a8 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=75de468d6d4041d77e5757118c3c93df6319f30ba6372fdc8e859b9e48f27d81 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=96f7dbe5d4bfe852b22f971cb59b7fa0981fd7fdc9e8d28fd1b6f6ae3bc59bfa -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=4166e6b0c28eca8a507f1d3c83948ba09361198466eeb648f491d9850e884df9 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=035c4db6428b912280ac56bb520bad29255b3c30bec0e89839721443109a7ce5 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=4a94449dd1f02d748c79ec1aed3907cbce97dc5641e5be3b3011234ef3517987 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=94006dd7c1a1d6cb28972369a0b0c429de992d541549d4b292fd6b737eacce24 -dist/2025-09-16/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=bb5cce4d13f2ae9d9d6f254d021d516189f29b6e78f3c1824e0803f7856ce7e9 -dist/2025-09-16/rust-std-beta-armv7a-none-eabi.tar.gz=453d62c4392ffd108233b7ce9b6abf0cc04b28a63bbbc5b979927ed7e9f8481f -dist/2025-09-16/rust-std-beta-armv7a-none-eabi.tar.xz=9b4093e7735ffe3c79f16f99a412492588a6652242e2a18c0f278e24e34cb333 -dist/2025-09-16/rust-std-beta-armv7r-none-eabi.tar.gz=293dcff7ac56a7f52fbfa1afef9fa2b4a3e14b9b418c5a56e12e8c7cc76c963f -dist/2025-09-16/rust-std-beta-armv7r-none-eabi.tar.xz=75f3737b88d197769d999b484aeb6aff705696fdccec8f3772c7a1e10630b146 -dist/2025-09-16/rust-std-beta-armv7r-none-eabihf.tar.gz=3d988af87a2c90efc5674f77baf67f5933fe60ae6ab9f4eb4256f14d98446824 -dist/2025-09-16/rust-std-beta-armv7r-none-eabihf.tar.xz=e91a15900421a8a445a7a0038923ad197fea4ec19e972ba7ff75fd4dd7d7ac12 -dist/2025-09-16/rust-std-beta-i586-unknown-linux-gnu.tar.gz=19795fe21f305ed033354d127f8e9e7aa0e9d7c67f756d22beb161aaeb9a0742 -dist/2025-09-16/rust-std-beta-i586-unknown-linux-gnu.tar.xz=8afa409edf8dfb45eab3565add6dde2fa71118008ee1e7e1416fb8dc11f66fde -dist/2025-09-16/rust-std-beta-i586-unknown-linux-musl.tar.gz=43aaa9101863b6a419330ec75f0ffde61faf2a27f050947d2a200e5a705dd085 -dist/2025-09-16/rust-std-beta-i586-unknown-linux-musl.tar.xz=86ac890f2aaee4382a126ad9e667d53039dbca550aa548090706bdc308749962 -dist/2025-09-16/rust-std-beta-i686-linux-android.tar.gz=c3df364048b9af096c607a8e5639dc37d470ab125441ea04a2f2241766338bd5 -dist/2025-09-16/rust-std-beta-i686-linux-android.tar.xz=556bb5e7e4effb543c04a64cba683b81a6ffaa319cf1d053482968767480b9b9 -dist/2025-09-16/rust-std-beta-i686-pc-windows-gnu.tar.gz=8c141a8c3b4cdbc2eff61d2a557fa602b9039dd54ff2000d0a0b790ae58c0879 -dist/2025-09-16/rust-std-beta-i686-pc-windows-gnu.tar.xz=3995a3c391e242663533680600a38343396e2a73b6876b1dd691d83dd143eac7 -dist/2025-09-16/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=3da461c03124d6ca148ed1d4cc80be4bd0d9f4610df95770ca800d72ef6c2b4f -dist/2025-09-16/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=7eaba102d1ce8ea0461657dcce62a5f8826f2154f56f89e9385e75fdc763c399 -dist/2025-09-16/rust-std-beta-i686-pc-windows-msvc.tar.gz=d1e31c04ff2145122df2ab05af6e2ba1091d1788741234cc39524f1289886187 -dist/2025-09-16/rust-std-beta-i686-pc-windows-msvc.tar.xz=330aca62a0cb38342ce6eda427c6074651ddd0c83c4b28b53ddc736edf049ee5 -dist/2025-09-16/rust-std-beta-i686-unknown-freebsd.tar.gz=48dabb6775c14d23bf04a8c5c26f2e4d6af369dff6d506aa08cf2a08d75a5d8d -dist/2025-09-16/rust-std-beta-i686-unknown-freebsd.tar.xz=db97db17addbf5d4e314f77ac9bb232a661042edf7beeed73b252e44c6439fe8 -dist/2025-09-16/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3abbec5a87dfe240bbdaf6e9a92acb2d8e6e684983803daadc7750290da71264 -dist/2025-09-16/rust-std-beta-i686-unknown-linux-gnu.tar.xz=568aec0d1427a2d866c7550dfc770be13401902741999410d4dc2e7772ec0a57 -dist/2025-09-16/rust-std-beta-i686-unknown-linux-musl.tar.gz=0739e8dcab50c87156cb3e52a18b57da6040fffd9509561fb3046e81be953a40 -dist/2025-09-16/rust-std-beta-i686-unknown-linux-musl.tar.xz=8ed8a4b1f402593db73fc2e9540664d9e4e12b8e1b5f027e56b2f3c4784a8995 -dist/2025-09-16/rust-std-beta-i686-unknown-uefi.tar.gz=40a2726131ef0e6102667bcc8ea9a64b4b19f12d58696ab434b74f9abf37cee0 -dist/2025-09-16/rust-std-beta-i686-unknown-uefi.tar.xz=500b0018fe01e9a9949ca077bb69426078a2774e83b95319d09bab5d3f6d0e04 -dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=64aadbe1da544e2f08cafb217ec1ad341b8e2adc660f60502f700773983d059a -dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=e864959561ee49a0ae680f93307929d0e16013d2ef0743a525c5d592faa10704 -dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=c709c58bb18b5a9385e07998dfe31e3ade0661fbfd4811907a6e7cfffbfe2e6c -dist/2025-09-16/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=e797481997def9fe0a6466b31439d1eeb4b299c92cde3a25a7fdd557611f0888 -dist/2025-09-16/rust-std-beta-loongarch64-unknown-none.tar.gz=79d43f32d6830a0d3c9e1e8fca3ba87db44e692cc70431ac6cabea5bc59b8f0b -dist/2025-09-16/rust-std-beta-loongarch64-unknown-none.tar.xz=4d158a9d4f4e1943b2d00fd19adad762c35af24200742440bccfea62304272b8 -dist/2025-09-16/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=f0c460fee60c913463d9c1fbe369287ab436cc7e2882487afef457c78cf86ad3 -dist/2025-09-16/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=f15e2baff9b0ce68ca7e1595f00b21c45bff33a1b75fbf05a8f04b096295aa0f -dist/2025-09-16/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=102c4017e11cc3407f4871aaade7f3292c8cdc92707a243788e0e4a62604cce0 -dist/2025-09-16/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=6eaad8877694af02a10d18ce609b6678d96e75f87a1684b67279c9915601bd3b -dist/2025-09-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=26139715f7faac9be6e458ee1be840db044692a518cd0fde29c59454405d3063 -dist/2025-09-16/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=0edf1c0a3b8ce5dc76f1ade2dceb91f96a5afa3e54c7f25f3d3320dabeab06f2 -dist/2025-09-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=dbdd4f2cb5cacdf2656f83f0dc0b2101613cc344819e9ba8e790406e17d16b16 -dist/2025-09-16/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=a6dd7f0416ceea63ac723d4aeaf9cbd8d7ed8ed7d5b8925b3317cee75b9138df -dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=424eabcd66e922cb61757842c46afd298cac2e1ff809b593f6f409732261f4a3 -dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=7ac3a7e79c5b3c498daad88a6f926544eaf59d04711cf20ba05c1391544a4335 -dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=9e21d985a6702a96161aeb9ea6d1e12eb52136c7433b2ca5597c07b85a954939 -dist/2025-09-16/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69658c2818ff575eefbda5e64a2a6f253ce21f587a72afb2727466a923ec508f -dist/2025-09-16/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=25da1a37707d9dbac16d91f5177eaa5244f4280758f3b5a0bfbb09b5ae190720 -dist/2025-09-16/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=52f6a0752e9db84c0efa49826988dd64f32930799ce2e057b3a6a20a5c696181 -dist/2025-09-16/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9f4f18ca2d1d4d7e8785f3ae61084aeaee7581d7eac2c7c883557cf30888cb57 -dist/2025-09-16/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=2ef831047ada8f706fa30a655e8a2b17c15c1f10e65c66a0d3577085ff1e80c2 -dist/2025-09-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=9420edabe9112cb1ab9fee01dea1bdb30a866b4633205f287767c07fb57f4630 -dist/2025-09-16/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=ed7b43b375dc7c30e1bd1add31940192978ad86c5c6684b54b24252117e92008 -dist/2025-09-16/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=cbb03936548c947633b7dff7952653aef98ae25d1ff79b8f8549e87158b6cac6 -dist/2025-09-16/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=c957ec9bc4b1345bc805b506caeeee9350e9f07d31d4177796f461cce7e7a341 -dist/2025-09-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=46fd5976d8bd59a89ebd2c74cc246b9727516b28cb9b1a839ac06340d738a4bf -dist/2025-09-16/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=a7640744bef500db2e7ebaafc4c93e73acb31b61faf47decef61ed46db73c001 -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=537dd37985108561d6e0afe76238193fa33f1e600aba44b484a15d1f40d68142 -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=bda3e2c4b93d864dd75bf64e08ba3d2ac9719581fb890c62073078d2005bd634 -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=3edbf40890f0f52cb61c0ec8665a43d230e6e148dd4afbdbd7ca8ad53a0a2b8d -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=a515cc391e794e397ce34eb994f3a1c35cff7e7e31d54a859141000a52397c70 -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=d45fbe65a55b3010fd8994d3effec67f96d86593d37b6fefeb956f4a6b282e50 -dist/2025-09-16/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=13f9c87c6bed3b905ec7564fb79517e891b4a70d6c5191a876844199780f7a81 -dist/2025-09-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=e55f12443bf8c44e27d585bc1c38472e3175bb9d7913af55ab3bcd8f23498146 -dist/2025-09-16/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=5cde9db69b110f1766da147105e3a8d879dd36c69b2367416228024d183b12b0 -dist/2025-09-16/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3fb23f12e07d3b4ef59a637fe68c2ad1799aead28c65cf3d5d136dfea4c12eb9 -dist/2025-09-16/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=999b7f7813d0d868bbda410fa37d26ba737d443a99ad74d8c2b0ecbc24fb1af3 -dist/2025-09-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=12e756fe1f5b57a752916b7397b981e288cc30b5861b16c5a710778c372be42a -dist/2025-09-16/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=0d0ad94937379ac571397b7f10ec5aa20cccf5401aae16ad4d18582dc609055e -dist/2025-09-16/rust-std-beta-sparcv9-sun-solaris.tar.gz=4bbe087dae754754f4dc1c05aaf664c5e0dd4429932feba88aab744e7c5b7472 -dist/2025-09-16/rust-std-beta-sparcv9-sun-solaris.tar.xz=dfa49be70f7ee3989cec7f634cf84e3b418f48882af8b69540e41f2ffb8cc216 -dist/2025-09-16/rust-std-beta-thumbv6m-none-eabi.tar.gz=598622e28c6ce111f4d47e2172a0657c3b0ca62c42895836376b1959fc2e094a -dist/2025-09-16/rust-std-beta-thumbv6m-none-eabi.tar.xz=359bb98d293e1cea22a505377ce49ba95095c735b50b7d404ce4f36d84bdfec4 -dist/2025-09-16/rust-std-beta-thumbv7em-none-eabi.tar.gz=d1f994c835b1d72a665eeb7aa4683a09ac60c1977766b066c817c3eb37ad3a4a -dist/2025-09-16/rust-std-beta-thumbv7em-none-eabi.tar.xz=22e8605af621866d82f2bdcd8089a561e10f4055624aa6dff5d704b953b7d547 -dist/2025-09-16/rust-std-beta-thumbv7em-none-eabihf.tar.gz=8e862615db8daf2c063d27f1860bd083fadefd459634e61b946ca05b8747308d -dist/2025-09-16/rust-std-beta-thumbv7em-none-eabihf.tar.xz=8c9b3d2913242cd2e7fc690e02bd28690fa50b7278befa8b57ec9b7eec4f34e4 -dist/2025-09-16/rust-std-beta-thumbv7m-none-eabi.tar.gz=fa79d4e07630821149b151bc5673205a479570bfd971e66e874e75b5046bdfc5 -dist/2025-09-16/rust-std-beta-thumbv7m-none-eabi.tar.xz=f6f3c14f35d3b5fd01a6244f802d99e261e529bc6d4a6c5749b1cfccd524c16b -dist/2025-09-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=194bc6660b3d4809d5f709e7f82159141e90b31d2318cd550b4deab65e108fe6 -dist/2025-09-16/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=36534004068562d8678a3cd73f8f82b50406aad6daeecf348246375da3bae720 -dist/2025-09-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=622ec13126461d4d6c1f7eb3fc387279c03ffbb96fdbbfcc7c22c2433e62232d -dist/2025-09-16/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=a8162987ddefbde68e2931fc824371aa71d595106488a48732b67ec45f36ac4a -dist/2025-09-16/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=6d7f31ee7fd8633d8497cddfbe05a1ca064c4d45f50066e86cd82fe4b40b93d5 -dist/2025-09-16/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=9b3309e290007406d410b8ee86ecef887d5c48b515b11cf7827baef23a0c4a7d -dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=74fd7db50be0b77e7a44d1a32afc76f2a438fb789ea32f3ce1ceff00ccbf030c -dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=e7736bc6c78eba1947ca6ec4ae5d875de192f44755ade737ce1e367f294576d8 -dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=d8905fddbae4ae3e39439fe5234cd05454034d9f2a847056766bbe41126405f1 -dist/2025-09-16/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=94628c4c60615b15f1c5b331a803d4d1963289b770ba54adc4458e52d17397fe -dist/2025-09-16/rust-std-beta-wasm32-unknown-emscripten.tar.gz=68c53c1069b29461573c68b5df7ae2e30b4b7dd682cde70f26a200854525c012 -dist/2025-09-16/rust-std-beta-wasm32-unknown-emscripten.tar.xz=cc1a4d61bc45832fa1ae19ecc1347d084249f1be3553fb33d33f0e5d8df5fe5d -dist/2025-09-16/rust-std-beta-wasm32-unknown-unknown.tar.gz=a33ed15817407053144b8a6041dab287a390b3338dafcd1b02418b3dbe18b024 -dist/2025-09-16/rust-std-beta-wasm32-unknown-unknown.tar.xz=f0df12d2767da7528c614f5bdf6a9c6bec831b4020eed357409d3fc7fb0c869c -dist/2025-09-16/rust-std-beta-wasm32-wasip1.tar.gz=86634e652b087947b914b590a2e978ef1d29d09b69afff63a682f26b6dcac41d -dist/2025-09-16/rust-std-beta-wasm32-wasip1.tar.xz=04e2a9c6914b17664443b674827ab706869a81200c885e97779df0da98682612 -dist/2025-09-16/rust-std-beta-wasm32-wasip1-threads.tar.gz=3fef167485111064b1d468e5664d9173e24dbf20406165f92293f304457aeee0 -dist/2025-09-16/rust-std-beta-wasm32-wasip1-threads.tar.xz=7e12cabce073a54fbd4c97d3169e34e4beb3872a161c7c082e148b0d4adb2f7b -dist/2025-09-16/rust-std-beta-wasm32-wasip2.tar.gz=3b8f3e6d4ce34bc8c5300b77bdf875b04a69f87f73d930439bacf56f061f667f -dist/2025-09-16/rust-std-beta-wasm32-wasip2.tar.xz=056ad523469276f90f185b72696b20c6b47f57b5721544a20f6e765cc51769fc -dist/2025-09-16/rust-std-beta-wasm32v1-none.tar.gz=fee626762c4bee195d800883ba15d890604280f0cddb08aa64a6199fc4591635 -dist/2025-09-16/rust-std-beta-wasm32v1-none.tar.xz=7bc289363efb2d5555e9742bf619decc2454cb784c133db55a71be4c0aed9f90 -dist/2025-09-16/rust-std-beta-x86_64-apple-darwin.tar.gz=51cf2f8f249da5df653efb073c81047583bc7bf952a4b03d6d05c9fecb7fa0c7 -dist/2025-09-16/rust-std-beta-x86_64-apple-darwin.tar.xz=4e380037df6b548916136138069e76139dbc069688ec717632c30a07854d0739 -dist/2025-09-16/rust-std-beta-x86_64-apple-ios.tar.gz=b232b73befda81ffaf0d1db7838e2057c503cf2f4f1e95f0706cfd0faf77d853 -dist/2025-09-16/rust-std-beta-x86_64-apple-ios.tar.xz=1431fa936f5909e4e92894c7e2074d3db879c10cf3f2344b050f9c77965d1373 -dist/2025-09-16/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=fb0a1f0228c051a85440933358f7c00d47c4ce44a15a0b0025b00331ec53f876 -dist/2025-09-16/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b725c62998a3b28caa1f89549230ff275af854a3d04cdb6562f19be7e8a1af31 -dist/2025-09-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=b9588bd0c684a50e0d73717f5ae5c2f0e36a90052126d2c4a539e5a116eeb4e0 -dist/2025-09-16/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=70affff2a14340109f86ec585b65bed16e77612ac7b939336245cc15f7f6c300 -dist/2025-09-16/rust-std-beta-x86_64-linux-android.tar.gz=fb9fc9bbfef414092ad1082d7529fa2efc52adc849a7f45da3d5688d5f6df1d2 -dist/2025-09-16/rust-std-beta-x86_64-linux-android.tar.xz=3fd9b4d89e7ee604f842f7915b90bb02a0c44f8a4694a2d10f94efe7bbf0840c -dist/2025-09-16/rust-std-beta-x86_64-pc-solaris.tar.gz=caa39b90ac5ff710cc76828ca52c784e48518b9c3f1c58cb6f6603a7d05f87b7 -dist/2025-09-16/rust-std-beta-x86_64-pc-solaris.tar.xz=6034b44e5e7bca888027a21d8a4b1229c08fd22b744b83ab817d487aa5e6db56 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=6e7a9aa27a85a09c603fb624ea1cc56120ccbf5b4fed1be8d0097232cd1bf849 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=00f6c500331f2f75ba9c56f896db1420c353e8c0fae450da6b5806794cd58fc7 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=9279908bfa629467d619143e5e0abbcec7a843dddd0f6737994f636edb171e90 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=f1eca139e01d2a8a2627c064f3cc14d7a2016c50738fdc19d3d586f225066f79 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=1fdcf7de3772c24733474e5c0f3e64b56ca627e5a235b890ba0efa2265648d79 -dist/2025-09-16/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=23f9e2447316fda77b7a5af90c160c89d9f5ed735c7d5715cc2850b92fd1cfe6 -dist/2025-09-16/rust-std-beta-x86_64-unknown-freebsd.tar.gz=8dbdbe296c35e64170b9d1e7361a90aa260e456ea7ae4bd969db1dbcad976532 -dist/2025-09-16/rust-std-beta-x86_64-unknown-freebsd.tar.xz=9469e49e425349514f2bd224ccc64903c163bb481a425e01122bd3bf00ebc90d -dist/2025-09-16/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=6e97622b123772e4deaf91b81d1925fe2d39b87f567b96437c03c16a0982b709 -dist/2025-09-16/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=0affcbb44870daa9410887cea10844ad1f48b4e1aec053274e86e39b42aba360 -dist/2025-09-16/rust-std-beta-x86_64-unknown-illumos.tar.gz=3023abaa7f221946e1e9cd40d4a607e8c57bddf8a250a27e0d58dd95a51ef877 -dist/2025-09-16/rust-std-beta-x86_64-unknown-illumos.tar.xz=1e76ba54bdd6673428efae1407e0e5991115f59885159e68e9d63cdfda9ca7dc -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=92db1c0d785820c128bf4ad05b567b17871d2f01ef902052a90839e3fe744979 -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=233d981cbd309a03b16c5a80037faf992c47548cedf5ab4593db41554ffb8525 -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=fe3fd22ad099bae73ffcf1a4881ee2f2c520c6108ac27ca0c64fc5111ec02230 -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=027738f65f61fb77ceff38d9342915ca8344e0a1323e7659a1a5159c99c4a811 -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=e6527497065541fc4701e71efd0a896a8048b653454a75f27765e5b7b6ac748d -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=807862fb874b7bee60b2740ed2df2454d8be50b0877d34b7bea796cfda69d583 -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=17259bb2f4bb1183ecb187296ae9afef58aa2f8e816d2764caf48aa3900fd66c -dist/2025-09-16/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=e459cff284cd0ee388ab65c945bfca4c64b32fd268ee66c2cd8abc325580ed12 -dist/2025-09-16/rust-std-beta-x86_64-unknown-netbsd.tar.gz=5a60ff084d1da42324d6956510a68b3b83a47b432b48e2228e58f52dc8c01b69 -dist/2025-09-16/rust-std-beta-x86_64-unknown-netbsd.tar.xz=9d6823b8b1605f748f1d7af5c52bed1dd926a1d5fbd01ea9a8f939f3648b7800 -dist/2025-09-16/rust-std-beta-x86_64-unknown-none.tar.gz=57b0a2838c59feb0808462fc043c9a85a292f0025104dd6de3c5e78d4d71894d -dist/2025-09-16/rust-std-beta-x86_64-unknown-none.tar.xz=e5a5cd9c861b29d11ae110dd4b239d5069dd0aac57202bfa440e15869f5c7e9e -dist/2025-09-16/rust-std-beta-x86_64-unknown-redox.tar.gz=f9cdee694af41422f785126fda566891357295b5fae56268188bbf2978b92089 -dist/2025-09-16/rust-std-beta-x86_64-unknown-redox.tar.xz=8c7668ceb1611dafd9bb9ffa6de9a11e39d049cebeba05e2dfa889e69d94a54c -dist/2025-09-16/rust-std-beta-x86_64-unknown-uefi.tar.gz=33045879d1aebfb17faf93bd471bb4c4ee3b9a787c57704814ab2dd301ac8ba6 -dist/2025-09-16/rust-std-beta-x86_64-unknown-uefi.tar.xz=28018cd9cd16e428790600decff5c7df749fe500861ecd3853895ebe69fb7100 -dist/2025-09-16/cargo-beta-aarch64-apple-darwin.tar.gz=f0642e83a5a6c8654d724e4929c0e58a4c07c330eae58fc4794ab94721b2732c -dist/2025-09-16/cargo-beta-aarch64-apple-darwin.tar.xz=13cd17e3f35cc0214b25b65463b2394f3642ff8acf4e13af20b442b0100556a3 -dist/2025-09-16/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=fa047b7d7ad4ab64b85ca7beef052a66a89c60f976b099364eb3acfd2867c3fc -dist/2025-09-16/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=df3a9254c4f329454dae9428d88f6c3e69ee8a120bf2eb380193eee63620ed69 -dist/2025-09-16/cargo-beta-aarch64-pc-windows-msvc.tar.gz=e5b608ae84d9258bccee0ecbefaefbaf34b989cd656f096692ea84c6f8d78645 -dist/2025-09-16/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8ad0c0d49f7f6ebc5cce4a2b76036c2d0eb8adb38ce11125e2b36a1291b8ebd7 -dist/2025-09-16/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=f454f83f4ffe0095d3285011b3abae11b0331d87d398ff95622e9091ee09826a -dist/2025-09-16/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=29c83085c7d51874e943b429999cf7709c0cdc422b1254a5e587aecd653430b4 -dist/2025-09-16/cargo-beta-aarch64-unknown-linux-musl.tar.gz=8f85db99809ae593abb4806ffced52abf048dfae81891ab68ef4c83f11f03fb2 -dist/2025-09-16/cargo-beta-aarch64-unknown-linux-musl.tar.xz=e5f004172331f658c3027084950360e1d60bd0cf3cca83fa43cf7fc251cefd37 -dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=1aae91a92e1d41e9c53ede795f91e7dccd3dea687d84151e507f4d3af089f15a -dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=369b8686197e4be3883c3225bb9c186b17839552c91117750abf428255df9c8f -dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=b2e9a3c467ca2847f4ef55241b05a4f5151ca2608e05a43e5101c62d9d6a399d -dist/2025-09-16/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=aaf6bfeb90e732627ae98f4b86083b3a902e31a951b98b3b5e94b67ffa6771a8 -dist/2025-09-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=75bcce21bcd655a537b77aeca644f5279ace4f782a97d1e82de3cbe76a7df6ee -dist/2025-09-16/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=287800d221906551a50922caf0637049f3490e17c65d62119c6a26ce48d5ffa8 -dist/2025-09-16/cargo-beta-i686-pc-windows-gnu.tar.gz=89a6059faab9a3e912dc2baae766ed232d38c240c90f503bb2b486225457e8f5 -dist/2025-09-16/cargo-beta-i686-pc-windows-gnu.tar.xz=96e5b7238f543edbcfb16022ec6aa6d3643add1f7b4b0febc3e35ff9d173c075 -dist/2025-09-16/cargo-beta-i686-pc-windows-msvc.tar.gz=39ed55c1619ade6fc49fefa5ba5bfbb67aa34e53d35384a35c37d0681596b9ba -dist/2025-09-16/cargo-beta-i686-pc-windows-msvc.tar.xz=d9ce7d301af311d58d1b4342855b70dfbe0fa8bb365b78bd83822e58a7ce9086 -dist/2025-09-16/cargo-beta-i686-unknown-linux-gnu.tar.gz=2dc0a357f58462c5474cb5c83445bb17d22450056fc77d3a92c844f104e1c96e -dist/2025-09-16/cargo-beta-i686-unknown-linux-gnu.tar.xz=c2e4f00fc345a77da5f13642d6b65a77df553ac0cb596fa34f837d76fac460c8 -dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=e1b5e490a00eecf93d7c591628c8d231eadb8c68104978b623fc16c5369248e8 -dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=c2f91d72d2977168eb12179abd98b4d18f67de4ed455856f7af18a860ff5b1c5 -dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=7fa229d54c917a4872efbc2e9eb9181f5b1133aa44508548e94e4529ab099cd4 -dist/2025-09-16/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=359d7ec4bc7e0eed1c936bff9cee56bc3a132a488499cb83a8e7561222893c66 -dist/2025-09-16/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=fe514bf5afccb535517decb4c3120375eefc36def2190d60f4f0f6d796af1b79 -dist/2025-09-16/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=d3d1307f3f60e9d8ee9f199441185bcb52a7bf5de460302291b178ef282a457e -dist/2025-09-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=e7c77c9baf683994bf180b8906d55a2117f5bff85fec6c602a6f1912c39b2817 -dist/2025-09-16/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=207e6fe0baedb7f19e8a0437e24cfb9b46d4131a141863c93a52d00f1b049d8d -dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=87433380a70642842f7dcf4a4c8614cbc136a18198837e631dce419e99ae71b8 -dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=207106c6e7c129fe19940da029360f8ce42f29468836a094a2b02156121888ed -dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=ad90e19faff850cbb03eb04195943a9f65169d6a7b030422f0310f8c053e61c3 -dist/2025-09-16/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=7abcb3c3cf3710fcf41d67664137bd0c823792a70cbd82004e0cbbef58446f44 -dist/2025-09-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=7acc6031840a56c47dd2d52a6ce169663ffadb108e92743b22a6dd9a7227baa4 -dist/2025-09-16/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=a2ae500b6c44abeb6cbb42a07a37a8e0ded707fdc1e3f4d6159aaec404912f5c -dist/2025-09-16/cargo-beta-s390x-unknown-linux-gnu.tar.gz=3a69ae63bde95a6dd4020395b90e821e4342fa1b45b00d12ea30f3b1c643ef59 -dist/2025-09-16/cargo-beta-s390x-unknown-linux-gnu.tar.xz=231b1b052018ab851c57563d3c3b4a943cc01f99e3ca6795dfb6a1315d2577c8 -dist/2025-09-16/cargo-beta-sparcv9-sun-solaris.tar.gz=41677b7f137d6509bf7e0fa2eaeefd91d03316e566136d37d006fd98a2a4c28d -dist/2025-09-16/cargo-beta-sparcv9-sun-solaris.tar.xz=f5b4057e69c50258c3edf00dd71f47951833ae892b121641d8d3a0bd38991838 -dist/2025-09-16/cargo-beta-x86_64-apple-darwin.tar.gz=edfe3b23fe5824b5ae763871f133cce684ace0999afd38e9a7b2a08f17b12ac0 -dist/2025-09-16/cargo-beta-x86_64-apple-darwin.tar.xz=173ec4d3c129530c33623f2ec6a5fdc5d739ecfd24f7372f3713ea94aeab8eb1 -dist/2025-09-16/cargo-beta-x86_64-pc-solaris.tar.gz=fe0f57ea7eafb5e157a04cd753b4f6b733245fa8e9baddccf581cec0a7ea2ed4 -dist/2025-09-16/cargo-beta-x86_64-pc-solaris.tar.xz=61ac8a524964f2179c8195d821382597bc8641eace9ba1c27e81453ab8c347e0 -dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnu.tar.gz=44200f95def8558a8b7b85c11533841786d3fd17331e13056dd7ce25de667b2c -dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnu.tar.xz=7144031f2f69bb3bba08cca81e15dc557424c096f9555678b1bd1dd5f4891360 -dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=a7a9c76ec0cb87a725c44336cad0182cbf2c1e06d19cbfa0311501541c08c852 -dist/2025-09-16/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=0b66de9c68f0ec42a410a898468dd67f147284911803207053a01fb2d29b65d7 -dist/2025-09-16/cargo-beta-x86_64-pc-windows-msvc.tar.gz=de26ef4d9091775cceb21af53cb1177922f8eb93763c0e333e59205dcb05ffa5 -dist/2025-09-16/cargo-beta-x86_64-pc-windows-msvc.tar.xz=e6823ffc56d1136d02384acd09e73b6e45ee197c2126b49aa95df832704b9d24 -dist/2025-09-16/cargo-beta-x86_64-unknown-freebsd.tar.gz=dd0656bae2fbf483ebe641ed952499f0127897b09fe14273046cc8e0c7611825 -dist/2025-09-16/cargo-beta-x86_64-unknown-freebsd.tar.xz=6c8b65ac66bf730f9c5bb7caffc75ab1912439d033130438d98ebdaa1a2b922a -dist/2025-09-16/cargo-beta-x86_64-unknown-illumos.tar.gz=5c3f38613b4d2f26643bab1a6db5b769f58878e47168dc92bc2c7b2fe9559ae1 -dist/2025-09-16/cargo-beta-x86_64-unknown-illumos.tar.xz=046ee0c80efe70375179c95461af5724cb00eb9ecc1d995e4a629d316d853686 -dist/2025-09-16/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=b6da1a94fa5718c5a1be4d67d6422d28e62365a433d82f11fe7f09149690e78e -dist/2025-09-16/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=5b8aeabb11e88e4cb02c766c11c0d3d826ded4d08874a11127d8f73f033b0072 -dist/2025-09-16/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00f191b30c29d46e503bfdc49c112ac5295bb67caa091333b0caf210e08d3f01 -dist/2025-09-16/cargo-beta-x86_64-unknown-linux-musl.tar.xz=750060cc199fac6990597a9859234392f4c0a5405d87d1234fc7990032b4c138 -dist/2025-09-16/cargo-beta-x86_64-unknown-netbsd.tar.gz=12513081e2bd88c666881e77e3c4935c710cd6132d9ec48cf9049ac7ece5dd9f -dist/2025-09-16/cargo-beta-x86_64-unknown-netbsd.tar.xz=b1338ed261e33b0fa3e8a63c8930835d87d352ec10011bd4d626c44fa0b0392b -dist/2025-09-16/clippy-beta-aarch64-apple-darwin.tar.gz=668e7fb88b52ad92634fc4d39885843b4893fbb9f34062e8c4fa870f0e71fbbe -dist/2025-09-16/clippy-beta-aarch64-apple-darwin.tar.xz=a0fbf1903d1a95c6ca98ce98a3e639110022480d56c20e175e4fadf211baadda -dist/2025-09-16/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=6593c10385d78ba68b38b8815e5c7aead991d83d9f689a42f4a2911a5f7f0450 -dist/2025-09-16/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=856303f96ed6bd1be89295dffccfc944cd70ce3d1921afc9366f19c6ac800b60 -dist/2025-09-16/clippy-beta-aarch64-pc-windows-msvc.tar.gz=e60f30cba9fe154e7446cf5b7114e7f8c153937eb58cca4cb24dad1b8dd453af -dist/2025-09-16/clippy-beta-aarch64-pc-windows-msvc.tar.xz=24ae9f98df0f2320271b8250234f571b64a4b5ce983a083f45966e58f39b1c94 -dist/2025-09-16/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=aeaf3ed45a8feda550b2043fcbc55ca9fa3eb95141dfecabb794fa9003d76a3b -dist/2025-09-16/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=3187bb767e36aee12059f1d2b77697aa57f71a3c478930c4901dfcd25d414369 -dist/2025-09-16/clippy-beta-aarch64-unknown-linux-musl.tar.gz=c2c23a91b2cccd4978fe612f22c33773833c87719259bd0d501e5a2523f3c689 -dist/2025-09-16/clippy-beta-aarch64-unknown-linux-musl.tar.xz=b7902a5d4dafd1301fb573148b6d1164b9365e976a9019151b66aa93b88e93bf -dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=69e95f21ef2f59df25ee56c2dc10ed5306ca5b41299acea22d2d87d967d17575 -dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=24343efbed86314a6c292659ee0625cdc30bd655eec8009d8e2209a659dcda12 -dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=404b0db1d121ad8fb1a43ecadaa84a79f976a68dbf088ed47fb31245e293445e -dist/2025-09-16/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=f4fbf3a39e1b5d61a481109da644e44e58371c00a3224b187dfbe39827615a33 -dist/2025-09-16/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=fabfcb98b0d9d69e5d022e40ab572d2e84c604dc8d4ba2c88d44501c2a7390ff -dist/2025-09-16/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=8c289d02256ff36412231b320c723becc8d83d5acf9c2325541367eb66f6443a -dist/2025-09-16/clippy-beta-i686-pc-windows-gnu.tar.gz=13838c1fa366173219023000810ba180899b843f7d5c54ffb415c7a517f5af80 -dist/2025-09-16/clippy-beta-i686-pc-windows-gnu.tar.xz=a86b22e78175f89ff2b4dd40b9fbe91b4447914b226d7ef7d020903ed2c9581f -dist/2025-09-16/clippy-beta-i686-pc-windows-msvc.tar.gz=fc2a9397912c6651e04dca0475dc74fcb9a50f370a0ef7f9c7987158dfc58d55 -dist/2025-09-16/clippy-beta-i686-pc-windows-msvc.tar.xz=bf4be32251bac244540759795afe760be13a134580cae8e3fd5956d8ed45b254 -dist/2025-09-16/clippy-beta-i686-unknown-linux-gnu.tar.gz=10580cdb4078d6a27e511ef71ed1a50f67202c1ba145fe315b63f2786ecf6428 -dist/2025-09-16/clippy-beta-i686-unknown-linux-gnu.tar.xz=5ef51556bc3b002a97e7b9f092ce280ee3b5c4a6b02a8d382d87a3f56d90eb04 -dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=34756f99178d5be61df2375f4161aacfb05fbe4d38e9259bb7a01f71e842d67d -dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=1d10a5f1ac3bb2bbd84c421cdd1978865fccd214c08a341c7b6527c6674205bb -dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=c0fc0dcc1a78960b53de22703e7764bb64bf35762127a8f272b45e95e64c7bc1 -dist/2025-09-16/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f41d1ac85d5714c6fbab9986ced2c80bafdf8251f37f16a5a9da994356b5912e -dist/2025-09-16/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=6f2cae468cc556a4083771c6e3e610f759cad00b7af7255db32d461d6e4f3dcd -dist/2025-09-16/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=6df81ef270b67457b96ae04da2801c2a80f9604df9c902e74140ab4b154a10ab -dist/2025-09-16/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=fa4b89d3144ae42ac8c69f85f7b63f46cbbaefa1c3063f719a75dbf8e3ec39b2 -dist/2025-09-16/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=944976f337f4c27176ac614abc918a2bb037d30c554ba5e92e180d7247089cb9 -dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=30da372a7d750fc5e8509cd2265522b7d3d24ab8c37af24076fd0c6f48d47ea4 -dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=dfc5382049b525b461b5bd343f214f357bd3cf1a66d4d226658538639f4ca85a -dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=f5f500c286fc90f4b7808d45a77beaecd7ae3d5c99522dbc80f09132f078fbe3 -dist/2025-09-16/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=5a5da7891fae2f8fd1fba6a537cb3f26cf0aa73f0e36d01181fa20a82be3536c -dist/2025-09-16/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=538b09d45dbcfed24f521a29f5107a1b39efd8c3217991c21eb6c55603ab267c -dist/2025-09-16/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e95cc43b991ab4d0f16c593171231bc134538f64ca40ddcdcbf5d2b73bce3307 -dist/2025-09-16/clippy-beta-s390x-unknown-linux-gnu.tar.gz=37b1903fc1e58f57574a2a6ad23014443d72d6e8aec35df0168028acc813c8ba -dist/2025-09-16/clippy-beta-s390x-unknown-linux-gnu.tar.xz=04d65883b79cda42a26c0581349fbeb7023a25bb73db2e525483fc4895386e97 -dist/2025-09-16/clippy-beta-sparcv9-sun-solaris.tar.gz=057cb0d5ba11a7679a17d87304d1301cf583c86ad2faa23fc449d3cedf0ea1be -dist/2025-09-16/clippy-beta-sparcv9-sun-solaris.tar.xz=8cf1abf779a8a5a18561f643a8fff9863909be7c3f8bc84be2d817fc262a1215 -dist/2025-09-16/clippy-beta-x86_64-apple-darwin.tar.gz=a1301c459894d6d9837b98ec8af238b26c401b860a78d458e34c3d747a8b5de3 -dist/2025-09-16/clippy-beta-x86_64-apple-darwin.tar.xz=af863a3fcae2193f8cc26d9b62854bcba6e029b0bef0f2151321bbabfc931c3a -dist/2025-09-16/clippy-beta-x86_64-pc-solaris.tar.gz=5a3176859e8f783d8bf687d578100dabdd8196e52290a9de6b6902463b4f193e -dist/2025-09-16/clippy-beta-x86_64-pc-solaris.tar.xz=93e37f354b89c94434c3c294cc54522ed503687ef62bb70a146196262993ce1c -dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnu.tar.gz=6403ea6cc8c3c3f83f29d894153ba3bc956b19fc213c11ed13d1117620fa543b -dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnu.tar.xz=a9ed248496eacebd88e33715b30253d9d2730087cff24427b34cf07b2eb89a1f -dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=5a72c9e26e4d59d013243d0d2416fe5280f2eb915f760470b4501731d8e8e05e -dist/2025-09-16/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=078dd02a254accc28ee8b26a5e4b3349f013c629bd1da49948f0071184727ab9 -dist/2025-09-16/clippy-beta-x86_64-pc-windows-msvc.tar.gz=288ff79cc4cc4aec96d6ecd92c733e18aca2c846c87359e77d825cf57817c1e0 -dist/2025-09-16/clippy-beta-x86_64-pc-windows-msvc.tar.xz=fbc1421027dc77265be5d106d6db139a6a33b4e5ade0b1eba17e17a4ea59483f -dist/2025-09-16/clippy-beta-x86_64-unknown-freebsd.tar.gz=1fc82034c6b8b38d60788ea3addaeea8ef4448d467def0a92bea750d060c4d39 -dist/2025-09-16/clippy-beta-x86_64-unknown-freebsd.tar.xz=3a3b7d4f98df124bc7c73ae46f0c776320c1a92c0d1dd7d7caa0d138e7068a3f -dist/2025-09-16/clippy-beta-x86_64-unknown-illumos.tar.gz=f02880e995ed24f200b5c1711f2951e7eaeecc4ab144e50d866f11959e8fbeec -dist/2025-09-16/clippy-beta-x86_64-unknown-illumos.tar.xz=a99652b13a6c3570bcdc41638a59b6d68b76562000ceb60a57128ee5065778f1 -dist/2025-09-16/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=657275ab960c8c65b55b22bdbff5040440a039c9631017645a37506771f3d443 -dist/2025-09-16/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=4ababcc7ffc0976218e62bd55666ff06e01350ecc790ae06effb2767521e169c -dist/2025-09-16/clippy-beta-x86_64-unknown-linux-musl.tar.gz=5c454d363e6f8615aaf4d93e39306972e65a544f3a973c034333022aee321f33 -dist/2025-09-16/clippy-beta-x86_64-unknown-linux-musl.tar.xz=327cb34aff228c3fbc3efb389ddab0b50e5e135145602a8f9e5227fb70a462a8 -dist/2025-09-16/clippy-beta-x86_64-unknown-netbsd.tar.gz=87426803e7fc0bebdec6ae46f8ce536d947bdc57294e592599cb54d9d98d3d50 -dist/2025-09-16/clippy-beta-x86_64-unknown-netbsd.tar.xz=021d69fe47201dc89f394d084b70491d15718b24ceeba56e7cda18e3572f0309 -dist/2025-09-16/rustfmt-nightly-aarch64-apple-darwin.tar.gz=fa289216a17ce0b4fce43862f80087e4bcdaae7b20eac1f3776488b3986db45c -dist/2025-09-16/rustfmt-nightly-aarch64-apple-darwin.tar.xz=1dade784b9caf54bc3ec5c9021d7c4ed1307f11f71d12af46961926a4ad6f7d4 -dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=0f221f2e4d5bece40307c4f7b095dd377ffadce916750c27bd7a2d5663eb6b37 -dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=3d7cdda977ddd4a49f27a2fcf9e0027ce9aebcc5f250e25c3788b6bb5169e8b0 -dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=28a44723d3c4da225592786db74f58af4af952b13112469910b5a2f58a7eb20f -dist/2025-09-16/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=7b4b9f2804488f90bdc9b4f5ac19aaaa9b82cff02c86b95aa0b7df0c805502b5 -dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=df6b42adce548127a2a549bc7b6e574de86c22533641c5bc725c1d5ad62af651 -dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=07d680aa64743ec6e8c417ff14747567fa6056738d6ed8c06db2c63c544f5201 -dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=66262bcc6e4fdffef1e9966bedaae64f27169980987425323fbf3a73ad46792d -dist/2025-09-16/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f8125405f6437be0357eb594fc74842d6995e113b2475fd8fef6f778dddba539 -dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=bcf9fdad0b5209b1e12fd81a18927698f468995e708dd56e8212f977d4ac39a8 -dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=f7a7289e5f48ecf9ddbb214e6ab47280789a14065960f40a92d8dde3e1df57b4 -dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=e463b2bd6236463c68b2d0377bb33adff0daf17fc47dfe8f0857043b793a847d -dist/2025-09-16/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=96c15e4bbfb17be75003ada804b2da5bd750889c783e110a5a3481f045ecbfc7 -dist/2025-09-16/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=6e53b146000b91f569aa5807e69dca726068d2c23e4a44c344592ef7a96927ec -dist/2025-09-16/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=a59f630b27fb33d188ba0dfcd3563a69bced49dfbc0fc1545b0c750bed41506f -dist/2025-09-16/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=ab6b4c2728dc0381f92af8b9f9c730507709e40ca7da89700bfca9b7adb93034 -dist/2025-09-16/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=71950a1d4c6b04868cec2fcdd7c80bbdc675ed5c25917c774e3b6445bdff21c3 -dist/2025-09-16/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=fd25c154f34b662d69a6d5cace59ebd605a1c4085a14ff8b8d597f5cb7324e95 -dist/2025-09-16/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=15a2a897028e11992d2cae90d2a00f730a65f8b62ad500ff82c2fa83767b866e -dist/2025-09-16/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=9516f97a5807b07d37e95a258b9cd60305c2b0429911c2425716e7f77a556eb2 -dist/2025-09-16/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=f665d43854449cb4ade4c518671ac5fef4a9640d276ff7d90c51c1bed08f9909 -dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5de565b08f2641f3a7b58f79f5c63905859d39573f105ba05addcd4db5cb30de -dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=0f3d7e4b91b6cab8ec9c534ae0f82ba79c57d621f25baa2b408bd2844edbc017 -dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=7a33a965a41fd3958df003506da405a42cd459bc8689aea530b4a66122eccd3f -dist/2025-09-16/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=b38a0cd88bec44e60b52e414237f50352900afb66e3f2b829acf92de5c060e3c -dist/2025-09-16/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=64cc62b309d4be3b004356637d726776c6765cee590cb0ca244e2bc3feb6368a -dist/2025-09-16/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=bf873d8101d8f2f3574387011749b3375298c7a828ba1ebed91536adf50be1be -dist/2025-09-16/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=3fba5ef7cdf564801de103e7724ac0d9096cdfd8340c75df09bc0ddc1e71a74f -dist/2025-09-16/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=c5a8af0f0689aabd52a337eb11a601877cd9f74efa2734d872f2752413551aea -dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=4f1d6e182fbe1fc1a87949651e64a7f6896c3b359b7937b02d2c02b8e9db952e -dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=29f7583b6f0af1239194c8d936a9f7e38f58920f6a4888d26ea1a48ab8c72235 -dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=f937a74b730cc1d064e0b4be538fa5bd51f636f8a5979367cff3a611d7893f45 -dist/2025-09-16/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=d208b1998db3a896ea9c7c79ded0ad6ca4de452d3b6e696ffeeca44fe9fbc58b -dist/2025-09-16/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=6816dc3cdd53c883a7cad8e7237c1e22264dfdf6e1a8033b41887a52cd43a8bc -dist/2025-09-16/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=904b26d880f6b364458e9d0f682cab3a136b3498f27c913d6f422de6fa822e60 -dist/2025-09-16/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=373a93410cc2fae30b952b036487417ec9e6211cd2e1980e60352329444a4376 -dist/2025-09-16/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=8e1e328f2312cf458f8d7288624c11cc5f39bd7c8feef62147216689a5c28a13 -dist/2025-09-16/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=8f22b6753dcad78a46cdc98251b27672bfa94f2ee11a655705fd7fa8a469ae82 -dist/2025-09-16/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=b719b7167321d4be13eaea674f713269c35e4d34dcecaca38e32cb72aa8632c4 -dist/2025-09-16/rustfmt-nightly-x86_64-apple-darwin.tar.gz=63006d28e754c6e6afc5cea25527d4ea628ba084f0af52a36b676faf73f22e07 -dist/2025-09-16/rustfmt-nightly-x86_64-apple-darwin.tar.xz=b74a4e9726b5acf7133511b855088aa3ca9eaf5e5cd73a6d3b054e8a263ed6f1 -dist/2025-09-16/rustfmt-nightly-x86_64-pc-solaris.tar.gz=a3625dc34b971fd11e3d2f895a4933f4ec6b1e01475385cfd02e4eded528a99f -dist/2025-09-16/rustfmt-nightly-x86_64-pc-solaris.tar.xz=1309352fa233debe6b1a06664da7f8d6db9e8b18afb60ca5709ca6a5ec657198 -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=b765f3a632f74d7624ad10afb1875716b836dd6e5836736fbed6ce5fe7b00594 -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=b74f1b6e563790926629952d25199eed14fa15e94845c962c79ac56df64cd18e -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=365e182e871e46e9f54b2265996c4531ae44b5f93a2208a5debcff5367026692 -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=34712b98cd806caf8507b3afb292cd7bbf41599a395847336f617a9c952f911a -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=d04e6573a9253d4c5bf512f7b65415f08389c499d0024ac3990110ec1859b24e -dist/2025-09-16/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=98de7fe5863ce17a6f3c35ef9baff92124c5a398a008d80394a1ddc61fd29390 -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=01f052f3ec99702f7747610c3a5fd0a440a7a38bc5f4da93be9e6db48b599f3e -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=38dcd9d9fedce55d75ea7151937cbdc4f6f76d92eb8039840e520faaa870182f -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=0341b4b7e5287aecafb3097334eeff773c83d5267c3a1c6edcea6c6ae1ee29fd -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=42ac68f632ca2d78b9b4647bde709eab84765f4376722ecb560d099cde89c7f8 -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=af7491f1d5fee8a52768397966b75ca4104400e7023f373dd8b188aab4ae1b35 -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=38cae1811a0e18ddaf094d3931d8d532c5eaba03fa2cc1149380ff9393e8f84a -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=631cf4d825237406f2992f44f26086672886b61fac0d7ff7a4991b25ec756ebb -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=ee52ab0c86918b2a155098cac489f5e639c0abd7064539d0e8a6a7502ca33c54 -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=67de842ff1f8cf99b0ad88ecefc17fa36359fa718e3fc04f243ad8c1595987bd -dist/2025-09-16/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=349480a812b9861112e80ab86d3e80318d239af5212b314b3a7299dbbaffbf8e -dist/2025-09-16/rustc-nightly-aarch64-apple-darwin.tar.gz=fe1ffcb90bdca92a61470c4f7cdf7bcdb4e7bf7c685ac0b92eb3a22509d88963 -dist/2025-09-16/rustc-nightly-aarch64-apple-darwin.tar.xz=b55d2837dcd2bdfbe8444e29d0f36ea584451c4f0b7fb7e9bcd77279e8cd820c -dist/2025-09-16/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=c303271dfc8ccd2c997e5ad88e2c3fbab6b9a188331217dbd46a6d96a53852ff -dist/2025-09-16/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=0d82ddfbeaf9380773bc91f294651609bc928cf53ce95fa89fc4a0f04e54ac67 -dist/2025-09-16/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=6a8a14c5180e4cbd23bf144cf11dec5f47b769a717aeac03546d5cda83b766ab -dist/2025-09-16/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=915239fd57032010740ba9aebea3e018581993d2ae5d2ebab9ca42d73e48077d -dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=932a75ac114cb08c0eef0ef2189b463885a6d64334e25899ff386196ec59fc4e -dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=fcff7229b11ec8925d39830ce62892265f655ff272d9e3a167f102cb0cd8f098 -dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=3ae873418d17f15d46a1de95e945aa1e00d737b688e196d565031947b9dc420d -dist/2025-09-16/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=036eb7c219c6e1c447c5e6ee6d4635dcbcf4c1274c5a14f0dbe5eaee3f175f1b -dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=16484c845c672c775970f0108a8c336a11d2a2e4dd5f76bb5d1b74da1e436484 -dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=9004db0b31113fa8ef0cd44318d0df62e76b8d30ac2a6332f6d483513e4ee7dd -dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=6b3c245279a006b0516df26ca686f56cdf6233740d8c8b18bc19c5aefa84dbad -dist/2025-09-16/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=ecd58877e63d7d209a67ccb5a6e7693af38f2e249ce04001605ac49fcec45edf -dist/2025-09-16/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=d5370d72328bd22b2fc79661061352c99d3288604bd1ed58ae2b798586db5f70 -dist/2025-09-16/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=5b8a6f255601c33bfd215b646b8ff164390e1eb7df69aeaf7be65d97dd9f426d -dist/2025-09-16/rustc-nightly-i686-pc-windows-gnu.tar.gz=74ff396b8dfb28aa91692aced5ffa76f3e270d4c5a2e47b12eda5c4534e92bf3 -dist/2025-09-16/rustc-nightly-i686-pc-windows-gnu.tar.xz=953e50c365d084ffeac61d1279f89943e81b43922c6721f5e55f211d0fc61902 -dist/2025-09-16/rustc-nightly-i686-pc-windows-msvc.tar.gz=c3485374a990da572cab859f6cadbdf252d32e07d550e0f20fcee24be543050c -dist/2025-09-16/rustc-nightly-i686-pc-windows-msvc.tar.xz=ea4afaf63f5b5c92f7feea4b82ae751f6f8bf8f54126d7007bc72d4815352628 -dist/2025-09-16/rustc-nightly-i686-unknown-linux-gnu.tar.gz=0635e9a84313f572d1883841f91bb49c7e7fed9a6dc5db751f00e7b00f140ce2 -dist/2025-09-16/rustc-nightly-i686-unknown-linux-gnu.tar.xz=8904638b6ab37416eedacfcb03c7b87fdcbe1fcd0e3a80e0e5f410c671959d44 -dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=3fab80f207dd5e8f5c276deb11512d55b5e97b3dffe44c1f0249e0c331ce2b68 -dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=95dd7df11dd2b9f27f8fc9e88f37ada794f9e0443cf1291c554f47485eee84dd -dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=a4e7d3c55c7acce10b1f0b59afb9e70d32c651b87a4d1381e945fc07543e474d -dist/2025-09-16/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=f2ca377351093829123525578451c60987c3943be1783e396ab3d5f34e7735cd -dist/2025-09-16/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=b7e5d9c1ecde1b69b17d29a3ac6d15af0e734a7666381f1adefd0bc31ea2c397 -dist/2025-09-16/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=1c18dca6d3ac47b8223ab1e67e94640f402ba8f2ab787b38ba85c49ca8143acb -dist/2025-09-16/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=0850c609f864638538f4a960ba34307045d74d10d462949e9728b2e14cf5eafc -dist/2025-09-16/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=ed4433fd1004935913d5a48faf78bcc4d2517f45e08032995414c69e4ede78ef -dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9f54367ce8c0f2f1cbb29f84e403a8aebf9a3ec7d2675faa744e8c28b2adcd0f -dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=c1ebb094ca29b4fbb30326ae9ef99804d9f6ecee0bcb5633ce0236ea90058a13 -dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=c39f9dd4ad6f7939d114a9204a72cc22cf9a3d97ef3b496eff2bd78f55ff4e1d -dist/2025-09-16/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=cf218f8da409b2cdfe3820db1ce882e5d10f8a24a77b600cee9f00e85e747d13 -dist/2025-09-16/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=b64731d52f06f0b08fcc6dd64e9319d91fde2e48fd71d2b193f32ff770b81357 -dist/2025-09-16/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=07fac144d37f87e5f7b3a9521ef79789d7ab33cd529bb27c1b95238a28602857 -dist/2025-09-16/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=727ca4ef70eb8cae09f73762202aee2b7998bc97c000571223991347a5408712 -dist/2025-09-16/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=787ae447f764bf727c7debf6543b1ec22ebcf463832eb4d1279ec0f6824c2955 -dist/2025-09-16/rustc-nightly-sparcv9-sun-solaris.tar.gz=9f80d6add413e65dc6ab0e3d44b62f24134c6b3ee0bcc604ab66b3fdcd4fa0fe -dist/2025-09-16/rustc-nightly-sparcv9-sun-solaris.tar.xz=3075e68b1f8a7b7a1c9489afdc2c9a38b1f0107865229497b2c9a7215853ef08 -dist/2025-09-16/rustc-nightly-x86_64-apple-darwin.tar.gz=685ffc70ff08c696321ebae272d09ba7f9e62f221929fa703e8cf21ba790df58 -dist/2025-09-16/rustc-nightly-x86_64-apple-darwin.tar.xz=29bd3bbb0f082cebf2dfef6d89a50dc5f33be231fe9d3e5bd2bb9b0b9bf53f90 -dist/2025-09-16/rustc-nightly-x86_64-pc-solaris.tar.gz=720e21f5ece47547b4cd91d5be89d67ce5334fa23a70921e7d60b0642b53a2d2 -dist/2025-09-16/rustc-nightly-x86_64-pc-solaris.tar.xz=d1e4d96e6f390ab2b6b1f435f5be61a69e01555f5bb66d58b2571f363cce8d26 -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=2e1a315af7faa1f67c35e927fd0f3a0c96fecf0da1a2b3269ced7846d99d9100 -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=7cb11ec687244e19a31996a3a802a8d0851cecd444abc5a8e65a10a037f67f4f -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=89010bc8a19cfafa6bc9714dd90cdcbb31cb85362846b8072cb41a3e8e7583ee -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=e84050c777e73941cb28f39e72a992b6a4a63100541f5b3fb288cf91fa1b0bd2 -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=ffd857605275d71bf7e09eff94bc5fbc9cef222b1c076f1b7aee72f980e4c470 -dist/2025-09-16/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=f28f28f07e98cb1bb43e93501cb43bd88b91b9913257f4de5c7154f0f9653d41 -dist/2025-09-16/rustc-nightly-x86_64-unknown-freebsd.tar.gz=66fe447d3f4526514b146633375efd40373dc28fe0262302be75afdf736986c2 -dist/2025-09-16/rustc-nightly-x86_64-unknown-freebsd.tar.xz=4d929f5079cd7a1c878631288765441aed538956d496881c89465aede623d94a -dist/2025-09-16/rustc-nightly-x86_64-unknown-illumos.tar.gz=feed1caa5d31ab01cd4dc3c4b6b893c5d291fca9c470430f83c2cc90d26418b5 -dist/2025-09-16/rustc-nightly-x86_64-unknown-illumos.tar.xz=2f2b4e9e9a42f255cf66565012c63b2b2c0a13309dbce94d5135cd3280a8fc67 -dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=f96e122b71d41b4889b18a0cee173822d509d8be9eaf28a3fec111df1a5dc5be -dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=ee8914df087f4e20c322851f322220e2f4885a316627c464881d086024e84b54 -dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b226b4edc64f4ed91a9cb616600ece61c12f5da72ca4b62f13669e849de7ebe5 -dist/2025-09-16/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=9a3d98e0fec50ab589027f1d5973ec583b062581b1a1cd59470bb4fb6c51c463 -dist/2025-09-16/rustc-nightly-x86_64-unknown-netbsd.tar.gz=bd0d47aaa630abc01d2f36f9c2a99577254aa3428abf1d666d5520c4fa990844 -dist/2025-09-16/rustc-nightly-x86_64-unknown-netbsd.tar.xz=863edf8589fe1f3f1728222ee49960457d9edd2abc521557f28562e546e27b81 +dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.gz=08f8aee2085d8da9041fa9f4c7c6d79b5b1c06c544a3e2309f353844e1250bd0 +dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.xz=a36bed31d0f600ca8e8efc19322fe05a88e31bc218078e79c8ca0e7c3d582b20 +dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=2b6b8f275d1b03ed7bc05e631378c0b462d274b7f1f038f2feec752b29993b10 +dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=13adf0b39c176761adcf754671911d5309cf04348ef9f93fcf8c09afa6b70da0 +dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.gz=568566c82dd296babbd5588d0c69f23c5b5bfd32b3b25e493e6d45f15d645db7 +dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.xz=8357fb4ec176279416cabc0edbb2f7c3d4c812975867c8dd490fd2ee30ed1d1f +dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=a885d01f6f5043bacb3bf4820777e29ab45aac4dbdfed75ee71a3de01b056e05 +dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=3a2bed859214bbea2cdd13675eaf480e62c01646efed26067ba7078e6dd8591f +dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4b66e79a48d172eb674ba7e6b4eea91ebda2351d6d253deef90010ffc48d4801 +dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.xz=131f270aee35b36ae02959abe032c77e1de0c75f23f7c61bbca1e2c18a23f4f9 +dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=d8c38594dfd1ef17c9ceb2ea614be730f4647fa5e75e80b5bc12d235216ecbf4 +dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=1643434757b590b1586e9074e82be3cc9e50e5551212d5f2040fdd8feba8f1e2 +dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=1619461791fa6c2b8750043a41acd285bdf1f32d376af675343be3449bb7e5b8 +dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=cd2ed3ae30cf77b5530a2ebee13daeb1419ceec2ab18f754d07b081dd6a607c1 +dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=b0703e79530bd836df864facbfb5065c3e5e8b3a457e4ef55b4f7a4d362b9ba8 +dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a647780abbe8d36049edd90857b3baab556ac9b61caaef1d98307fe92fc20453 +dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.gz=c7ec1f853b96edbf1a914b8345b025c87641225e0c49507bbffd88f2da05b8f4 +dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.xz=53803baae3061eb164f34900f5867cfdf3bf50733ca0a6bda674b491bc0250b8 +dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.gz=a0f9192059b9989db0c4dba57b5eae9cace1b8e6f8bb2362b028c7f36e34d44c +dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.xz=f8c237af5f0e2fe293671ddfe7fcf90f6e2b161a52314b2eb622f2a1b23ba3fc +dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.gz=da2a42e5a76e95460a348ba70cdf1c5c6ade82eb6ad3796935158bbf5859b602 +dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.xz=c98df2f0156c3065179f50d55dafda8c5db1f2eae99ecb3f568a8861299be289 +dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=1149494d96b4ce949308620a360a365c4304b8ee8f8c9512a35f08048aa13c78 +dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=c906f519bc65a3a7514a62f8920d334bc10623a76dd2d3464af88065b79cb334 +dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3a9dd7ae0179ebb7659024532b9f3cca9ac4cdf62c0ae411b00d8f8768aaa34 +dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=d9f3428d80a7b72b15c62bd3306628820f73b64f48de37ea079699b733bda048 +dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=4b52241a8b65a9a42db2a75e057176a99e3b434907f498c4b6b9da104e138c72 +dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=40f3a5fc7478b40153ab20e3f14a6d838c80dda529481735e898de989a31f963 +dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=f5aa411dfe614ed288351fa4b17d1e2935501c804c0ad51f22e3db71617b17ea +dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=b9efeb2e185e43775d309d083d8c4f45e30e18b7af71b9c45e397af6bc723fcf +dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=38b6a69885e4dac48f7c3128ff1e88d0bf2d0ce1fbd6a5baa9dda62bca0b2b08 +dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=8576ae6d787b0f8b127bb2dbeee213cc6093ba92dc7d5ff08f463d56e2e6ce90 +dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=5e91ce627e900da2606782ae60598843a6ba17593a7eb0dcc8f5f9a1cc20676d +dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=fe24fad781f829838592e6670655dcff52002ae720f987868fd4b17eb9ed631e +dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=170ccaaa94eb7c813bcedf2afb37cb0c696c5f48ca9d93238ee8cf26efc5bafa +dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=db5a862a260fe8688e3b1da1161948eed5361723a296bb27dcc62758eaa2b873 +dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c764aa7b70dacf7ac3ef5d2184d021304b633309b771f24d62375fa64791614f +dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.xz=69eedf71d20924d9729684e27a3a8cebc60efa7c0e7a3f8b6fe664f469a36788 +dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.gz=efb9d78cc395774e05353615c029ed674c1ba55204ae9be3d022abda9f5c6d9c +dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.xz=e8de37de871888886bb58d915f3a27bfd8c30a912ea3f3af4abf52f66708268f +dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.gz=b945ef94a4efdc0fdd4a66c3708cb95a97592c922652af06d8d1b6bbaaf71660 +dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.xz=876a6080177df194c14d0984f112692295a21186b05bd03a77d0a304dec5ad51 +dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.gz=d7c0b4fb19c785ed3a0c16d903cef266438031c3a43b1721d19864a1923d3cb4 +dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.xz=b4a5494890bd92b85f66054523b26e9aae5e74b3177c9eae64740ed7fa1d4da4 +dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.gz=ea55aab0bd57f0cd6568a6e78c9d0a3727fb7cfaf8ada9379084091244b3221b +dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.xz=426009c68fa78001b34f8b329cac7634dd8921c569061f45972058b770206f9f +dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=c79a925f6f2b406db97732e22e1b245ef2c7d1291a574b0d55a861d3c7e5d766 +dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=0f46e118b67656fe16c484589ee0213654cd6edfbe5a29d641aa810bddcc8c62 +dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.gz=d7b5fb269841039af498a6d0be2cbd70cb7b65f6a9918a2b6c022cadfdb30fcd +dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.xz=dfef15ca4fcf06622953296ebec960e446402ce542e2f264c12c0c03b9a476ce +dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.gz=09994a33e03f50212cabee85294dfb684fafcef95e1de5b082540d01d92df1ce +dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.xz=a0e3409ec6f6b02517c8f9d0e00a0627434f6b06a5360da286c46ceab9d12ab1 +dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.gz=01daeea1f1f10d84444b56e8e74e3a451c54e65832234b2caa2ce0a63c0a9ea1 +dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.xz=6299fa81533b9362d1cdbf7984506fcbc26f7d9e857a942f081f5325c87cc4c4 +dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=cafaecb5158fcf39b676baf2d0060fb8b31558be0e442389755ae33a3e7bb42f +dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=5d3c1fceba5285bc54f5a327841ecb8893e719ba874e483c904b903f4dc293ed +dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.gz=290a07f32c769f74d21c57a856b3aa39da89e2f086e53c42f3333d1f9ffb5673 +dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.xz=8bb354230d3da85bb0fc280c3e95ceadd9f7522d231fe787be8c82aa072ad506 +dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.gz=af3c98fb99b419cfe50433f5f4a046065066183b248708ec8800253867c678df +dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.xz=0ea09297621d3b735b2931f6472f95e1587d38f6fb0df7fdf5e427fa3baec4a1 +dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.gz=8c08542fe69e9fd5b2256d17d84427ac206c9e79e265fddbcdf12d1af4e5d913 +dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.xz=7ddd43d1e32a829ffa9a7a798e1339d0569e773d841d8b7ad33701664373b8ae +dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.gz=bf3df6d2eb7e5515ae86bb970b5c145140f8e9d503e636fcfc435d47797b650a +dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.xz=fbb88375a8c0c5e41d35e4838ecbd31e4ad1b96e22eb689ae37dd50322545d39 +dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=26e9fb3607dfeab90500bac3e9eaa23170f7f22a4738ae6b58e2e89e0c87f72a +dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=6c9622771203bf342d59673bb1f53fe715b4255f0860feb6b19be57de2ef9f92 +dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.gz=a9c15e05b58adede5d08d7628de75d47d5c38ca60fad87dca8b8c9801050ee1a +dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.xz=bd847e7952c02312e36900766a71a5284c221b177ddef0b9cb071c5f6186a70b +dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.gz=2dbfa47893553b2868c375bedda6c4e08c33bbfa9cc96ff6e89ccf0525f8b14b +dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.xz=6b83da57cd768bad91a820d698bd18ae60586b0920950ea14105d6f23b4b1db8 +dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a71a57f26812c2e1529c10e2e02b8d9b466564065a8a10ceb69f22cb76e83814 +dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=29f8789707c545e45680acd30a329fa28613dd247ce7c91d65b13a10c0c21202 +dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=07067546648ac6e784f9d5f6455534b62b9eb5cd86805c327b98505a0caeb2d8 +dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f224f6b979ceef56ef8a10eaf063a6ea072d405a52ef123b720d44925b530d36 +dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=756534ef3e62c80481e4886348bc80632ca68ec9c49045d71838dc7ef0751373 +dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=c6eee692a79106d7733c1cbc525b241b6d88a53ee08242e494d286eb0ad3024a +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=4843b5a6d3e8b89a54ab91e44768bb023178c8cc7cd745639d9a616f2331d9a2 +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=89a808aade0a91043bef23f3e3f38d193b4f02b6556f01cbaf103c43ce428478 +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=6c09b424925e89957fb1921887b7034c3d3adf012571415b9930e1d0119bed41 +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=3c34d71b74adb145302772db2a5c565235576a14c42eca0a270b0e9e67ac9032 +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=70225984fa7ad361126efd9cbd40fe9dcf4756866b23079e4dbde5ec51f3a10d +dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=e696cf9ac5b4b0e16e3947377424515c761697541351d0924b61a37557394828 +dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.gz=7b754105300a911c24f7483b7eb482d076f5f98e16f685215d06df3dab1fdcba +dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.xz=8168916ec457eaeb32ad1d274ce67666d6ff8fdf662f32bc6e17656ef4ff7c81 +dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=1ff511547185b42b801ce51f84985767d580c08f183b15033e8ae05274b7f90c +dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=263e10d4226c5328cb41299466b82e154fa1c94c67fc3a185a0bb9a6639bebad +dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.gz=eb3710b6ccbde9a265217a4e64f2c62bb22bcc79dd58a48381cc81c5e95073d4 +dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.xz=b1c231790f55fd9a3dfcb9e6c946f34afb3bf96c57bb9d8615894d81aed44f95 +dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.gz=0d12ed3a2980fce0d71d728d6c2840eac36a3e3ae93f2dfc3cb391d56c20cbf1 +dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.xz=2219966a5e884a94c324b74872a2a4a12378d595cae10b53958190acc05ccd45 +dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=286c12975e333cdf9c7ad0b21217e3b83682047c37c1dba766cff4a201bab40b +dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=9e56db5ac01ae18077551117348fe56050426f521e41f217ac3d71c23eff4d88 +dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=f52e699638e352d9f816a21965a5696acc5fd77325ff074f93c27587292bca19 +dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=d0a4abaa489bfc6f2f7d2305e8edbd502b12f247357ba4cda541786377648108 +dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=7ee043969e94b14ea74e083fd3edb9e0639d68c2bdd7ebdb188e98b36c854fcb +dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=8ce6bafaae0e8217bdb138d104955ce7f0a747ef915aebb181cf3047beb4456f +dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=8e5c901df3f932bac7dad635bc1197ffbee4884c0a101632d51a32f23c875cdb +dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=166a1d949b6847e9bf102a89f9a417a30d8ac25a35fe3f732d6a513a7674af85 +dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=8660de6d0d97fdffe3bbcfd5ffc7e11bbfe9c43f80067ba17845414958778845 +dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=8b563eb032535c58c487d4ad992a12a106208861e45ea78c342e940b9356ebf1 +dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.gz=cd761b3f761198cc6ac64809eaa28ac299b67ba48d964298db3f5b4ea52f3623 +dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.xz=071864464c52c37bd102fad26b5d28f31aa9e06d34ee868a33ead297c3e20a4d +dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.gz=402c044cdaad16d2b60365b6894250aa43424902c0b3f0526e849d7d0d452315 +dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.xz=0028e17d0164bbb8166ddaad815874123fcc326dffef4740389ff2cb069a3e2b +dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=0b9be6bfa168756361aa5feb7802133c4cbebd3fd20d75d32a4385b716417a9f +dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=1893fcd9b16f0c334257cbc78dc416cc048d7c1603ba632ed7300bbf6c0bffb0 +dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=5aa03609f57d6c959673963b633adf194ea240b3604ba6635a6ef5fbe5c519d3 +dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=8f075eb3b1ed0bdfde8af08ee69778af2d2e896d1cdf17035657d1a84c85e856 +dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.gz=1499f0b4c3a4838dbd7b0df7303fbe7e157dfaec396b5ee1a6ae6a727ea3122a +dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.xz=f0ad36dd56abf6c03395bfc246209bce90aba1887dee81a2841f7e1013f93850 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=4a430fa04ef3d23dcf1d5e1f69c37127a5fb58e883ac52c8885125e0f578cde9 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=6fab12ecab36252aa1a4f6aa523ae1546f534548394e2585e96a869b87656806 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=4081b51910cb95fbacafc9518ee5891e1131af79a8348635c13765706c18c3ea +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=ed9a56e0e8b4e0f639afd9c6c75c4adfeddc7ce0aaa9132591f774754f412b6e +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=571a08bf8eaa522017b0aa67fb78b344590fde57ab3425575c01ceb3b258c557 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=e50728c440ae8fc9d154a3893914126d4486ca7dd197891b78531f7d5d081211 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=1f8570de307fbc59e962ef6b419009d57fb05b2e1d5fc9ade9d425e3c9977cfe +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=35db980cea1ba70003374a738f20af63d54796e9181b8cf0e9d0626e0935a9a2 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=ba5a8487dbb60851fc927dc24ee58186aa6e74d42dbf5202df7981a456b5f8f7 +dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=f763ae3e33f4785ff505eb068ed6515aff8ffcdb9895595d23c2cea519e26355 +dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.gz=3cd90f1a7c14a732a951026458a976fd5e833f212c6f6433f8de348b7b742b9c +dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.xz=237f44f2b9984743f71ef0cab8d693092748fd2da25cabd3468e3e45ca20e2bc +dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.gz=ec38043fd7877d45331414d059d0198d055ab724e84c077ca75a2902afbb2d6b +dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.xz=f511909286f3e1cb52f0e698722bec1a3cfb750e19bb2fa781bfff225620ca8c +dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.gz=556365cb3ed473222e1b135be77086214f3f94f863817de4a87ee7d75456b824 +dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.xz=8483d2550782e253cdace51fe24249fbd6bd0b10a850c75e62dc60f803be17b0 +dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.gz=0ed5faa9e8e73f4e7b9e75741d000954558bafeaf776a6e61a4e44ac120b91e9 +dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.xz=665d5a0debd829f3682572e4c3578d41bec58b01df10cc8c71ca66d326a3579f +dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.gz=c59dcbce2435a5826161d4319dcf84e128f9fa4c0bf075fab2a26c2bfb5d9887 +dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.xz=13a2292936e289941be4a02903051eadb076bb44368494d530cf66832978f46f +dist/2025-09-21/rust-std-beta-i686-linux-android.tar.gz=5d23e660218e04a7dc4aaf940959619ec9aa14bf5574a554c0d8f377910ed017 +dist/2025-09-21/rust-std-beta-i686-linux-android.tar.xz=cffd08cc85df3cc661d8a572e940316da06754b61893efcd9ad3b7db09a0e6ee +dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.gz=91743434207475f4404707cf7a203b46f032a041184a729ddcaeca280b2fac05 +dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.xz=1f0240a71bf5a3bd74e1ae960c1aae440c3b3e32e6c62835287f78cc777f0d7f +dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=ec5907cfb6faafcc20f3d7cdb22fd7836c9c2d7cb4871c48e64732bb7f5dcba5 +dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=e7e8453b9dafc3c8c222455f5327fc8cde127f8dc877991688afd3c2f23675f5 +dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.gz=50dd40b16e8ea85fd7ca67583d5cae80910d36531a7babe13a94cb638015a1d3 +dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.xz=dafeb013333acc8a3a4181358584851b47c5f21138d8164ccfd6863b171309ba +dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.gz=91d741bfd158f22f4dea8bf768c5fb60ca05f5dc64cd5a848428b8dfe8beccbf +dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.xz=12ddbbb201a973148979a99ccbac3c65690010dd2f6984fa390fe5e63a28dbda +dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.gz=975e30f37f03afb47777a38edcd535df6729311cc0acb587d417ebff694df796 +dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.xz=bc95dd6129e90c9275e0340962993de7a0842040bdfcde9aa419f227d79dbf31 +dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.gz=1c937cce8b40567851578790512fe079c0aa828374a3bb76423d685357388576 +dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.xz=b42d227d63f0b3352d4d66f1198294c2f4df574c48fff794ac3483cef869c2bf +dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.gz=0e8c239ce3b8701c4a26b46aca9a700083667ffc3228d796ba0ba6d0728c6826 +dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.xz=54cba2405dfa2a23164bb8e7de5e0d6a6a6523f36b0763f077d2bfec1f303576 +dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=72db70ab9289bce8ace5da246432d2a00552b4cd9ebef7930b563e04d1cdebf1 +dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=5b578548a62dfd3902920719acd17550f45d0e9106049cbdc1f36c8907a8291f +dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=993fdc6d1894f823b3782fe180ac40a3ad7baba110f2eff68d9e38e8f79a95a4 +dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=b5161bd0064bfb312cf156ec4689a3f5922c7df24468660e1046798c8984938c +dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.gz=670ef40754ac30a2edb65384de65f028a4f8e96dca49fd0bb5eb2d9d6020e906 +dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.xz=b9aa6311d6a3e428f151fc6720147ea8759092545b05cad3f16b6e563d523813 +dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=5c4c2e6bdc6d3c79578a3fd581064ba6aeb21fd9311a39a62bf58b36e7ea00cc +dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8e272682e98ff8b139da621d7273cf71efa407538ea176d873a1ea7e22246ebd +dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=0781275b356176417c21c1bd1a4068fe2a42dc6de9b34695c937d5ba94b98ad6 +dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=8747e3e686fbf41389a8ad958596577670f0626a610d380b0a775e704bc6c6be +dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=95e8443355571edf645d75d31a33277f0d6f7161f8592ec213a407bc4839819c +dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=4abcda8b23d17f6e6681329b54215f37cca5fc1f3383e58dd60c38220f5528de +dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=a24d3b7db647c114c95f7da40ca2001085d935ebffcc17e269af5be636ec1f2a +dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=7579f587df01fb55211e6a0a61ed96f14955b7f56990e679715157b06b49fe79 +dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=ea071da90747334a786f1e4784e39c11058d7f7719e498a8b6ae29672a999abb +dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d612ed01011c1e7f24b08318029523f6b7ffb12ec38b1f41ebcedf463f924430 +dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=722b93d6c5e1f9a326461bb920fafef62cc8257ff67732c3f65ecc540782a504 +dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=5b5010f550b317facbd599fa363d633e0540836145717f35ffa0bff14ec80558 +dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=7dea77dc10830754d5aa9a6e5ae3272e4955cab8df1e20f0784901ca6a60c49d +dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=f212b4afaaa954809af920d3fb3de76a611d387910e6162b902fad8f38f36c49 +dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=3f81a7134f44a87b7724a510e4cd4209ab52fb03fee3dc051c26bc0612e4b1af +dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=cd9db852c6f7e454e94161379c032e3ccabfcdaeddd74e8f612870ef39eb230f +dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=6da7d7c9cdc05fc3b86930d98fe9828ecef02b5b3cead51252fe9f131ab5f9e2 +dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=97ad71f7f63f2c3b01ba822164df457d88331880bd21837a18354fffd1b38918 +dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=9a5d94e1a77159a4bbf4fe7490019fff763daeb24dc2b8c732442275619f9ffd +dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=dc5826fef922a6987650b491957b17693c49d1ab26b618efacbb1bb0b5a9b1bc +dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=1b9c1cc0648fc86fdaaf23e6793fa826f3639bab9d42e1bbe2c70f19cecc11a8 +dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=90cb9c376894a122f3872a77a653e3decf95f1eef54ba7980846165e6f34377f +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=22069b14b3eab5f3bd24a0f10185a5484022ac60fb7b2b5cb0019281bee79a4d +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=395f2975bc86a63736ba7661985db038efa5f5982459add18201c97e4b1a9200 +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7932c8dbc9727a85dbf2ad28066cef1da46cf0ced358aea0e78a254fc1e423f9 +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=69b8ce57a0c459ca57353cd8302deba6791a19dcf54e16b8d07f76b44e3c65fa +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=27717f0b8b51f90c7e1579a2e3fa781f2a19064872133a951e60200c05db1df8 +dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=d6cccdb4ca0856ce1d314c03779c082ee0dff153aa6bf9ea050ca3d0a395dc1c +dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=9fd58b7c529d530e8b894a24e7f3a33d291d7305357c7cf52bbe708cde28c381 +dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=f62de7e74f558a27bc2ef04897ad2f4fdfc162a17f21fde8efb2ba15435d80f2 +dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3e97b06bc72aa51aafd2d2f65b4c4d9ab08599c2616729b79dbd9c51886ab6f4 +dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=8f149e17d654de210a71ace9db03f23bd1a80d0e2c17f8336da2b1ec2315c8a0 +dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=ae6f3a738f1793fb9659e7613811b2ac151e91e3d8e470166b6ae615e5a285b2 +dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=92af1bc3beaf80a763aac682a15957d82771fc619d446fb4327f4e8be229438d +dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.gz=b1f5ef77e28e9ed25050b130299a1c431a851df8b11bd457393fd464a7a9c35a +dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.xz=e5d744447649c57f8238c7d020f405559185d644b9739cae53c6963cdb380ea1 +dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.gz=964c824519d8f352ea049766c428e6409549f7a4921c50f91dc548f2ec7f65f0 +dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.xz=2f3b6d4781b21902e5f6986b75f3a0617198bad4741d4a9b957ab5ae2beab05d +dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.gz=7a95faa851ac8dff7f57cfa42169018b29683fbe06dbcf29e2cb311a0c880e84 +dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.xz=deb1eafb4cdad0391bad8dd0657577d4c0960fb7fad7b7552ef1e662c4c1f12a +dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.gz=1b35c7e25986065e63dfe8e8a1824bf13b62daa5777f32b140f03d0f4fe5cd1e +dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.xz=335b28756025f8454ae7c6ef6760a512f0b59385cdeacc7dca0ea1bfe5e9a703 +dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.gz=2291b4c7f27fa0408f394c48390cfd6c7144db5cc4e51c8891c3bb24300b8421 +dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.xz=16b6104ae79bc0f3fa6d862c72cb3f35a9f67bbea7f9aee7b2a3b0c810225c6b +dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6a7f167dd4c457d6185ee47dc206d19d6ca93e3e0418b21c0745d84c53995e64 +dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=4fb366719cdadec26e88d64154b2b1b459affe5b894b426a0509681d173cf823 +dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=3ff578be0c8b1171c5c2d0aaa3f4fc20f3a252f5adf050bd5856b201cc22841f +dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=16c518c3daf87722a5e2556e92e97d429a06b2ed2c79380989db04ffa4791279 +dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=b1d67e62ac198fcff25c29e731f2dca9eba3fbb09adb29db68d823b0ad63e85b +dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=ac586b0a3cd91eb2928861ded895b96a85880851df2f3e63c2391cb38d98d140 +dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=93cfb0ceb07879366ecb4e00caf5b4459574852943363b0d6fd3293c4a0c27eb +dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=879724fc40ca55193760b3739387dc237587e91c30e334709d5453e07840d4d0 +dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=7eb1217837173f0974f7a0fc69b0e9fea484f2d457f3b193ca3b2c04ed83bcd9 +dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c38af1e6560589be7a0733508b800e68bb5b57f2ec3c5452fb14000cf9ef2fa0 +dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.gz=9475cb292c64491c545a02df4deae77d4174d77db18a84c8db635ae6de691b8e +dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e477e9ea0e5bac0b567deacfba3c236ceda28fab4d63c011d6bc54ac22c8570 +dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.gz=eb7bf16e819eabe3f685bb8dd09bfff31d35d87cf03535195c411ec1738b6647 +dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.xz=05a2bc1539b02ef314b268fc2860836c111705b872d5d56ba6ea511cb47e7169 +dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.gz=aa34f89676c72a3ce5df82cd819466631ed91896dd7a1b64fb4ca9a97595e254 +dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.xz=ad5756f4ce3e0309d04746609abdee2152fae66383b2b13d338c900b8f787060 +dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.gz=36c42b952305d381718c36f34c4d5c1705aec71f946eee56c685eae56f9c40d1 +dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.xz=c0285e26be272e3e832a74f22960899ac0f350dc6764701df748541ddbf69377 +dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.gz=198d4cb5195fa1e992cec8bf84716eed1ade0e9a8cc3981f3fb3cb9971e2796d +dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.xz=0fd2cd8923741931aa17d1571a5f8c20c9b0e96d74dc75ab47cd9245586bfa03 +dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.gz=cef69dbdfbd0352bf781c1e59129c29c17a6c1367aa00184be309c56f8f29dfe +dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.xz=a412840ff9550e447a2608a9c26ec02e969b2579bfe5c635a3af0cccd011922f +dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.gz=290fefcf45ff24a79459c44523bfbbeeaf9eb9bf3e7e64fcab64368fe21ed2d7 +dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.xz=176634d6797df21873c317b93cecfc32f415b3248139a32bfdbee83607e734c1 +dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.gz=639916204bcc229bd5d5fd1ccb455d9a962a11d05388252c1e5e310d424f1ef6 +dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.xz=c0c597f428fdc8f2f89e26c0e5d9debef45ec449b869ea0a738102a8727e8da4 +dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=debfb6dfe448e345cc934e5a0d09715ca899ed9593c26eab07c58c41683113f4 +dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a9b6b2de9e26182f5a37a8ff56487916379809b2afe9e14d34ee55f98d526267 +dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=2517ded939281e8722e5ca6d2cdff6a78a4fa39b5828a3048d9f25a3ec40bbea +dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=7e8efa9cb373f580c46fa348b1f76acb46456c71fb6afea2b22d5a16b90ce28a +dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.gz=2bb9470fe62c5c1e1d31f63544b2bedb833c07c5305448e46283b48d8a575d65 +dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.xz=66a024fd9bda49ff4db5d70a2dc094708ef73c027ad0aa7dcbd7cea8449b151f +dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.gz=104b17a08a01593195921a56153a2b54782640f9dbf9e59c7da9f29afe3fe4aa +dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.xz=c3950a3a8bdd1326ab7d0ac08dc2a4f5c354e9ef6447324145cbe9fdef54f026 +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=d1d998991c9c8107f919c851d327d730beb6d4f4937a9f8dd2de2fbade1c1dd6 +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=654322ad813f9414e7ba2c5c5cb141db234d73b9ad237595d844dad564917a98 +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=6b9323f0bc1055dbf3e5fb4ec5fa09f28b7a0cd04ee8bb40e727d85d1a5225b5 +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=3ea958ef88fc3334e98556fd3bcc00264d9dd75cccf6f19f6f5514ec447d0557 +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=ddfbb760544eb8a7562cc8fab7cf313d45f490dacde3575329f627546971db0b +dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=25f8e1279fc8647e117c6f3dbf3f4059e7ddc058cf6e02b43f499a72bee6ebbe +dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.gz=2941d17a2370ecab1e839236ba092c065cfa1b94e448a77a5851dab9ec2f1a59 +dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.xz=ff2aae7c2e37e48f500df5876c3a26d3dd10affd04e888ce54a4635a5345efa6 +dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=1cdbbbdf1aa9c6e764493576adbd962e004ff029b064089be35910768f409579 +dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=8196d32e28630a3ccc1dc96d9abb3efb5f2090b7bdce9963b2579995f575435c +dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.gz=bbe4419e2d9f5bee75f6c1f7b0cf272100e3a37aebc28bc626820c886fabec47 +dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.xz=2fc8f8ccd022152a87a447079169340218d7541b3513eed36cf7af20d5f565ce +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=222198fa6b782010beac1710693ee1aeac1ad7eb9ac183625128de788a1a4bfd +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=b60da22feb82c21128a151013c690cdef1c291de33e1b6ada5dcc95d3bff3899 +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=31ab3940e428fe58ac584c33072be16d31edb0c16df379d9847cb904947126cc +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=8304e2e4440e0a91b05bfe58bd44e7087c28c2682a1a5f5b659e2aba708463fb +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c15ecaa46a814cfd5fa27b29aed9e0e578a652b8f6392b916341d30172da7ede +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=08a84716ed6bc70a58841c5d61216a781b8a947bbb5fb5ebde757e537a2e5dd3 +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=5f1a8ed2093099b18cc83eddb304234f201f8ab137ae950c73329156570ba975 +dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=ebcd581394fd243eac3d683e334d73ef3d3bbaf7de28bd4082329683e2c770c1 +dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.gz=430f4b7f7eceb5e633bccafa9acf08095c1aa4b3dfaa94734fcd331b3d69ca44 +dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.xz=2e403587de5c02ba9c5f9f2515d4c9fdffde59cec28c8dcafdfe40d03e4f3152 +dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.gz=84d695e6f19706fdd7c01dbfc4607f310e8495f57c29bad2476e00c7bb269646 +dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.xz=6e12698afd8a6743a9a6a011ad67ab16d5a40b6dbf1d09104b8294ea95fc2636 +dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.gz=cadafa58684734fc43417742d9151aea36b62f82aa3cd7b858140ce31e9a6ce6 +dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.xz=f1089cab004cb67134bbac6d8acb09b4dd5e02010e069790e13970b004ca4ab5 +dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.gz=2dbc6eec98b7d730fe2ba982d78f7331346e9018146597200340256d28c0aaf2 +dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.xz=8a5896f3301a6238984114cf52f7f234bdcb712cb6d914093159ecc82904ba7e +dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.gz=4c6172e8523576deaa6c83274dbd993338d545a794e42aca3c074450d7e7cea0 +dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.xz=5e8978daaaed1304e94c071ab5414ce90eb9c7bd1c4f1c8c5f4ff515f6558851 +dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=49cba73291916ddf2e4912d4ea02add165f2786ad7f7b8885628d92579cbebd8 +dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=d60a0a176b7d15606f6ee31b67d4a5ac6735e5a0b012022e9212fe723bddec48 +dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.gz=dfd4aa83d38a6236789676ef02c81382f0741671ed9a973cd74d37c65b3f111a +dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8ab6cd565993b58c6e2169bfb468c441dd385c5336081c45f6a60608522ce549 +dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=eb361e2d12c90c9380112ef48b81db1b41f04b4ae08cd061fe1caa46cca9ce6b +dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=e9f4c66995b8e955e86a67c44fd8d7f6e7349645393bfa605c6c1bb0afc7b930 +dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.gz=dc88806e5ac4004a9a3cb24f0c850fde2c22b0e38e6ad84bd570069043485bfc +dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.xz=e103f1d074ab105d03a88066363d2b103508ec95c18cbf8b1f92d0f473ddbf40 +dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=e35bcf36bd7578cdbccb60d554feb19f8376fd41850e4e8046e0b2f931040c01 +dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=ff1b46781284948aaf8c8f582203877ffda5a78d86c266bf724fbb08503a6e80 +dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=dd657b5eb50264c90fafbd967b20768d9e4df14ef179902420b3f9a3e2145271 +dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=3f821c437963aec534cdbd686f719eb86bfe41cf254ed5395730f7827d45a68a +dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7874b945f3d77e2a8ca308e5400a2411ab4f615f45a036bd9fab8a74434c309d +dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=39523f09c76473d10b91ee946523976e01dc337d2af067f08168f1d9cb44226a +dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.gz=43b095acb25cf5c0dbfffc6fbc864c2b2415251931b149b282d5e70844fc2c50 +dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.xz=6cac1a1a6d74765f4233908920d295761570ddcd8cf3638bbc8f8eb427084b92 +dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.gz=7f4314596e6ea01a35b9e2e250227a74b5d4bd772ac8d33d12bd44f8c11b37e5 +dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.xz=eeaca23bf3cafbd01cdcef890d02ecd622d3ccfd6d9830f1e599d29acfa371bb +dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.gz=e79e3a25bb790c5f6ed9e81a0559a55750a1a3e35250f0fc5fd92c195625aa28 +dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.xz=1fe31a0e463736a9ae90ef11c1e3c7b7972eb82779ecdf5b6bff1f643684a014 +dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=917db09ef343b6702c1410c2c68070c4bcfd90f6951591490a6a237290a4aed3 +dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=222010f8428a3d165801d95a820b639ac930747af3cb4a42a25548330585f73e +dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=7e949bc169a58e450e58088fd716aac9a05f5fca0790d94dd211ce823c2c5d36 +dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=dfeb99ac76e18160aee7ff1c878b44b9fdb725f7be28609e637bd372aab448a3 +dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=523103d950944aed52578002dd372207b3bb38e4130b4b11097b03f7d55345c9 +dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=db5c4ce1a1a4d87cca4fb64a6c533cc5ab1c94e25e69b26e13808b0fa5e853e9 +dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=68479082544f7f68a2fe073ed3d35e1895643f8ab9abe9d0e968efa9f342de36 +dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=8878cf473faf120efb80bac0564b193f3baa14a9027fb4c060574e6fc921edcc +dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=eb37177cdbc9e2b7f9b74856b351bb764e5c2603366fd92a5c863cbad26e6940 +dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=92734c444e0156e16c8d8998a8432b24d9d01b82da15123508d0002eb008b9bb +dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=502d5d2ec61d9fcd5b92caa0b4f0aaa11f27fccb7ec4736e05beca313f306585 +dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e00bc0ef1784b2f7b1fdbb757cd50342cacc49f7f5d2d3f7b36f9f4eca23882c +dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=3e00c4c0d64977ddd2fcece9407a01f92ec9b44ea37d72ebbdb77cf0c532163c +dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=3be5932af030c758a84bc09cbb1c2bc5abecc4e7d8a82de58c2a069ad36e737e +dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.gz=aefcadb257bbcf93dda58526390962316b4e579707c043c45e52bfd4d7a097dc +dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.xz=3d163f9fdc2b8b0f5cbbf846caf1dccaee07984d8783250e8988ef447e53663d +dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.gz=bc1692d8d75654012a823adb40b87d3b5721b19beb49a30b404a6c78f431c944 +dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.xz=ff7f36d7832b094b9ca2132df4851cf0ca50c9fc2de3d55bb6c75b46dd028f10 +dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.gz=1a67e618eeadf362e868bf2cb35c1a312db83d1a59cee38f61794e45cba3ba4e +dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.xz=28c0ae4f78f37abe27a3db5e5fb8c78c51a98b71cd0c4c69f9256b5d4064e78d +dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.gz=c2da94328a164d889ebbbcd5f403068126e8f28ebc0c4ff7bf5cde1e8cc380b4 +dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.xz=4fb30f600f8a10f43bfbf4361fbc7e906217007d46d65731b1bae0007eaca783 +dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.gz=86e23a551906f961a8a05b50185185de683f824a69bc739c3786e4f2004d83f8 +dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.xz=860562d5c50c60233d088886dd22b23c0c40504107b04cdfb51506c631d948ba +dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=b568148f13e609e6cbb7e2b424c13a8b85126c8ef84f3b884043aab204352615 +dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=7983768e6c77334eedd563cea4cd51cbf85d5234d1952801783016f07f1d6ce7 +dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.gz=839f7866c75750a5fdc0e7b9fdf37e0b60e71be916b496a9be3ecedc87473c2c +dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.xz=5d0e3c8e9082a00be80cc3924e12b7d9d067f9ecfbe14dd1e1bfadff55d2bccd +dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.gz=8c22ee4fb01955f20d04dba271b44e69718266d70610fbd979565d95df316e6b +dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.xz=6356f4d133c3820736f82c4eb2857548b5255af4ead57f1f8e66ebc6aaa628ed +dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.gz=43523fa8da79aca1e5a618c10ea031404250cdf1a41b0da369ed6efd05c4190e +dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.xz=c9a1b43c762b3658b0fac5145c6314a1c9e416d025ac22958fc0809fbb24d1e0 +dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=ba780983f067e7dbcce49dd4d39a0d3c0002dbe7dba73eb2a98d7eae17f70931 +dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=07aa13a5411a49238b31191a0797d63b74120a1fa9b5658a67f6c1065271c30c +dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.gz=96e6367138d6ff9ae2ca4343f3d5277b5fce39fe6909cfccdd57f1867eb9b021 +dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.xz=83e6fb5196805c9bdfca4e80e76e185a885da0820108e98e1fc7ef4aeea7f1e5 +dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.gz=422fdb2cc97767f235d6abb29dbb0e802b320e11c743f794f8ad13160e4c7c7c +dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.xz=75c4aee9a720fa55ac5e80c58a890efbf88c57fbd2c57043b9f29bdbd6ae0e3b +dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.gz=de39b5014bffa7e20ae1f981616664703828428b6b1a74a6fee80fbab446e74e +dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.xz=d5ad3181f6978604f725db8607daf39ee20cbbb6ade35bb50ae7b032b0b62e9f +dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=a4f5538776b2f1f31bef81f37615d9bc3495080174fe83be0c549508923c9e9b +dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=a78a56cf381483703f120c596d6921b04aface91847310e20da53aa887a2e603 +dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.gz=06a6ee3aa204812322d0b9946ea31dbc5045e59253891fea7e079d4c7e1de894 +dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.xz=a4f0add69dad90f0dd7c47966b12f6cb7a4c6e34cc1b44e4a816d359659ae012 +dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=9d88fade821957052581f65765ae84286eee07e0985504d5a7324f615649a506 +dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=0c278a9aaa1ae41bd9bd96f52fed50b1a11a65822024fd01a9eacfa3aa8f1de9 +dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.gz=7d04aeb77402ca2ad964b6430ad75d0ec08a68efb505573f5e134664a5aae044 +dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.xz=d28207a804219edccb110160ffdf1c1525248ac225df89f4d11e3538a5dd0dcb +dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=2433be238da05b6dbf44a74537e48a1dcd96fc03a8059ab78e553833546f1b97 +dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=74d5920785504fbc0c1e0237a4ee4e8355ffeba2c4bd9471c38d44e3ae52ef4d +dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=f83867145c740302ad81912f8e39433aac19fa5312f14d35aee2b59638660299 +dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=420c7b7b6cf54eb27fc3446223ab03a3f90628b47d6b4ae66e432380b57661ad +dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=14eefaa624591a49d6d2a3af9663ea4f3aca804d3563f668c734d9e18cc0b39b +dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=14e8371566643fdf146117d06b9fa77aa886360d3696d9e43482f288338822b6 +dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.gz=b7ceb33faebadc67294e1df3f08d8d9760a6a17ca1ad30f26da3c586487a14c6 +dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.xz=f0a3f41a65d90119a4c66c6a2007d1f1a75a24e86d9a572837c4410b02af426b +dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.gz=dbdf0cae38daed8bee11eb63d7c3f1c5d019777c238495149baa5ccb10af0f37 +dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.xz=adc49c09b72ff46d3d03f31c8c641675af389ba99c4c517149a10ae471c37c25 +dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.gz=793ace0c8927a48caf443b794de097895f9e503299da07da13238a56ea8ac07e +dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.xz=22b9b2b27d0b6b1fd88d67b18d34a4a91207e6b64ba8d47dbfd0c58763d429b3 +dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=101437e0f1bdc8ca07455d92c87bc32914a5047f6c9d7b7ab9e34799c5d4a5a3 +dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=afd8c55fa82482a852b564511c4fdddf12abbffc0bbee1b0b4155fd1d6c04105 +dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=df33c329856ed057d069a479181b4fa97fd4a11d109abfa32d6b46c36215e6f3 +dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=ca8451dfcb5b919c1a6510616c8e93dfb15914e689cb30f7debf4c1a4aef58fe +dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=1b738f58256186f0b530375ea2da804aa1834a908412e56767c9a44b134cfd68 +dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=93333f47a041d4ddea4fd9ad3fb3ab43c40fcee4fabe6405190fa26d6bfe3e2a +dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=2f0da38cf8efcda85634249df5398bb99f3b34982fb4509a0a3171437d809ab0 +dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=fb3d68e09e40cbf7d6c330c3866c37c759ed728c1d8cbeb6e8e834f6a1fce1c9 +dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=7cb5fdfebbc0565e2d883da09815dfb626104afe39c01b169a919a82f62df607 +dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=d6705b1e6722e3faf5b863fb319cd811fcb27f4a564e633f164f02f8699c9255 +dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=ea33f22a67f7c8354e7421129bfcbfb4bce7d909fcfa6a64a3107d82be69d213 +dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=081e303cf123ddc162633d4d1e3adef4e6fd39598f60ac9dd75c76230df39ddb +dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=76ac5dc8b8284437e5fe81cb4978460a6aa5c4a857c4f14246dfabf1831998f4 +dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=2ed67a738a07e9d07c1db7789cc5ebe7af033334670fcb1ce84441b9e474ec0c +dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.gz=d5a7e6cfdd099ed18e54d88dc1d740b90d1f7d2f22d1fe6ca7960b7319b0783a +dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.xz=78231b81d8e612a4c41828428ba2e9af926f2119308b291c8ce81a5233c3c6a6 +dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.gz=a1b0086259586a26f6ca65b02adea83b953989a508385d58fa56c7eafb770227 +dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.xz=b58151b098d58b19bc900f72813138799e2e568a5ad3038528045e5ac562606e +dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.gz=62ecc253fa747ec67ae11c7a1672661cbac7d78c1001654e17ca5c0e3bd72d91 +dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.xz=b7e9785d3ab00163a0070b7772a4354e9503cdb8456d1a2b0708920658aac614 +dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.gz=783d47012b943cd4497c2e0e854cd7727b0957518178165cc1cbc4dc5e6509ff +dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.xz=94efccbbe73b2f15f5f86c90324b3adbd1b58bbdb81ea9c32d7efaf067bc6795 +dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.gz=8b12cc5e7b9b7e0b234a29886c81455878e806067c025cf3d26eef4a52e08bc5 +dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.xz=35fc298fd25949b491c54bfa2f40c963d7ca530b65ac8e52031edf17624b3d05 +dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=824e1590e12bcad69b43912068e27585466fcc5cf7a2f92f41f727aa39cbcaad +dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=6fad67e180d0eb0d551b2101dc27bf6846ae2840c63d1ef05588691d055e3806 +dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.gz=1353d8c3310d53576d94aa744fe0844b5527d8b54fe43a692042be78b0fca6f5 +dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.xz=a7ca6fecd77dc44f3102abad7fbe1fa3846d9ff6ea98a25d4c3bd703800894d2 +dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.gz=33b5f8dd6a0ef045ad19df4327259a468ece00b250d9fbfe1be7c0f293f874ce +dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.xz=1bd56197e30fc325c7482aa7a42006a7ad9a0ffad9f3d74d209e98582d2897e4 +dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.gz=0ba3c497472c34de44bda2485d3b964cdab83e3700b44ffd8b41037ccf59a932 +dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.xz=040302a04decb3cfcd599b329db3f17e5f96b7aa4b8174d6f2b17ba19c991853 +dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=21fde20675c5f786b5da4f1be39785d1106f748d88a6609fd4976bfe372e6817 +dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=217255d6ea157f7b06aa66d033dca6239bbc296bc14ff3f0017d5c68bb4d1022 +dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.gz=7be4202a658df30aeba451e6dd4f740068dbcc769fe0eaa9a7eb8cb2c2e264ff +dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.xz=d2cf3cfa0c5c67d57867586709c274e320c1a76418ffe7dcf65b271448d4de06 +dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.gz=91f510466f2a8606efc746a5be209a1f0ffe1e20b803f9c54ee91786053cabbc +dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.xz=2c17d3a00885495f81cb8606ceb78674f63396b3c2a0b3415bb2e62ab39f9d87 +dist/2025-09-21/rust-beta-aarch64-pc-windows-msvc.msi=d5e39b0a1deaaeaf956e57da755e16255b265e80722428625783e7be0835cbb8 +dist/2025-09-21/rust-beta-i686-pc-windows-gnu.msi=edcb39b92d1e84c7d6b0d2559e37be673795a14e807e77e40b32dcaac8b9d415 +dist/2025-09-21/rust-beta-i686-pc-windows-msvc.msi=dac7d64336aa8fcc77761910392efc845aa2137fff8be8df980b02d48809bbd4 +dist/2025-09-21/rust-beta-x86_64-pc-windows-gnu.msi=44e1e8298714b11bc7cc44184f2b20aa39fbadc23f8b2b86005e74879b8430f8 +dist/2025-09-21/rust-beta-x86_64-pc-windows-msvc.msi=4c673f514c7f0f9bf780c2448fa4a4bbe4e4db618d6a9931bd092a6116d432fa +dist/2025-09-21/rust-beta-aarch64-apple-darwin.pkg=4a23353da7a58deac032341011c7bdb78f069ff4bda97d837c67e54454e6e1af +dist/2025-09-21/rust-beta-x86_64-apple-darwin.pkg=5e02da3f6ab8791426060ca40ac7c719451f6f5acba06ec27c273e6f2590cad6 +dist/2025-09-21/rustc-beta-src.tar.gz=22b0288ca9f949cac41260370afd4e6e487c1e3430f6aef23340b50ec4e4ea9b +dist/2025-09-21/rustc-beta-src.tar.xz=31f4b8b4b3471e7063da5038fe5072e44293705ec65b2c272f8d4cdd37875ff1 +dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz=78627de068d788f65482cdb2763b27fb7570a197b97056ad16f9f6117fccff8a +dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz=d6c4252e895d303337ce1c8edf2fcfd02078b81007e785ff7a15f773a1789e3e +dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d65ef7c1348a74dc1b042c30281ec57c2619a25bdfd8151223415f9d6e067fc5 +dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=dcd986e9560c45eae6f1d0ee0bce9ad2365d101f4c9b792062557cb26a26152e +dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=8b5a164ee78ee9bf76c1ac9d95f63743cc0b05cff9823d42b88d596ee34c9b52 +dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=da675f08931285b2d59be0b8cda46f7489855ec9cc07a608d17e4c0f1e6de486 +dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=7a1b11c66f3832e0ccd390441a921cd50a25ae87e641bb856966fd81cd3d5d59 +dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=5f6aa12529624b66f1de643afe6805cf5484c57e3a7c791f85023d28b590dac2 +dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=0cc213fabdad76e6ff699f2f0462c8b3dfe5bdc6b14131fc2c87d915a8fdabbb +dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=ca84ce0de6d11b69ddc691f4edca1474e66b513f695fab738374942d57ab8b83 +dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=dc0f391a0ac09a8ae2271443584dc8f1338bc0b89b50ee82d47599912fb74c52 +dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=d4bebefbc157ecde2fbf7f7ef6a6d8c703d264f56e2ca8a80b7c241b8e14f862 +dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=672fd91b880195a0fb2eb294129c0ec465aa3be217451fd4b835b2c3294d4c1b +dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=4aa45c993b82f9d9f6b8bf79db2d04acb83cd70147c9ecb1804a3c8258a6c022 +dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3a8fef72bf471ea1c575c3a6d3a0ffb957fd862f55afb0d40b39c85ff7fc1f13 +dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=08854b212790685caa928e37aa7fe50009590050873c390d2999d6b814bcd2bc +dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=e99f0d4b314c59b7564e85be580477e751e46acf30752b970c36aa9719e10995 +dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ba3b9a0e0c44c6edc1396915034efe9e7f59e0724271fd6c1fd4805382e95677 +dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=40f42081d1d2eec00bf49f62c12d75e5e5c345e2a4d8da4fa0741239aea72218 +dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=1b9ef88c7ea98880835d8c298625e2bdd219af46eabb18b8c18c92882d81d054 +dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=2ff88b8231c70044e9b35c3855515d143aac1b3d7a82bfc84833f76f45539c97 +dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=e07bab9116c10576b7ab01e26af72bdc97bd34a56aa2468e188e58864b030c33 +dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=766a69e69be097f710a7c175dbfa39b20970135a6fe420457191e095de5fab1e +dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ad4a38853cb9e6bb6029dbb2ffedf4b49dfc7cb696edbcb561b204bfa89fd8d8 +dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=f08d5f5ac31fda285b81069709a74eb382450543c4d22289980a9ef94a473fac +dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=40bb1e41db10d4c6b22e46c0f8b5fa1a6ad06cd5f3102c189705380383444323 +dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=d3bf8c8c186c94a0190ae73386839e53dd6ea76cd81e9132438fb7f245d955c5 +dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=665dce6b1a464e1969e3901d7bd293d35a85d5a50ad976600566dcc2a9c46b58 +dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=a28c82ea8a7e2bbd61043e89994cf2be71ead745b3fa782d0653a99fd81bfa64 +dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=3c5cc78a7e311f73c39030f42b8f1d3dd0e54e09f4d636be6a581a829f15483d +dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=372c476dc902ffb7ebb8ab8934a89d1bbddf9df9c810bc6d90d3afab984b8205 +dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=cf2e738c44ea95d71090bc3526d8c7c70e4554667449f4705614c93444e817a9 +dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=47f215d0c639f0a4bb67423c65c5b87a06cbecd47ea53484b57c9b7d87c6791b +dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9085b66b2e8e3460f0993896ca3d684395001ab4ed37a16947ce1d15d5aa224b +dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=0f07ac40b25eeef46a4f4a0d34cf50c9336407f2d7f23c05c47fe35f3a7a1d49 +dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=ce08e9b33e75eb504f28ba23e1cc3003c0aa503fbdceb04271bd533613713160 +dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4e64fc0ec680a294308f897131f8ab185872dc68cd1312fbe1a306ed6e53ba26 +dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=b46d423db54a90944276cee172b8cf0ea70562c01537c37c65f3ea17c13a47fe +dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=3a84501e05cc7430f91903dbb0de0946621d05c095459c47dde3cf7e662e771f +dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=0107d3c129e1a18a814d5c213b6445aa7ecb7dd95507641d2cb3d0c39293818c +dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz=c58e0a2db9b3933539a20614b143e6575f6aa1459ee35af4d67210dd572e6af0 +dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz=0cd4d7a8cfedc2787bacebbb2fa481d5efe3d56ba476ef8799c34325c40283e1 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.gz=ad3fdf81b7b00ee670b05ed2bdc05f79a9c066104d797dc7eaa4d767dfe2eeae +dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.xz=df79594ece4b8753d8215672004e9071a8c10c8ece8c86d1d3608c8d7c3f0486 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=cb800c92a8f899d148adc96283818aa81c115b73555c047e07a67d738e9cd2c9 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=09f6d95c49725c36bace10c8e119d6850dabee1dcdebac264074e296f9e8ab48 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e061a3925b95a99dffb17d34c85803bbcac4604f95da2674872f0725d82cdda4 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=1090793fe09cd2ec4c54063600c1999f5e53a9ddc5c5d74e4f5e85dc6f2ef98f +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=f3978135d4a9bf2537625e38866fca74ca1f0655fc9fae736bf87d257d6cd0d5 +dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=03814722fe9798b503ab7d8284c67e84cf18a9a2f179fe227e3313d0ae3e2cff +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d5a477ce3f220016f097f8949fc2eb1c700c612e97105804156e82264e7ba787 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=0fe90bad20ee599e4e57c46d4bf700c5775c484f0a8bfb2ce4957d2aa2df90cb +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=6d48ed9c944fb01655d4025c4aa3b719813cfef040fecff1f59b8b51a0b9510d +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=34d5a066b9f5bcef81b38badcc96f295150c2b2a96c35621235bdcc54ce92158 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=61a6a8feaf0490e3db169e86e85989538bff994fb76481a81a1ae02222c7ba59 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=cd94e20b4985964442b080454c2b628bcb435898e50bc2de55799cc51cd75f16 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=c2912263d24904ee5b1014a98d5b349754a6fa1bd66498f607cc62ebcf903cc3 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=8ad5b1284c91798a01fd25b3b690f88b55026e109471e759d4cecdefd1f83a39 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=e0f52a6511c36c2ece175bc993861cffe0cc72a2e1b56b1def246e09f70d3a75 +dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=229b92a2c0ef8ab1ac588858bb371ea0ed3449dec82a11ca7386df6efb2f65b7 +dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.gz=de7af74b8c91fb87b20df2d65b536fe6f49cc632b1f0c52a1e65a215fd5e4a06 +dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.xz=7a3e8c68f0bf4d393393628bd85d22242eee59605e3d56e0e94d06163ee2d4e9 +dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=2826132a82eb5adaabe2fdadc76ddc21460834365085ff2a113d934c11870a41 +dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=47980ea13cb887d85f8e501ca2b5d6e4b77ba8f229b2cfb9a1f28426c60d87a9 +dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=10dc98065c0b19d737ea93506df1ac399c33190edb3f6bbc51d6c1697e910f8a +dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d791bf9c54ccdb02da34e408aa93e0680f19a3bfbed1e5dbd61b57f1e1f38fdd +dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=ba6e33f6efa2f5a97790e29bb72c89bd460d758244dc9dfa4684e01bc75b6656 +dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=4e38e862770ed0215720445e56fb027570e4f3c09d63a7f68cdacbff482b4cec +dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=b126fbef234c0b67df42fb0568580b3d95ce98b7346095c3762214fcdece14a5 +dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=07af694d0ab0b55b18bd437ec9edb965f451f1bbb8334e1667f87d1d8e8354b2 +dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=6901b57b0fe7182a45b1934e1d7a006ba353daf114ea7601563caade4de1b2c2 +dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=c1af7bcb75c1ce5975e606aacb2d3decaf7a8470cd347d4caf75f11f84d3122f +dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=8f29e493bd15175ed2a72d50857cbcc07992194c0b38d2b0a4660217b04b8276 +dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=fe478ade162b6b5d33808f4872de54e0b9dedd84e9e420480a370a2555d28cbc +dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=f03a3368f41969d061a9ec2e87af512c346f9e82b6286eea65dbce33de90391e +dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c771ab34e5bab9344be3dab9315225296e41b3fa70cfe59fd3e0b287c4985fc2 +dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.gz=9f5555633f1f1462285c0eb39aa42d0beb45cdb3b45c524483e4e4c6b76b6551 +dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.xz=ae8c171fa20a49d7323bb5e6a36b262947caae260adb942204206aada00bcfaf +dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.gz=2b50b6d9027d5b480dcd2693a551bf80db7d3dae802bfd9a825b68a50ab022a6 +dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.xz=d4b396eb0256cd62718751f3a52498dba992ba063ed77e5d675da8dc06a6751e +dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.gz=f74acd9ecd35d10040e388d5224a9c88e66348dca09930d89068e87a0371a7d8 +dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.xz=92bb07e968cbbbfcf1bc7d0ecdd1a088b8c2975691bbf6ed846bc69708e34f13 +dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=7b756904c495de2d37993d71fe1e70e182c232aa408296c6ba05f71a94423406 +dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=522114675fb36949b953491d9a5fa0db39d22118f015f8ce92a120eab39244b0 +dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=2309e49988ec8c35ef17f7293d6b2a787589eb38bba217a8f9429446713cc2a4 +dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=820950e1cbfe6d973e1835532f9e201fe215d149bc415ac7ea011b16bf6b7bc8 +dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=6fe053425d6b840c72352a88021c3b2b6deb389986575cb5e7b8c5991e86d039 +dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=d62cad3e6a7dbab7cbefa493e78a0b7d7e8f724dcd766ae03b6715c325594fe5 +dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=8bc6b3d521f5117bd3f9321d9d086e928fecf548be58edc71b257269e68ad21c +dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=d08a0ed4adb7fdf451d39c1dd56171d6ce345b10cf905515c07ac5eb66f7d030 +dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=02ac6a9c23c1dfaf12e26b466bb33057787c28f2bfe8503b998a5d5aa55a4370 +dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=77709b47a9d99657e03c77f32183b2127e75488df59cd000ed20cad5868afd5d +dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=b811bfae5380ffe89e2f48f6c0e6f293e8db33461a1fda94a85759d3464100c4 +dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=bc41de8c0c65d912b5d6be06f3b12b3e4be1c20c1dc6ce1b7f5226e7d3ab3ae2 +dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=110b42065218c2607b01edb83d41425176d7f065fac52c5836bed0d2215fc5b3 +dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=97e3a41b0718ea14be4b7320aa4efc7f19b3feeabc7aa9079ce4ea487cad8064 +dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=4e1fd4ed9df5ae921380e3396159053c87623a9ee1c7bcc1f897674c9165714d +dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=1e2833f165f7b255731fb1d26bd6026f5b6152ed91ac70d8dceb4f692ea9a66f +dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.gz=8113fa75d9ad92c411c71b6769f2af4450ed3ae285be1ebf10afe022abe52661 +dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.xz=150128e8dde149bfbb2071cc933844ff87931cb856939db922eab98230ab7bb1 +dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.gz=727f7ae1f1e5fe51a3722105211cef3eb92f792cd054857ffef7bf858d0963cd +dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.xz=295672b0d6afb6e80f25dfd6d1643414f976eab6da00a5babf377ecede580e56 +dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.gz=3505cebc0659388e110d1e55a5eca94ac945d75b3320f16ed9ded08629a91638 +dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.xz=515d5a5046dd2c4b3ac2b21a6dd4bc834eba20d08b902ed396e0b62101978210 +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=838ce3f625b6dfb87f0271770515988d3b3f1535d75353b8f0f4a69074c1ceac +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=186eae6c01ecfc67facc96ac75d8518c31de1bf8897d82bc587941c3f686f4c3 +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=76e5d092c78b663c2d75ee9d95f6c60d1ecb509b440312f4a8ad333d58de54b8 +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=69ffcda8f985b3c5b78b18f0eea037890f2efc205f0b7cc4b788f1b35a3b7eb1 +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=2b08c563daa21d817bdac9c8dd81021a80967e7e671a312c2990575e3622b928 +dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=2e54f6a6b6e096be1f717361d2e474b2ca94957ee006d5fa62910ff3d85cf05b +dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.gz=6e00949c5d3a2f0ba86f1d89f54278f09e58f043cfd00d1f5df984835228d28d +dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.xz=46d9945d5361b758448454c4778a42ce01b4cff7370b9988d5e7b2c7d889d24f +dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.gz=83f3d4d069729a72da4b96067400b812367e0a81284bfe3cd73b1939fb81db9c +dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.xz=110ca4f2630368f1c94084332d825964f3852bc9e70db8ec738de2cd4f450f2a +dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=e1ad313cbe777997222bbdd4b26a5b4c21da50b6378e434501c58219137dad77 +dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2ab176057835fabd55e6e2372b036c245be44c0705198557ef2a16d187ea9457 +dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=3e643ce549e9db3768c478b37f088afbf9b2f63dc0275bfdf7c2cbb48ac4fef8 +dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=597c47ff84de68f317b0672d5564a3121edd88cbf5dd3d27192d133ca4ac05a8 +dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.gz=5f948f48d64420119f1bd1a90952a04cec074ca45bda8d46f020163cb2809016 +dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.xz=977612fd1ed20d57b95e577dd9b3632209fb1f376f46c66467e2a2ccdd7d29f0 +dist/2025-09-27/rust-nightly-aarch64-pc-windows-msvc.msi=b39edbdc83f4329be0e194be1b7e002e764153628bb107bdc77e6f8c2331abe1 +dist/2025-09-27/rust-nightly-i686-pc-windows-gnu.msi=d023b88f94d2d25b4a29c03d4e1243484fd7a20d67753fd3e9a10e6f39069df8 +dist/2025-09-27/rust-nightly-i686-pc-windows-msvc.msi=8441a5f6e8650613b5b9c0c2778bc88bcf259fd4f3acd226a6ec52f1b4a960cb +dist/2025-09-27/rust-nightly-x86_64-pc-windows-gnu.msi=15a83b7056623d30dc1d47560151ec79e2cb7db1d229069085e73b782347e8e7 +dist/2025-09-27/rust-nightly-x86_64-pc-windows-msvc.msi=607a9219272d8b41fd6bedf884515d3584471c75be19f9353c1c67826c115aea +dist/2025-09-27/rust-nightly-aarch64-apple-darwin.pkg=55cc7129e581244dcbc567eb905183ff3e45edc8847fc58cb350394e6df55e96 +dist/2025-09-27/rust-nightly-x86_64-apple-darwin.pkg=a6add14a01bfd77634e67425db47cf63144dbc0b618beeaa4f37be2d7103146c +dist/2025-09-27/rustc-nightly-src.tar.gz=419d5aea9252c3a9377fcfefe0a0e91b7be1354b9c33e36e346c547c4a9ec3eb +dist/2025-09-27/rustc-nightly-src.tar.xz=fd454f13408f045e3ba1d4618699a3c6e42fcc66902c37972aa3729bb681d951 From 760ed37769c4902c97c874d324978472ce02f9ba Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 27 Sep 2025 08:25:47 -0600 Subject: [PATCH 354/537] redox: switch to colon as path separator --- library/std/src/sys/pal/unix/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f0b6068e06c0..7c9f3b7992f7 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -16,7 +16,7 @@ use crate::{fmt, io, iter, mem, ptr, slice, str}; const TMPBUF_SZ: usize = 128; -const PATH_SEPARATOR: u8 = if cfg!(target_os = "redox") { b';' } else { b':' }; +const PATH_SEPARATOR: u8 = b':'; unsafe extern "C" { #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] From 35e582f9828a515c94946eb03910d563d6d38427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 27 Sep 2025 17:03:26 +0200 Subject: [PATCH 355/537] Library: Remove remaining private `#[repr]` workarounds Co-authored-by: David Tolnay --- library/core/src/ffi/mod.rs | 2 +- library/core/src/ffi/va_list.rs | 8 ++++---- library/core/src/os/darwin/objc.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 0bc98e2ea864..1356ca217c9a 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -56,7 +56,7 @@ pub use self::primitives::{c_ptrdiff_t, c_size_t, c_ssize_t}; // be UB. #[doc = include_str!("c_void.md")] #[lang = "c_void"] -#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +#[repr(u8)] #[stable(feature = "core_c_void", since = "1.30.0")] pub enum c_void { #[unstable( diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 0d4ccb5aeb28..46ccf330d1c2 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -25,7 +25,7 @@ crate::cfg_select! { /// /// [AArch64 Procedure Call Standard]: /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[repr(C)] #[derive(Debug)] #[lang = "va_list"] pub struct VaListImpl<'f> { @@ -39,7 +39,7 @@ crate::cfg_select! { } all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => { /// PowerPC ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[repr(C)] #[derive(Debug)] #[lang = "va_list"] pub struct VaListImpl<'f> { @@ -53,7 +53,7 @@ crate::cfg_select! { } target_arch = "s390x" => { /// s390x ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[repr(C)] #[derive(Debug)] #[lang = "va_list"] pub struct VaListImpl<'f> { @@ -66,7 +66,7 @@ crate::cfg_select! { } all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => { /// x86_64 ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[repr(C)] #[derive(Debug)] #[lang = "va_list"] pub struct VaListImpl<'f> { diff --git a/library/core/src/os/darwin/objc.rs b/library/core/src/os/darwin/objc.rs index 928cb54e82c7..df3aab867e83 100644 --- a/library/core/src/os/darwin/objc.rs +++ b/library/core/src/os/darwin/objc.rs @@ -6,7 +6,7 @@ use crate::fmt; /// Equivalent to Objective-C’s `struct objc_class` type. -#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +#[repr(u8)] pub enum objc_class { #[unstable( feature = "objc_class_variant", @@ -31,7 +31,7 @@ impl fmt::Debug for objc_class { } /// Equivalent to Objective-C’s `struct objc_selector` type. -#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +#[repr(u8)] pub enum objc_selector { #[unstable( feature = "objc_selector_variant", From 9878be7787a6239b9651eeaccb040778051038f6 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 13 Sep 2025 17:20:34 +0200 Subject: [PATCH 356/537] Re-enable assertions on macOS --- src/ci/github-actions/jobs.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index b3e3fe7d96aa..8303699ce8a6 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -431,9 +431,6 @@ auto: MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_15.2.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos @@ -449,9 +446,6 @@ auto: MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 SELECT_XCODE: /Applications/Xcode_15.2.app - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 <<: *job-macos - name: dist-aarch64-apple @@ -471,9 +465,6 @@ auto: # supports the hardware. MACOSX_DEPLOYMENT_TARGET: 11.0 MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos @@ -493,9 +484,6 @@ auto: # supports the hardware, so only need to test it there. MACOSX_DEPLOYMENT_TARGET: 11.0 MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - NO_OVERFLOW_CHECKS: 1 <<: *job-macos ###################### From aef976ed4c73dab044002b39817509110ddf2cf2 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sat, 27 Sep 2025 14:10:06 +0100 Subject: [PATCH 357/537] Add auto extra-checks in pre-push script It enables automatic check changes of Python/C++/JS before pushing the changes to remote repository. Those checks happen only when the target type of file is changed. Otherwise it does not install any dependencies (venv and/or node_modules). Note that shellcheck and spellcheck are not included in this change, because: 1. Unlike venv/node_modules, shellcheck is not installed automatically by the command, and 2. spellcheck is built whenever pre-push script is run, it forces developer to wait extra time So not to break the current productivity, this commit skips them. --- src/etc/pre-push.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 7bacc943f258..33ed2f0e406b 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -26,7 +26,10 @@ ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" cd "$ROOT_DIR" -./x test tidy --set build.locked-deps=true +# The env var is necessary for printing diffs in py (fmt/lint) and cpp. +TIDY_PRINT_DIFF=1 ./x test tidy \ + --set build.locked-deps=true \ + --extra-checks auto:py,auto:cpp,auto:js if [ $? -ne 0 ]; then echo "You may use \`git push --no-verify\` to skip this check." exit 1 From b3631e1174e222bf1dadf1549cfd0f717ebf6d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 16 Sep 2025 11:52:17 -0700 Subject: [PATCH 358/537] improve empty attribute diagnostic --- compiler/rustc_attr_parsing/messages.ftl | 10 +++++++++- compiler/rustc_attr_parsing/src/context.rs | 7 ++++++- compiler/rustc_attr_parsing/src/lints.rs | 18 ++++++++++++------ .../src/session_diagnostics.rs | 3 +++ compiler/rustc_hir/src/lints.rs | 15 ++++++++------- tests/ui/attributes/empty-repr.stderr | 1 + tests/ui/empty/empty-attributes.stderr | 4 ++++ tests/ui/macros/macro-use-all-and-none.stderr | 3 ++- tests/ui/repr/repr-empty-packed.stderr | 1 + 9 files changed, 46 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 81ec17077c13..6c5346e83554 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -8,7 +8,15 @@ attr_parsing_deprecated_item_suggestion = attr_parsing_empty_attribute = unused attribute - .suggestion = remove this attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .help = `#[{$name}]` can {$only}be applied to {$applied} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7ccf3c78069..e8bb4caa4166 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -597,7 +597,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span); + let attr_path = self.attr_path.clone(); + let valid_without_list = self.template.word; + self.emit_lint( + AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, + span, + ); } } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index ab8ba0daf1f1..3a2a37046696 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -43,12 +43,18 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi ), }, ), - AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { attr_span: *first_span }, - ), + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *first_span, + session_diagnostics::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + }, + ) + } AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter .emit_node_span_lint( // This check is here because `deprecated` had its own lint group and removing this would be a breaking change diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c2b14c8a68b..1194ac5872cb 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -503,9 +503,12 @@ pub(crate) struct EmptyConfusables { #[derive(LintDiagnostic)] #[diag(attr_parsing_empty_attribute)] +#[note] pub(crate) struct EmptyAttributeList { #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, + pub attr_path: AttrPath, + pub valid_without_list: bool, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index b7a0a6a0c197..c9de6f6b5d52 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -31,6 +31,12 @@ pub struct AttributeLint { #[derive(Clone, Debug, HashStable_Generic)] pub enum AttributeLintKind { + /// Copy of `IllFormedAttributeInput` + /// specifically for the `invalid_macro_export_arguments` lint until that is removed, + /// see + InvalidMacroExportArguments { + suggestions: Vec, + }, UnusedDuplicate { this: Span, other: Span, @@ -41,13 +47,8 @@ pub enum AttributeLintKind { }, EmptyAttribute { first_span: Span, - }, - - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, + attr_path: AttrPath, + valid_without_list: bool, }, InvalidTarget { name: AttrPath, diff --git a/tests/ui/attributes/empty-repr.stderr b/tests/ui/attributes/empty-repr.stderr index 92901fa170c2..6dfa2df75b73 100644 --- a/tests/ui/attributes/empty-repr.stderr +++ b/tests/ui/attributes/empty-repr.stderr @@ -4,6 +4,7 @@ error: unused attribute LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | + = note: using `repr` with an empty list has no effect note: the lint level is defined here --> $DIR/empty-repr.rs:4:9 | diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index f0be56ddc6aa..41dc790737dd 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -56,12 +56,16 @@ error: unused attribute | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute + | + = note: using `repr` with an empty list has no effect error: unused attribute --> $DIR/empty-attributes.rs:12:1 | LL | #[target_feature()] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: using `target_feature` with an empty list has no effect error: aborting due to 8 previous errors diff --git a/tests/ui/macros/macro-use-all-and-none.stderr b/tests/ui/macros/macro-use-all-and-none.stderr index a5efb065a21b..b4c05adcb33d 100644 --- a/tests/ui/macros/macro-use-all-and-none.stderr +++ b/tests/ui/macros/macro-use-all-and-none.stderr @@ -2,8 +2,9 @@ warning: unused attribute --> $DIR/macro-use-all-and-none.rs:7:12 | LL | #[macro_use()] - | ^^ help: remove this attribute + | ^^ help: remove these parentheses | + = note: using `macro_use` with an empty list is equivalent to not using a list at all note: the lint level is defined here --> $DIR/macro-use-all-and-none.rs:4:9 | diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr index 6565b2e8c1dc..adf32c955296 100644 --- a/tests/ui/repr/repr-empty-packed.stderr +++ b/tests/ui/repr/repr-empty-packed.stderr @@ -15,6 +15,7 @@ error: unused attribute LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | + = note: using `repr` with an empty list has no effect note: the lint level is defined here --> $DIR/repr-empty-packed.rs:2:9 | From fa53de656ec9318d9462dcadcfd851685c3dcaf1 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 27 Sep 2025 19:40:48 +0200 Subject: [PATCH 359/537] tests: Remove ignore-android directive for fixed issue --- tests/ui/test-attrs/test-panic-abort-nocapture.rs | 1 - tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr | 4 ++-- tests/ui/test-attrs/test-panic-abort.rs | 1 - tests/ui/test-attrs/test-panic-abort.run.stdout | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index 6a1025ea087c..7c78d432fa08 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -6,7 +6,6 @@ //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ ignore-android #120567 //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 8d7c62f8ec70..d8f65a78261f 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,11 +1,11 @@ -thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:32:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:31:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:26:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:25:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 6c9b641fb6fb..13a30223399e 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -6,7 +6,6 @@ //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ ignore-android #120567 //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 4d65c05b9440..ca247f7da418 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -18,7 +18,7 @@ testing123 ---- it_fails stderr ---- testing321 -thread 'main' ($TID) panicked at $DIR/test-panic-abort.rs:37:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort.rs:36:5: assertion `left == right` failed left: 2 right: 5 From 19d0e728496afa1ba6a5f9817201b7d57337c14c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 27 Sep 2025 20:38:45 +0100 Subject: [PATCH 360/537] fix build for android --- library/std/src/os/net/linux_ext/tcp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index dbefc91a979a..3f9b2bd3f4b4 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -4,6 +4,7 @@ use crate::sealed::Sealed; use crate::sys_common::AsInner; +#[cfg(target_os = "linux")] use crate::time::Duration; use crate::{io, net}; From 4d32b9a1783343d42a9864fe3d2115daa2cb425e Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 27 Sep 2025 15:47:06 -0400 Subject: [PATCH 361/537] Hoist non-platform-specific code out of `thread_local_inner!` --- library/std/src/sys/thread_local/native/mod.rs | 4 ---- library/std/src/sys/thread_local/no_threads.rs | 5 ----- library/std/src/sys/thread_local/os.rs | 5 ----- library/std/src/thread/local.rs | 8 ++++++-- tests/ui/macros/macro-local-data-key-priv.stderr | 2 +- tests/ui/thread-local/no-unstable.stderr | 6 +++--- 6 files changed, 10 insertions(+), 20 deletions(-) diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index 9544721b923b..5dc142408047 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -108,10 +108,6 @@ pub macro thread_local_inner { }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*); - }, } #[rustc_macro_transparency = "semitransparent"] diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 4d6a4464cfa8..409dfb19518d 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -39,11 +39,6 @@ pub macro thread_local_inner { }) } }}, - - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*); - }, } #[allow(missing_debug_implementations)] diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 77746b203a32..b488f12fe841 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -85,11 +85,6 @@ pub macro thread_local_inner { $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? }, - - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$($align_attr:tt)*])*, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$($align_attr)*])*, $($init)*); - }, } /// Use a regular global static to store this key; the state provided will then be diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 70df7e724caf..4259a4d1f3b7 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -327,13 +327,17 @@ pub macro thread_local_process_attrs { // process `const` declaration and recurse ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = const $init:block $(; $($($rest:tt)+)?)?) => ( - $crate::thread::local_impl::thread_local_inner!($($other_attrs)* $vis $name, $t, $($align_attrs)*, const $init); + $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> = + $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, const $init); + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? ), // process non-`const` declaration and recurse ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = $init:expr $(; $($($rest:tt)+)?)?) => ( - $crate::thread::local_impl::thread_local_inner!($($other_attrs)* $vis $name, $t, $($align_attrs)*, $init); + $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> = + $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, $init); + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? ), } diff --git a/tests/ui/macros/macro-local-data-key-priv.stderr b/tests/ui/macros/macro-local-data-key-priv.stderr index e93bd11046d0..8df1aec140d0 100644 --- a/tests/ui/macros/macro-local-data-key-priv.stderr +++ b/tests/ui/macros/macro-local-data-key-priv.stderr @@ -9,7 +9,7 @@ note: the constant `baz` is defined here | LL | thread_local!(static baz: f64 = 0.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/thread-local/no-unstable.stderr b/tests/ui/thread-local/no-unstable.stderr index fc2541894e74..fbcd804d9178 100644 --- a/tests/ui/thread-local/no-unstable.stderr +++ b/tests/ui/thread-local/no-unstable.stderr @@ -10,7 +10,7 @@ LL | | } = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable = note: the `#[rustc_dummy]` attribute is used for rustc unit tests - = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of an internal attribute --> $DIR/no-unstable.rs:1:1 @@ -38,7 +38,7 @@ LL | | } = note: see issue #93798 for more information = help: add `#![feature(used_with_arg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[used]` attribute cannot be used on constants --> $DIR/no-unstable.rs:1:1 @@ -50,7 +50,7 @@ LL | | } | |_^ | = help: `#[used]` can only be applied to statics - = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From 4d411775139e1bc39c2752d78e40f2bcecb5304b Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Sat, 27 Sep 2025 22:58:02 +0100 Subject: [PATCH 362/537] Rename various "concrete opaque type" terminology to say "hidden type" --- compiler/rustc_borrowck/src/lib.rs | 7 +- .../rustc_borrowck/src/region_infer/mod.rs | 4 +- .../src/region_infer/opaque_types/mod.rs | 79 +++++++------------ compiler/rustc_borrowck/src/root_cx.rs | 22 +++--- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../src/collect/type_of/opaque.rs | 12 +-- compiler/rustc_hir_typeck/src/opaque_types.rs | 19 +++-- compiler/rustc_hir_typeck/src/writeback.rs | 28 +++---- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 7 +- compiler/rustc_middle/src/query/mod.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 4 +- compiler/rustc_pattern_analysis/src/rustc.rs | 4 +- .../src/traits/select/mod.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 +- 15 files changed, 82 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4c380ddcf708..d799eb1f8c6e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -116,10 +116,7 @@ pub fn provide(providers: &mut Providers) { /// Provider for `query mir_borrowck`. Similar to `typeck`, this must /// only be called for typeck roots which will then borrowck all /// nested bodies as well. -fn mir_borrowck( - tcx: TyCtxt<'_>, - def: LocalDefId, -) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> { +fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<&HiddenTypes<'_>, ErrorGuaranteed> { assert!(!tcx.is_typeck_child(def.to_def_id())); let (input_body, _) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); @@ -130,7 +127,7 @@ fn mir_borrowck( Err(guar) } else if input_body.should_skip() { debug!("Skipping borrowck because of injected body"); - let opaque_types = ConcreteOpaqueTypes(Default::default()); + let opaque_types = HiddenTypes(Default::default()); Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 0910e8ef4b37..e98c60e63380 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1382,10 +1382,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// The constraints we get from equating the hidden type of each use of an opaque - /// with its final concrete type may end up getting preferred over other, potentially + /// with its final hidden type may end up getting preferred over other, potentially /// longer constraint paths. /// - /// Given that we compute the final concrete type by relying on this existing constraint + /// Given that we compute the final hidden type by relying on this existing constraint /// path, this can easily end up hiding the actual reason for why we require these regions /// to be equal. /// diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 0af636aa734c..6aa3345d4d42 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries}; use rustc_infer::traits::ObligationCause; use rustc_macros::extension; -use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory}; +use rustc_middle::mir::{Body, ConstraintCategory, HiddenTypes}; use rustc_middle::ty::{ self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, @@ -129,9 +129,9 @@ fn nll_var_to_universal_region<'tcx>( /// Collect all defining uses of opaque types inside of this typeck root. This /// expects the hidden type to be mapped to the definition parameters of the opaque /// and errors if we end up with distinct hidden types. -fn add_concrete_opaque_type<'tcx>( +fn add_hidden_type<'tcx>( tcx: TyCtxt<'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut HiddenTypes<'tcx>, def_id: LocalDefId, hidden_ty: OpaqueHiddenType<'tcx>, ) { @@ -139,7 +139,7 @@ fn add_concrete_opaque_type<'tcx>( // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to // `(X, Y)` and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) { + if let Some(prev) = hidden_types.0.get_mut(&def_id) { if prev.ty != hidden_ty.ty { let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); @@ -151,15 +151,15 @@ fn add_concrete_opaque_type<'tcx>( // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. prev.span = prev.span.substitute_dummy(hidden_ty.span); } else { - concrete_opaque_types.0.insert(def_id, hidden_ty); + hidden_types.0.insert(def_id, hidden_ty); } } -fn get_concrete_opaque_type<'tcx>( - concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, +fn get_hidden_type<'tcx>( + hidden_types: &HiddenTypes<'tcx>, def_id: LocalDefId, ) -> Option>> { - concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) + hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) } #[derive(Debug)] @@ -173,22 +173,22 @@ struct DefiningUse<'tcx> { } /// This computes the actual hidden types of the opaque types and maps them to their -/// definition sites. Outside of registering the computed concrete types this function +/// definition sites. Outside of registering the computed hidden types this function /// does not mutate the current borrowck state. /// /// While it may fail to infer the hidden type and return errors, we always apply -/// the computed concrete hidden type to all opaque type uses to check whether they +/// the computed hidden type to all opaque type uses to check whether they /// are correct. This is necessary to support non-defining uses of opaques in their /// defining scope. /// /// It also means that this whole function is not really soundness critical as we /// recheck all uses of the opaques regardless. -pub(crate) fn compute_concrete_opaque_types<'tcx>( +pub(crate) fn compute_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, universal_region_relations: &Frozen>, constraints: &MirTypeckRegionConstraints<'tcx>, location_map: Rc, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut HiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec> { let mut errors = Vec::new(); @@ -201,8 +201,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>( // We start by checking each use of an opaque type during type check and // check whether the generic arguments of the opaque type are fully // universal, if so, it's a defining use. - let defining_uses = - collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors); + let defining_uses = collect_defining_uses(&mut rcx, hidden_types, opaque_types, &mut errors); // We now compute and apply member constraints for all regions in the hidden // types of each defining use. This mutates the region values of the `rcx` which @@ -210,21 +209,16 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>( apply_member_constraints(&mut rcx, &defining_uses); // After applying member constraints, we now check whether all member regions ended - // up equal to one of their choice regions and compute the actual concrete type of + // up equal to one of their choice regions and compute the actual hidden type of // the opaque type definition. This is stored in the `root_cx`. - compute_concrete_types_from_defining_uses( - &rcx, - concrete_opaque_types, - &defining_uses, - &mut errors, - ); + compute_hidden_types_from_defining_uses(&rcx, hidden_types, &defining_uses, &mut errors); errors } #[instrument(level = "debug", skip_all, ret)] fn collect_defining_uses<'tcx>( rcx: &mut RegionCtxt<'_, 'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut HiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], errors: &mut Vec>, ) -> Vec> { @@ -244,9 +238,9 @@ fn collect_defining_uses<'tcx>( // with `TypingMode::Borrowck`. if infcx.tcx.use_typing_mode_borrowck() { match err { - NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type( + NonDefiningUseReason::Tainted(guar) => add_hidden_type( infcx.tcx, - concrete_opaque_types, + hidden_types, opaque_type_key.def_id, OpaqueHiddenType::new_error(infcx.tcx, guar), ), @@ -277,9 +271,9 @@ fn collect_defining_uses<'tcx>( defining_uses } -fn compute_concrete_types_from_defining_uses<'tcx>( +fn compute_hidden_types_from_defining_uses<'tcx>( rcx: &RegionCtxt<'_, 'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut HiddenTypes<'tcx>, defining_uses: &[DefiningUse<'tcx>], errors: &mut Vec>, ) { @@ -358,9 +352,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>( }, )); } - add_concrete_opaque_type( + add_hidden_type( tcx, - concrete_opaque_types, + hidden_types, opaque_type_key.def_id, OpaqueHiddenType { span: hidden_type.span, ty }, ); @@ -489,20 +483,20 @@ impl<'tcx> FallibleTypeFolder> for ToArgRegionsFolder<'_, 'tcx> { /// /// It does this by equating the hidden type of each use with the instantiated final /// hidden type of the opaque. -pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( +pub(crate) fn apply_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, region_bound_pairs: &RegionBoundPairs<'tcx>, known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], constraints: &mut MirTypeckRegionConstraints<'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut HiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec> { let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else { + let Some(expected) = get_hidden_type(hidden_types, key.def_id) else { if !tcx.use_typing_mode_borrowck() { if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() && alias_ty.def_id == key.def_id.to_def_id() @@ -521,12 +515,7 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( hidden_type.span, "non-defining use in the defining scope with no defining uses", ); - add_concrete_opaque_type( - tcx, - concrete_opaque_types, - key.def_id, - OpaqueHiddenType::new_error(tcx, guar), - ); + add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar)); continue; }; @@ -566,18 +555,13 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( "equating opaque types", ), ) { - add_concrete_opaque_type( - tcx, - concrete_opaque_types, - key.def_id, - OpaqueHiddenType::new_error(tcx, guar), - ); + add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar)); } } errors } -/// In theory `apply_concrete_opaque_types` could introduce new uses of opaque types. +/// In theory `apply_hidden_types` could introduce new uses of opaque types. /// We do not check these new uses so this could be unsound. /// /// We detect any new uses and simply delay a bug if they occur. If this results in @@ -682,13 +666,6 @@ impl<'tcx> InferCtxt<'tcx> { /// /// (*) C1 and C2 were introduced in the comments on /// `register_member_constraints`. Read that comment for more context. - /// - /// # Parameters - /// - /// - `def_id`, the `impl Trait` type - /// - `args`, the args used to instantiate this opaque type - /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of - /// `opaque_defn.concrete_ty` #[instrument(level = "debug", skip(self))] fn infer_opaque_definition_from_instantiation( &self, diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index cd4e9683f2d8..d9599bbdd461 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -12,12 +12,12 @@ use smallvec::SmallVec; use crate::consumers::BorrowckConsumer; use crate::nll::compute_closure_requirements_modulo_opaques; use crate::region_infer::opaque_types::{ - apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types, - compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types, + apply_hidden_types, clone_and_resolve_opaque_types, compute_hidden_types, + detect_opaque_types_added_while_handling_opaque_types, }; use crate::type_check::{Locations, constraint_conversion}; use crate::{ - ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes, + ClosureRegionRequirements, CollectRegionConstraintsResult, HiddenTypes, PropagatedBorrowCheckResults, borrowck_check_region_constraints, borrowck_collect_region_constraints, }; @@ -27,7 +27,7 @@ use crate::{ pub(super) struct BorrowCheckRootCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, root_def_id: LocalDefId, - concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, + hidden_types: HiddenTypes<'tcx>, /// The region constraints computed by [borrowck_collect_region_constraints]. This uses /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before /// their parents. @@ -49,7 +49,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { BorrowCheckRootCtxt { tcx, root_def_id, - concrete_opaque_types: Default::default(), + hidden_types: Default::default(), collect_region_constraints_results: Default::default(), propagated_borrowck_results: Default::default(), tainted_by_errors: None, @@ -72,11 +72,11 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars } - pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + pub(super) fn finalize(self) -> Result<&'tcx HiddenTypes<'tcx>, ErrorGuaranteed> { if let Some(guar) = self.tainted_by_errors { Err(guar) } else { - Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + Ok(self.tcx.arena.alloc(self.hidden_types)) } } @@ -88,12 +88,12 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &input.universal_region_relations, &mut input.constraints, ); - input.deferred_opaque_type_errors = compute_concrete_opaque_types( + input.deferred_opaque_type_errors = compute_hidden_types( &input.infcx, &input.universal_region_relations, &input.constraints, Rc::clone(&input.location_map), - &mut self.concrete_opaque_types, + &mut self.hidden_types, &opaque_types, ); per_body_info.push((num_entries, opaque_types)); @@ -103,14 +103,14 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.collect_region_constraints_results.values_mut().zip(per_body_info) { if input.deferred_opaque_type_errors.is_empty() { - input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types( + input.deferred_opaque_type_errors = apply_hidden_types( &input.infcx, &input.body_owned, &input.universal_region_relations.universal_regions, &input.region_bound_pairs, &input.known_type_outlives_obligations, &mut input.constraints, - &mut self.concrete_opaque_types, + &mut self.hidden_types, &opaque_types, ); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 886ebddc75c9..e1e6860e4300 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -219,7 +219,7 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! + // Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it! // See https://github.com/rust-lang/rust/issues/75100 if tcx.sess.opts.actually_rustdoc { return; @@ -252,7 +252,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>( Ok(()) } -/// Check that the concrete type behind `impl Trait` actually implements `Trait`. +/// Check that the hidden type behind `impl Trait` actually implements `Trait`. /// /// This is mostly checked at the places that specify the opaque type, but we /// check those cases in the `param_env` of that function, which may have diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index b6d898886ac4..a02990fe4aba 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -177,7 +177,7 @@ impl<'tcx> TaitConstraintLocator<'tcx> { let tables = tcx.typeck(item_def_id); if let Some(guar) = tables.tainted_by_errors { self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)); - } else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) { + } else if let Some(&hidden_type) = tables.hidden_types.get(&self.def_id) { self.insert_found(hidden_type); } else { self.non_defining_use_in_defining_scope(item_def_id); @@ -185,8 +185,8 @@ impl<'tcx> TaitConstraintLocator<'tcx> { } DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) { Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)), - Ok(concrete_opaque_types) => { - if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) { + Ok(hidden_types) => { + if let Some(&hidden_type) = hidden_types.0.get(&self.def_id) { debug!(?hidden_type, "found constraint"); self.insert_found(hidden_type); } else if let Err(guar) = tcx @@ -247,7 +247,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( let tables = tcx.typeck(owner_def_id); if let Some(guar) = tables.tainted_by_errors { Ty::new_error(tcx, guar) - } else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) { + } else if let Some(hidden_ty) = tables.hidden_types.get(&def_id) { hidden_ty.ty } else { assert!(!tcx.next_trait_solver_globally()); @@ -261,8 +261,8 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( } } DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) { - Ok(concrete_opaque_types) => { - if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) { + Ok(hidden_types) => { + if let Some(hidden_ty) = hidden_types.0.get(&def_id) { hidden_ty.ty } else { let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity(); diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 5cefa506b5a0..a47fa202acfe 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -15,7 +15,7 @@ use crate::FnCtxt; impl<'tcx> FnCtxt<'_, 'tcx> { /// This takes all the opaque type uses during HIR typeck. It first computes - /// the concrete hidden type by iterating over all defining uses. + /// the hidden type by iterating over all defining uses. /// /// A use during HIR typeck is defining if all non-lifetime arguments are /// unique generic parameters and the hidden type does not reference any @@ -35,8 +35,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } debug!(?opaque_types); - self.compute_concrete_opaque_types(&opaque_types); - self.apply_computed_concrete_opaque_types(&opaque_types); + self.compute_hidden_types(&opaque_types); + self.apply_hidden_types(&opaque_types); } } @@ -71,7 +71,7 @@ impl<'tcx> UsageKind<'tcx> { } impl<'tcx> FnCtxt<'_, 'tcx> { - fn compute_concrete_opaque_types( + fn compute_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { @@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.typeck_results .borrow_mut() - .concrete_opaque_types + .hidden_types .insert(def_id, OpaqueHiddenType::new_error(tcx, guar)); self.set_tainted_by_errors(guar); } @@ -161,7 +161,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { match err { NonDefiningUseReason::Tainted(guar) => { - self.typeck_results.borrow_mut().concrete_opaque_types.insert( + self.typeck_results.borrow_mut().hidden_types.insert( opaque_type_key.def_id, OpaqueHiddenType::new_error(self.tcx, guar), ); @@ -197,20 +197,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let prev = self .typeck_results .borrow_mut() - .concrete_opaque_types + .hidden_types .insert(opaque_type_key.def_id, hidden_type); assert!(prev.is_none()); UsageKind::HasDefiningUse } - fn apply_computed_concrete_opaque_types( + fn apply_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { let tcx = self.tcx; for &(key, hidden_type) in opaque_types { - let expected = - *self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap(); + let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap(); let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d01eeb9a4b69..697029e55f7c 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -550,13 +550,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_opaque_types_next(&mut self) { let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() { + for hidden_ty in fcx_typeck_results.hidden_types.values() { assert!(!hidden_ty.has_infer()); } - assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0); - self.typeck_results.concrete_opaque_types = - mem::take(&mut fcx_typeck_results.concrete_opaque_types); + assert_eq!(self.typeck_results.hidden_types.len(), 0); + self.typeck_results.hidden_types = mem::take(&mut fcx_typeck_results.hidden_types); } #[instrument(skip(self), level = "debug")] @@ -588,7 +587,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hidden_type.span, DefiningScopeKind::HirTypeck, ) { - self.typeck_results.concrete_opaque_types.insert( + self.typeck_results.hidden_types.insert( opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)), ); @@ -600,16 +599,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { DefiningScopeKind::HirTypeck, ); - if let Some(prev) = self - .typeck_results - .concrete_opaque_types - .insert(opaque_type_key.def_id, hidden_type) + if let Some(prev) = + self.typeck_results.hidden_types.insert(opaque_type_key.def_id, hidden_type) { - let entry = &mut self - .typeck_results - .concrete_opaque_types - .get_mut(&opaque_type_key.def_id) - .unwrap(); + let entry = + &mut self.typeck_results.hidden_types.get_mut(&opaque_type_key.def_id).unwrap(); if prev.ty != hidden_type.ty { if let Some(guar) = self.typeck_results.tainted_by_errors { entry.ty = Ty::new_error(tcx, guar); @@ -628,7 +622,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let recursive_opaques: Vec<_> = self .typeck_results - .concrete_opaque_types + .hidden_types .iter() .filter(|&(&def_id, hidden_ty)| { hidden_ty @@ -636,7 +630,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .visit_with(&mut HasRecursiveOpaque { def_id, seen: Default::default(), - opaques: &self.typeck_results.concrete_opaque_types, + opaques: &self.typeck_results.hidden_types, tcx, }) .is_break() @@ -651,7 +645,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .with_code(E0720) .emit(); self.typeck_results - .concrete_opaque_types + .hidden_types .insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) }); } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index fa6a2db38ef9..a63030b11452 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,7 +27,7 @@ macro_rules! arena_types { rustc_middle::mir::Body<'tcx> >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, - [decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>, + [decode] borrowck_result: rustc_middle::mir::HiddenTypes<'tcx>, [] resolver: rustc_data_structures::steal::Steal<( rustc_middle::ty::ResolverAstLowering, std::sync::Arc, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a509c40c89cd..791565e387e8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -84,11 +84,10 @@ impl Debug for CoroutineLayout<'_> { } } -/// All the opaque types that are restricted to concrete types -/// by this function. Unlike the value in `TypeckResults`, this has -/// unerased regions. +/// All the opaque types that have had their hidden type fully computed. +/// Unlike the value in `TypeckResults`, this has unerased regions. #[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap>); +pub struct HiddenTypes<'tcx>(pub FxIndexMap>); /// The result of the `mir_const_qualif` query. /// diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 326df9239aa0..1efb29c788d4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1244,7 +1244,7 @@ rustc_queries! { /// Borrow-checks the given typeck root, e.g. functions, const/static items, /// and its children, e.g. closures, inline consts. - query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::HiddenTypes<'tcx>, ErrorGuaranteed> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 8dd80aab946d..944bd9756a95 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -167,7 +167,7 @@ pub struct TypeckResults<'tcx> { /// We also store the type here, so that the compiler can use it as a hint /// for figuring out hidden types, even if they are only set in dead code /// (which doesn't show up in MIR). - pub concrete_opaque_types: FxIndexMap>, + pub hidden_types: FxIndexMap>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -250,7 +250,7 @@ impl<'tcx> TypeckResults<'tcx> { coercion_casts: Default::default(), used_trait_imports: Default::default(), tainted_by_errors: None, - concrete_opaque_types: Default::default(), + hidden_types: Default::default(), closure_min_captures: Default::default(), closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d9f8085083eb..0652461e9750 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -120,7 +120,7 @@ impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> { impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Type inference occasionally gives us opaque types in places where corresponding patterns /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited - /// types, we use the corresponding concrete type if possible. + /// types, we use the corresponding hidden type if possible. // FIXME(#132279): This will be unnecessary once we have a TypingMode which supports revealing // opaque types defined in a body. #[inline] @@ -146,7 +146,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// know it. fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option> { self.typeck_results - .concrete_opaque_types + .hidden_types .get(&key.def_id) .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1dd31990ab73..fb4f28412d42 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2359,7 +2359,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { if self.infcx.can_define_opaque_ty(def_id) { unreachable!() } else { - // We can resolve the `impl Trait` to its concrete type, + // We can resolve the opaque type to its hidden type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index f743b84bce68..feafcee7bad9 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -80,7 +80,7 @@ pub enum TypingMode { /// the old solver as well. PostBorrowckAnalysis { defined_opaque_types: I::LocalDefIds }, /// After analysis, mostly during codegen and MIR optimizations, we're able to - /// reveal all opaque types. As the concrete type should *never* be observable + /// reveal all opaque types. As the hidden type should *never* be observable /// directly by the user, this should not be used by checks which may expose /// such details to the user. /// From 3a20a4d0a5463edb5fca2adfbe0522042a9ce752 Mon Sep 17 00:00:00 2001 From: Sebastian Speitel Date: Sun, 28 Sep 2025 00:51:57 +0200 Subject: [PATCH 363/537] Fix typo --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a45edd08e8cc..25a4661a0bc9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -3234,7 +3234,7 @@ fn inlined_slow_read_byte(reader: &mut R) -> Option> { } } -// Used by `BufReader::spec_read_byte`, for which the `inline(ever)` is +// Used by `BufReader::spec_read_byte`, for which the `inline(never)` is // important. #[inline(never)] fn uninlined_slow_read_byte(reader: &mut R) -> Option> { From fdacc0cf5f11769427cb86c3133051314f9e8485 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 28 Sep 2025 08:41:15 +0800 Subject: [PATCH 364/537] Add `all` `any` and `not` attribute completions Example --- `#[cfg($0)]` -> `#[cfg(any($0))]` --- .../src/completions/attribute/cfg.rs | 30 +++++++++++++---- .../ide-completion/src/tests/attribute.rs | 32 +++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index 1676a8467c85..b2e8efde8beb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -53,15 +53,33 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { acc.add(item.build(ctx.db)); }), }, - None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { - let s = s.as_str(); - let item = - CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition); - acc.add(item.build(ctx.db)); - }), + None => ctx + .krate + .potential_cfg(ctx.db) + .get_cfg_keys() + .unique() + .map(|s| (s.as_str(), "")) + .chain(CFG_CONDITION.iter().copied()) + .for_each(|(s, snippet)| { + let mut item = CompletionItem::new( + SymbolKind::BuiltinAttr, + ctx.source_range(), + s, + ctx.edition, + ); + if let Some(cap) = ctx.config.snippet_cap + && !snippet.is_empty() + { + item.insert_snippet(cap, snippet); + } + acc.add(item.build(ctx.db)); + }), } } +const CFG_CONDITION: &[(&str, &str)] = + &[("all", "all($0)"), ("any", "any($0)"), ("not", "not($0)")]; + const KNOWN_ARCH: [&str; 20] = [ "aarch64", "arm", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 30e1e108c6c4..1d2a9c7c8d3c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -815,7 +815,10 @@ mod cfg { #[cfg($0)] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -827,7 +830,10 @@ mod cfg { #[cfg(b$0)] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -843,7 +849,10 @@ mod cfg { #[cfg_attr($0)] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -855,7 +864,10 @@ mod cfg { #[cfg_attr(b$0)] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -867,7 +879,10 @@ mod cfg { #[cfg_attr($0, allow(deprecated))] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -879,7 +894,10 @@ mod cfg { #[cfg_attr(b$0, allow(deprecated))] "#, expect![[r#" + ba all + ba any ba dbg + ba not ba opt_level ba test ba true @@ -904,6 +922,20 @@ mod cfg { "#]], ); } + + #[test] + fn inside_conditional() { + check_edit( + "all", + r#" +//- /main.rs cfg:test,dbg=false,opt_level=2 +#[cfg($0)] +"#, + r#" +#[cfg(all($0))] +"#, + ); + } } mod derive { From c1259aa26fead9a9d365c4436d5ceb00cad88bbe Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 28 Aug 2025 23:31:46 +0800 Subject: [PATCH 365/537] Add LSX accelerated implementation for source file analysis This patch introduces an LSX-optimized version of `analyze_source_file` for the `loongarch64` target. Similar to existing SSE2 implementation for x86, this version: - Processes 16-byte chunks at a time using LSX vector intrinsics. - Quickly identifies newlines in ASCII-only chunks. - Falls back to the generic implementation when multi-byte UTF-8 characters are detected or in the tail portion. --- .../rustc_span/src/analyze_source_file.rs | 109 +++++++++++++++++- compiler/rustc_span/src/lib.rs | 1 + 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index c32593a6d95a..bb2cda77dfff 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -81,8 +81,8 @@ cfg_select! { // use `loadu`, which supports unaligned loading. let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) }; - // For character in the chunk, see if its byte value is < 0, which - // indicates that it's part of a UTF-8 char. + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. let multibyte_mask = _mm_movemask_epi8(multibyte_test); @@ -132,8 +132,111 @@ cfg_select! { } } } + target_arch = "loongarch64" => { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + ) { + use std::arch::is_loongarch_feature_detected; + + if is_loongarch_feature_detected!("lsx") { + unsafe { + analyze_source_file_lsx(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + ); + } + } + + /// Checks 16 byte chunks of text at a time. If the chunk contains + /// something other than printable ASCII characters and newlines, the + /// function falls back to the generic implementation. Otherwise it uses + /// LSX intrinsics to quickly find all newlines. + #[target_feature(enable = "lsx")] + unsafe fn analyze_source_file_lsx( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut Vec, + ) { + use std::arch::loongarch64::*; + + const CHUNK_SIZE: usize = 16; + + let (chunks, tail) = src.as_bytes().as_chunks::(); + + // This variable keeps track of where we should start decoding a + // chunk. If a multi-byte character spans across chunk boundaries, + // we need to skip that part in the next chunk because we already + // handled it. + let mut intra_chunk_offset = 0; + + for (chunk_index, chunk) in chunks.iter().enumerate() { + // All LSX memory instructions support unaligned access, so using + // vld is fine. + let chunk = unsafe { lsx_vld::<0>(chunk.as_ptr() as *const i8) }; + + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. + let multibyte_mask = lsx_vmskltz_b(chunk); + // Create a bit mask from the comparison results. + let multibyte_mask = lsx_vpickve2gr_w::<0>(multibyte_mask); + + // If the bit mask is all zero, we only have ASCII chars here: + if multibyte_mask == 0 { + assert!(intra_chunk_offset == 0); + + // Check for newlines in the chunk + let newlines_test = lsx_vseqi_b::<{b'\n' as i32}>(chunk); + let newlines_mask = lsx_vmskltz_b(newlines_test); + let mut newlines_mask = lsx_vpickve2gr_w::<0>(newlines_mask); + + let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); + + while newlines_mask != 0 { + let index = newlines_mask.trailing_zeros(); + + lines.push(RelativeBytePos(index) + output_offset); + + // Clear the bit, so we can find the next one. + newlines_mask &= newlines_mask - 1; + } + } else { + // The slow path. + // There are multibyte chars in here, fallback to generic decoding. + let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; + intra_chunk_offset = analyze_source_file_generic( + &src[scan_start..], + CHUNK_SIZE - intra_chunk_offset, + RelativeBytePos::from_usize(scan_start), + lines, + multi_byte_chars, + ); + } + } + + // There might still be a tail left to analyze + let tail_start = src.len() - tail.len() + intra_chunk_offset; + if tail_start < src.len() { + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + ); + } + } + } _ => { - // The target (or compiler version) does not support SSE2 ... + // The target (or compiler version) does not support vector instructions + // our specialized implementations need (x86 SSE2, loongarch64 LSX)... fn analyze_source_file_dispatch( src: &str, lines: &mut Vec, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 35dbbe58db9a..ededbea57e96 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,6 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] From 0d658fe156c077e0f37068d5788f6c375d555b54 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Sun, 28 Sep 2025 00:55:47 +0100 Subject: [PATCH 366/537] test: add `keyword/soup.rs` --- tests/ui/keyword/soup.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ui/keyword/soup.rs diff --git a/tests/ui/keyword/soup.rs b/tests/ui/keyword/soup.rs new file mode 100644 index 000000000000..c4dbe3fb4834 --- /dev/null +++ b/tests/ui/keyword/soup.rs @@ -0,0 +1,30 @@ +//@ edition:2024 +//@ check-pass + +#![allow(unused_imports)] +#![allow(missing_abi)] +#![allow(unused_macros)] +#![allow(non_camel_case_types)] +#![allow(unreachable_code)] +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +// all 48 keywords in 300 characters +mod x { + pub(super) struct X; + use Ok; + impl X { + pub(in crate) async fn x(self: Self, x: &'static &'_ dyn for<> Fn()) where { + unsafe extern { safe fn x(); } + macro_rules! x { () => {}; } + if 'x: loop { + return match while let true = break 'x false { continue } { + ref x => { &raw mut x; async { const { enum A {} } }.await as () }, + }; + } { type x = X; } else { move || { trait x { } union B { x: () } }; } + } + } +} + +fn main() {} From b3f3e36c72952736be5b9e0360ee5b86148f2c29 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 27 Sep 2025 20:00:54 -0700 Subject: [PATCH 367/537] compiler: remove AbiAlign inside TargetDataLayout This maintains AbiAlign usage in public API and most of the compiler, but direct access of these fields is now in terms of Align only. --- compiler/rustc_abi/src/callconv/reg.rs | 22 ++--- compiler/rustc_abi/src/layout.rs | 65 +++++++------- compiler/rustc_abi/src/layout/simple.rs | 27 +++--- compiler/rustc_abi/src/lib.rs | 85 +++++++++---------- compiler/rustc_codegen_llvm/src/consts.rs | 4 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 8 +- compiler/rustc_session/src/config/cfg.rs | 10 +-- compiler/rustc_target/src/callconv/mips.rs | 2 +- compiler/rustc_target/src/callconv/mips64.rs | 4 +- compiler/rustc_target/src/callconv/mod.rs | 2 +- compiler/rustc_target/src/callconv/sparc.rs | 2 +- compiler/rustc_target/src/callconv/sparc64.rs | 2 +- 13 files changed, 115 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs index 8cf140dbaad4..66c8056d0c2a 100644 --- a/compiler/rustc_abi/src/callconv/reg.rs +++ b/compiler/rustc_abi/src/callconv/reg.rs @@ -42,22 +42,22 @@ impl Reg { let dl = cx.data_layout(); match self.kind { RegKind::Integer => match self.size.bits() { - 1 => dl.i1_align.abi, - 2..=8 => dl.i8_align.abi, - 9..=16 => dl.i16_align.abi, - 17..=32 => dl.i32_align.abi, - 33..=64 => dl.i64_align.abi, - 65..=128 => dl.i128_align.abi, + 1 => dl.i1_align, + 2..=8 => dl.i8_align, + 9..=16 => dl.i16_align, + 17..=32 => dl.i32_align, + 33..=64 => dl.i64_align, + 65..=128 => dl.i128_align, _ => panic!("unsupported integer: {self:?}"), }, RegKind::Float => match self.size.bits() { - 16 => dl.f16_align.abi, - 32 => dl.f32_align.abi, - 64 => dl.f64_align.abi, - 128 => dl.f128_align.abi, + 16 => dl.f16_align, + 32 => dl.f32_align, + 64 => dl.f64_align, + 128 => dl.f128_align, _ => panic!("unsupported float: {self:?}"), }, - RegKind::Vector => dl.llvmlike_vector_align(self.size).abi, + RegKind::Vector => dl.llvmlike_vector_align(self.size), } } } diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5004d0c80220..09b4322e299b 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -174,11 +174,11 @@ impl LayoutCalculator { // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. - (BackendRepr::Memory { sized: true }, AbiAlign { abi: Align::max_aligned_factor(size) }) + (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) } else { (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) }; - let size = size.align_to(align.abi); + let size = size.align_to(align); Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, @@ -190,7 +190,7 @@ impl LayoutCalculator { largest_niche: elt.largest_niche, uninhabited: false, size, - align, + align: AbiAlign::new(align), max_repr_align: None, unadjusted_abi_align: elt.align.abi, randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), @@ -388,7 +388,7 @@ impl LayoutCalculator { return Err(LayoutCalculatorError::UnexpectedUnsized(*field)); } - align = align.max(field.align); + align = align.max(field.align.abi); max_repr_align = max_repr_align.max(field.max_repr_align); size = cmp::max(size, field.size); @@ -423,13 +423,13 @@ impl LayoutCalculator { } if let Some(pack) = repr.pack { - align = align.min(AbiAlign::new(pack)); + align = align.min(pack); } // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). // See documentation on `LayoutData::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; + let unadjusted_abi_align = align; if let Some(repr_align) = repr.align { - align = align.max(AbiAlign::new(repr_align)); + align = align.max(repr_align); } // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate. let align = align; @@ -441,14 +441,12 @@ impl LayoutCalculator { Ok(Some((repr, _))) => match repr { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _) - if repr.scalar_align(dl).unwrap() != align.abi => + if repr.scalar_align(dl).unwrap() != align => { BackendRepr::Memory { sized: true } } // Vectors require at least element alignment, else disable the opt - BackendRepr::SimdVector { element, count: _ } - if element.align(dl).abi > align.abi => - { + BackendRepr::SimdVector { element, count: _ } if element.align(dl).abi > align => { BackendRepr::Memory { sized: true } } // the alignment tests passed and we can use this @@ -474,8 +472,8 @@ impl LayoutCalculator { backend_repr, largest_niche: None, uninhabited: false, - align, - size: size.align_to(align.abi), + align: AbiAlign::new(align), + size: size.align_to(align), max_repr_align, unadjusted_abi_align, randomization_seed: combined_seed, @@ -611,7 +609,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; + let mut unadjusted_abi_align = align; let mut variant_layouts = variants .iter_enumerated() @@ -619,7 +617,7 @@ impl LayoutCalculator { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; st.variants = Variants::Single { index: j }; - align = align.max(st.align); + align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); @@ -646,7 +644,7 @@ impl LayoutCalculator { let (niche_start, niche_scalar) = niche.reserve(dl, count)?; let niche_offset = niche.offset; let niche_size = niche.value.size(dl); - let size = variant_layouts[largest_variant_index].size.align_to(align.abi); + let size = variant_layouts[largest_variant_index].size.align_to(align); let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { if i == largest_variant_index { @@ -699,7 +697,7 @@ impl LayoutCalculator { .iter_enumerated() .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); let same_size = size == variant_layouts[largest_variant_index].size; - let same_align = align == variant_layouts[largest_variant_index].align; + let same_align = align == variant_layouts[largest_variant_index].align.abi; let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited()); let abi = if same_size && same_align && others_zst { @@ -746,7 +744,7 @@ impl LayoutCalculator { largest_niche, uninhabited, size, - align, + align: AbiAlign::new(align), max_repr_align, unadjusted_abi_align, randomization_seed: combined_seed, @@ -818,7 +816,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; + let mut unadjusted_abi_align = align; let mut size = Size::ZERO; @@ -860,7 +858,7 @@ impl LayoutCalculator { } } size = cmp::max(size, st.size); - align = align.max(st.align); + align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Ok(st) @@ -868,7 +866,7 @@ impl LayoutCalculator { .collect::, _>>()?; // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); + size = size.align_to(align); // FIXME(oli-obk): deduplicate and harden these checks if size.bytes() >= dl.obj_size_bound() { @@ -1042,7 +1040,7 @@ impl LayoutCalculator { }; if pair_offsets[FieldIdx::new(0)] == Size::ZERO && pair_offsets[FieldIdx::new(1)] == *offset - && align == pair.align + && align == pair.align.abi && size == pair.size { // We can use `ScalarPair` only when it matches our @@ -1066,7 +1064,7 @@ impl LayoutCalculator { // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); - variant.align.abi = cmp::max(variant.align.abi, align.abi); + variant.align.abi = cmp::max(variant.align.abi, align); } } } @@ -1092,7 +1090,7 @@ impl LayoutCalculator { largest_niche, uninhabited, backend_repr: abi, - align, + align: AbiAlign::new(align), size, max_repr_align, unadjusted_abi_align, @@ -1288,7 +1286,7 @@ impl LayoutCalculator { if let StructKind::Prefixed(prefix_size, prefix_align) = kind { let prefix_align = if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAlign::new(prefix_align)); + align = align.max(prefix_align); offset = prefix_size.align_to(prefix_align); } for &i in &inverse_memory_index { @@ -1312,7 +1310,7 @@ impl LayoutCalculator { field.align }; offset = offset.align_to(field_align.abi); - align = align.max(field_align); + align = align.max(field_align.abi); max_repr_align = max_repr_align.max(field.max_repr_align); debug!("univariant offset: {:?} field: {:#?}", offset, field); @@ -1339,9 +1337,9 @@ impl LayoutCalculator { // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). // See documentation on `LayoutData::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; + let unadjusted_abi_align = align; if let Some(repr_align) = repr.align { - align = align.max(AbiAlign::new(repr_align)); + align = align.max(repr_align); } // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. let align = align; @@ -1360,7 +1358,7 @@ impl LayoutCalculator { debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); inverse_memory_index.into_iter().map(|it| it.index() as u32).collect() }; - let size = min_size.align_to(align.abi); + let size = min_size.align_to(align); // FIXME(oli-obk): deduplicate and harden these checks if size.bytes() >= dl.obj_size_bound() { return Err(LayoutCalculatorError::SizeOverflow); @@ -1383,8 +1381,7 @@ impl LayoutCalculator { layout_of_single_non_zst_field = Some(field); // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size - { + if offsets[i].bytes() == 0 && align == field.align.abi && size == field.size { match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. @@ -1428,7 +1425,7 @@ impl LayoutCalculator { }; if offsets[i] == pair_offsets[FieldIdx::new(0)] && offsets[j] == pair_offsets[FieldIdx::new(1)] - && align == pair.align + && align == pair.align.abi && size == pair.size { // We can use `ScalarPair` only when it matches our @@ -1450,7 +1447,7 @@ impl LayoutCalculator { Some(l) => l.unadjusted_abi_align, None => { // `repr(transparent)` with all ZST fields. - align.abi + align } } } else { @@ -1465,7 +1462,7 @@ impl LayoutCalculator { backend_repr: abi, largest_niche, uninhabited, - align, + align: AbiAlign::new(align), size, max_repr_align, unadjusted_abi_align, diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 0d0706defc2e..b3807c872739 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -4,7 +4,8 @@ use rustc_hashes::Hash64; use rustc_index::{Idx, IndexVec}; use crate::{ - BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants, + AbiAlign, BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, + Variants, }; /// "Simple" layout constructors that cannot fail. @@ -20,10 +21,10 @@ impl LayoutData { backend_repr: BackendRepr::Memory { sized }, largest_niche: None, uninhabited: false, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::new(0), } } @@ -37,10 +38,10 @@ impl LayoutData { backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, uninhabited: true, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::ZERO, } } @@ -89,10 +90,10 @@ impl LayoutData { pub fn scalar_pair(cx: &C, a: Scalar, b: Scalar) -> Self { let dl = cx.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); + let b_align = b.align(dl).abi; + let align = a.align(dl).abi.max(b_align).max(dl.aggregate_align); + let b_offset = a.size(dl).align_to(b_align); + let size = (b_offset + b.size(dl)).align_to(align); // HACK(nox): We iter on `b` and then `a` because `max_by_key` // returns the last maximum. @@ -112,10 +113,10 @@ impl LayoutData { backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, uninhabited: false, - align, + align: AbiAlign::new(align), size, max_repr_align: None, - unadjusted_abi_align: align.abi, + unadjusted_abi_align: align, randomization_seed: Hash64::new(combined_seed), } } @@ -138,10 +139,10 @@ impl LayoutData { backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, uninhabited: true, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::ZERO, } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 369874521e57..fe7148d1d572 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -229,7 +229,7 @@ pub struct PointerSpec { /// The size of the bitwise representation of the pointer. pointer_size: Size, /// The alignment of pointers for this address space - pointer_align: AbiAlign, + pointer_align: Align, /// The size of the value a pointer can be offset by in this address space. pointer_offset: Size, /// Pointers into this address space contain extra metadata @@ -242,20 +242,20 @@ pub struct PointerSpec { #[derive(Debug, PartialEq, Eq)] pub struct TargetDataLayout { pub endian: Endian, - pub i1_align: AbiAlign, - pub i8_align: AbiAlign, - pub i16_align: AbiAlign, - pub i32_align: AbiAlign, - pub i64_align: AbiAlign, - pub i128_align: AbiAlign, - pub f16_align: AbiAlign, - pub f32_align: AbiAlign, - pub f64_align: AbiAlign, - pub f128_align: AbiAlign, - pub aggregate_align: AbiAlign, + pub i1_align: Align, + pub i8_align: Align, + pub i16_align: Align, + pub i32_align: Align, + pub i64_align: Align, + pub i128_align: Align, + pub f16_align: Align, + pub f32_align: Align, + pub f64_align: Align, + pub f128_align: Align, + pub aggregate_align: Align, /// Alignments for vector types. - pub vector_align: Vec<(Size, AbiAlign)>, + pub vector_align: Vec<(Size, Align)>, pub default_address_space: AddressSpace, pub default_address_space_pointer_spec: PointerSpec, @@ -282,25 +282,25 @@ impl Default for TargetDataLayout { let align = |bits| Align::from_bits(bits).unwrap(); TargetDataLayout { endian: Endian::Big, - i1_align: AbiAlign::new(align(8)), - i8_align: AbiAlign::new(align(8)), - i16_align: AbiAlign::new(align(16)), - i32_align: AbiAlign::new(align(32)), - i64_align: AbiAlign::new(align(32)), - i128_align: AbiAlign::new(align(32)), - f16_align: AbiAlign::new(align(16)), - f32_align: AbiAlign::new(align(32)), - f64_align: AbiAlign::new(align(64)), - f128_align: AbiAlign::new(align(128)), - aggregate_align: AbiAlign { abi: align(8) }, + i1_align: align(8), + i8_align: align(8), + i16_align: align(16), + i32_align: align(32), + i64_align: align(32), + i128_align: align(32), + f16_align: align(16), + f32_align: align(32), + f64_align: align(64), + f128_align: align(128), + aggregate_align: align(8), vector_align: vec![ - (Size::from_bits(64), AbiAlign::new(align(64))), - (Size::from_bits(128), AbiAlign::new(align(128))), + (Size::from_bits(64), align(64)), + (Size::from_bits(128), align(128)), ], default_address_space: AddressSpace::ZERO, default_address_space_pointer_spec: PointerSpec { pointer_size: Size::from_bits(64), - pointer_align: AbiAlign::new(align(64)), + pointer_align: align(64), pointer_offset: Size::from_bits(64), _is_fat: false, }, @@ -360,7 +360,7 @@ impl TargetDataLayout { .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err }) }; let abi = parse_bits(s, "alignment", cause)?; - Ok(AbiAlign::new(align_from_bits(abi)?)) + Ok(align_from_bits(abi)?) }; // Parse an alignment sequence, possibly in the form `[:]`, @@ -596,7 +596,7 @@ impl TargetDataLayout { /// psABI-mandated alignment for a vector type, if any #[inline] - fn cabi_vector_align(&self, vec_size: Size) -> Option { + fn cabi_vector_align(&self, vec_size: Size) -> Option { self.vector_align .iter() .find(|(size, _align)| *size == vec_size) @@ -605,10 +605,9 @@ impl TargetDataLayout { /// an alignment resembling the one LLVM would pick for a vector #[inline] - pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAlign { - self.cabi_vector_align(vec_size).unwrap_or(AbiAlign::new( - Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(), - )) + pub fn llvmlike_vector_align(&self, vec_size: Size) -> Align { + self.cabi_vector_align(vec_size) + .unwrap_or(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap()) } /// Get the pointer size in the default data address space. @@ -654,21 +653,19 @@ impl TargetDataLayout { /// Get the pointer alignment in the default data address space. #[inline] pub fn pointer_align(&self) -> AbiAlign { - self.default_address_space_pointer_spec.pointer_align + AbiAlign::new(self.default_address_space_pointer_spec.pointer_align) } /// Get the pointer alignment in a specific address space. #[inline] pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign { - if c == self.default_address_space { - return self.default_address_space_pointer_spec.pointer_align; - } - - if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { + AbiAlign::new(if c == self.default_address_space { + self.default_address_space_pointer_spec.pointer_align + } else if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { e.1.pointer_align } else { panic!("Use of unknown address space {c:?}"); - } + }) } } @@ -1185,13 +1182,13 @@ impl Integer { use Integer::*; let dl = cx.data_layout(); - match self { + AbiAlign::new(match self { I8 => dl.i8_align, I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, I128 => dl.i128_align, - } + }) } /// Returns the largest signed value that can be represented by this Integer. @@ -1311,12 +1308,12 @@ impl Float { use Float::*; let dl = cx.data_layout(); - match self { + AbiAlign::new(match self { F16 => dl.f16_align, F32 => dl.f32_align, F64 => dl.f64_align, F128 => dl.f128_align, - } + }) } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a110ecbb75d9..40375ef65109 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -564,7 +564,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.define_global(&sym, llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); - set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi); + set_global_alignment(self, g, self.tcx.data_layout.i8_align); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); llvm::set_section(g, c"__TEXT,__cstring,cstring_literals"); @@ -680,7 +680,7 @@ impl<'ll> CodegenCx<'ll, '_> { let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", methname_sym); }); - set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi); + set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align); llvm::set_initializer(methname_g, methname_llval); llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage); llvm::set_section( diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 50398a32142e..94a74e27bbcb 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1047,7 +1047,7 @@ fn codegen_emcc_try<'ll, 'tcx>( // create an alloca and pass a pointer to that. let ptr_size = bx.tcx().data_layout.pointer_size(); let ptr_align = bx.tcx().data_layout.pointer_align().abi; - let i8_align = bx.tcx().data_layout.i8_align.abi; + let i8_align = bx.tcx().data_layout.i8_align; // Required in order for there to be no padding between the fields. assert!(i8_align <= ptr_align); let catch_data = bx.alloca(2 * ptr_size, ptr_align); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ab08125217ff..4d6fc3e19c5c 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -291,7 +291,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( bx.inbounds_ptradd(va_list_addr, bx.const_usize(1)) // fpr }; - let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align.abi); + let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align); // "Align" the register count when the type is passed as `i64`. if is_i64 || (is_f64 && is_soft_float_abi) { @@ -329,7 +329,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( // Increase the used-register count. let reg_incr = if is_i64 || (is_f64 && is_soft_float_abi) { 2 } else { 1 }; let new_num_regs = bx.add(num_regs, bx.cx.const_u8(reg_incr)); - bx.store(new_num_regs, num_regs_addr, dl.i8_align.abi); + bx.store(new_num_regs, num_regs_addr, dl.i8_align); bx.br(end); @@ -339,7 +339,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let mem_addr = { bx.switch_to_block(in_mem); - bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align.abi); + bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align); // Everything in the overflow area is rounded up to a size of at least 4. let overflow_area_align = Align::from_bytes(4).unwrap(); @@ -813,7 +813,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( let va_ndx_offset = va_reg_offset + 4; let offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_ndx_offset)); - let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi); + let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align); let offset = round_up_to_alignment(bx, offset, layout.align.abi); let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32; diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index f3d91ce4a5dd..a72f6201dcea 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -259,11 +259,11 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { }); let mut has_atomic = false; for (i, align) in [ - (8, layout.i8_align.abi), - (16, layout.i16_align.abi), - (32, layout.i32_align.abi), - (64, layout.i64_align.abi), - (128, layout.i128_align.abi), + (8, layout.i8_align), + (16, layout.i16_align), + (32, layout.i32_align), + (64, layout.i64_align), + (128, layout.i128_align), ] { if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { if !has_atomic { diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 48a01da865b7..8ffd7bd17784 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -24,7 +24,7 @@ where } let dl = cx.data_layout(); let size = arg.layout.size; - let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; + let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 0209838bec18..8386a15933c9 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -110,9 +110,9 @@ where // We only care about aligned doubles if let BackendRepr::Scalar(scalar) = field.backend_repr { if scalar.primitive() == Primitive::Float(Float::F64) { - if offset.is_aligned(dl.f64_align.abi) { + if offset.is_aligned(dl.f64_align) { // Insert enough integers to cover [last_offset, offset) - assert!(last_offset.is_aligned(dl.f64_align.abi)); + assert!(last_offset.is_aligned(dl.f64_align)); for _ in 0..((offset - last_offset).bits() / 64) .min((prefix.len() - prefix_index) as u64) { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 7a7c63c475b0..c59af581a1fe 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -332,7 +332,7 @@ impl CastTarget { self.prefix .iter() .filter_map(|x| x.map(|reg| reg.align(cx))) - .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| { + .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)), |acc, align| { acc.max(align) }) } diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 48a01da865b7..8ffd7bd17784 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -24,7 +24,7 @@ where } let dl = cx.data_layout(); let size = arg.layout.size; - let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; + let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index ecc9067ced35..62c8ed1dc21b 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -29,7 +29,7 @@ where data.has_float = true; - if !data.last_offset.is_aligned(dl.f64_align.abi) && data.last_offset < offset { + if !data.last_offset.is_aligned(dl.f64_align) && data.last_offset < offset { if data.prefix_index == data.prefix.len() { return data; } From cc7bd291cdd76f1e1ef83223ec7bec4077646ac7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Sep 2025 17:17:44 +1000 Subject: [PATCH 368/537] Fix change-tracker entry for 147046 --- src/bootstrap/src/utils/change_tracker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index f311c84bec9b..0123bd6340e5 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -557,7 +557,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.", }, ChangeInfo { - change_id: 99999, + change_id: 147046, severity: ChangeSeverity::Warning, summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.", }, From e99364ea357957b33460664fc496a3a8c218494e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 18:12:33 +1000 Subject: [PATCH 369/537] Remove old-output-capture from compiletest --- src/tools/compiletest/src/common.rs | 9 ------- src/tools/compiletest/src/executor.rs | 35 ++++++++------------------- src/tools/compiletest/src/lib.rs | 32 ------------------------ 3 files changed, 10 insertions(+), 66 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6da102b1b5f1..6d9599489180 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -661,18 +661,10 @@ pub struct Config { pub builtin_cfg_names: OnceLock>, pub supported_crate_types: OnceLock>, - /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely - /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement - /// `libtest`-esque `--no-capture`. - /// /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture` /// to avoid `!nocapture` double-negatives. pub nocapture: bool, - /// True if the experimental new output-capture implementation should be - /// used, avoiding the need for `#![feature(internal_output_capture)]`. - pub new_output_capture: bool, - /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, pub git_merge_commit_email: String, @@ -790,7 +782,6 @@ impl Config { builtin_cfg_names: Default::default(), supported_crate_types: Default::default(), nocapture: Default::default(), - new_output_capture: Default::default(), nightly_branch: Default::default(), git_merge_commit_email: Default::default(), profiler_runtime: Default::default(), diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index c8e13d445738..c7aca6d1c5aa 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -9,8 +9,8 @@ use std::borrow::Cow; use std::collections::HashMap; use std::hash::{BuildHasherDefault, DefaultHasher}; use std::num::NonZero; -use std::sync::{Arc, Mutex, mpsc}; -use std::{env, hint, io, mem, panic, thread}; +use std::sync::{Arc, mpsc}; +use std::{env, hint, mem, panic, thread}; use camino::Utf8PathBuf; @@ -130,10 +130,6 @@ fn run_test_inner( panic_hook::set_capture_buf(Default::default()); } - if let CaptureKind::Old { ref buf } = capture { - io::set_output_capture(Some(Arc::clone(buf))); - } - let stdout = capture.stdout(); let stderr = capture.stderr(); @@ -144,9 +140,6 @@ fn run_test_inner( // Forward any captured panic message to (captured) stderr. write!(stderr, "{panic_buf}"); } - if matches!(capture, CaptureKind::Old { .. }) { - io::set_output_capture(None); - } let outcome = match (should_panic, panic_payload) { (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, @@ -167,31 +160,24 @@ enum CaptureKind { /// runners, whose output is always captured.) None, - /// Use the old output-capture implementation, which relies on the unstable - /// library feature `#![feature(internal_output_capture)]`. - Old { buf: Arc>> }, - - /// Use the new output-capture implementation, which only uses stable Rust. - New { buf: output_capture::CaptureBuf }, + /// Capture all console output that would be printed by test runners via + /// their `stdout` and `stderr` trait objects, or via the custom panic hook. + Capture { buf: output_capture::CaptureBuf }, } impl CaptureKind { fn for_config(config: &Config) -> Self { if config.nocapture { Self::None - } else if config.new_output_capture { - Self::New { buf: output_capture::CaptureBuf::new() } } else { - // Create a capure buffer for `io::set_output_capture`. - Self::Old { buf: Default::default() } + Self::Capture { buf: output_capture::CaptureBuf::new() } } } fn should_set_panic_hook(&self) -> bool { match self { Self::None => false, - Self::Old { .. } => true, - Self::New { .. } => true, + Self::Capture { .. } => true, } } @@ -205,16 +191,15 @@ impl CaptureKind { fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut { match self { - Self::None | Self::Old { .. } => fallback, - Self::New { buf } => buf, + Self::None => fallback, + Self::Capture { buf } => buf, } } fn into_inner(self) -> Option> { match self { Self::None => None, - Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()), - Self::New { buf } => Some(buf.into_inner().into()), + Self::Capture { buf } => Some(buf.into_inner().into()), } } } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ce2a3d4b5fbb..15e31dadf971 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,9 +1,4 @@ #![crate_name = "compiletest"] -// Needed by the "new" test executor that does not depend on libtest. -// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`, -// by having `runtest` manually capture all of its println-like output instead. -// That would result in compiletest being written entirely in stable Rust! -#![feature(internal_output_capture)] #[cfg(test)] mod tests; @@ -178,12 +173,6 @@ pub fn parse_config(args: Vec) -> Config { // FIXME: Temporarily retained so we can point users to `--no-capture` .optflag("", "nocapture", "") .optflag("", "no-capture", "don't capture stdout/stderr of tests") - .optopt( - "N", - "new-output-capture", - "enables or disables the new output-capture implementation", - "off|on", - ) .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") @@ -480,14 +469,6 @@ pub fn parse_config(args: Vec) -> Config { supported_crate_types: OnceLock::new(), nocapture: matches.opt_present("no-capture"), - new_output_capture: { - let value = matches - .opt_str("new-output-capture") - .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok()) - .unwrap_or_else(|| "on".to_owned()); - parse_bool_option(&value) - .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given")) - }, nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), @@ -503,19 +484,6 @@ pub fn parse_config(args: Vec) -> Config { } } -/// Parses the same set of boolean values accepted by rustc command-line arguments. -/// -/// Accepting all of these values is more complicated than just picking one -/// pair, but has the advantage that contributors who are used to rustc -/// shouldn't have to think about which values are legal. -fn parse_bool_option(value: &str) -> Option { - match value { - "off" | "no" | "n" | "false" => Some(false), - "on" | "yes" | "y" | "true" => Some(true), - _ => None, - } -} - pub fn opt_str(maybestr: &Option) -> &str { match *maybestr { None => "(none)", From 7b8ae74da119e9ba025baeca60c22376f30d1307 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 21:38:11 +1000 Subject: [PATCH 370/537] Add a bootstrap snapshot test for `x test compiletest` --- src/bootstrap/src/core/builder/tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a3c8380a3c7d..66771fbf41c0 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2145,6 +2145,18 @@ mod snapshot { "); } + #[test] + fn test_compiletest_self_test() { + let ctx = TestCtx::new(); + let steps = ctx.config("test").arg("compiletest").render_steps(); + insta::assert_snapshot!(steps, @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + "); + } + #[test] fn test_compiletest_suites_stage1() { let ctx = TestCtx::new(); From 193f7179cca1c3b01eb7f2587616a95999e51903 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 18:22:56 +1000 Subject: [PATCH 371/537] Build and test compiletest as a stage0 bootstrap tool --- src/bootstrap/src/core/build_steps/check.rs | 11 +++----- src/bootstrap/src/core/build_steps/test.rs | 29 ++++++++++----------- src/bootstrap/src/core/build_steps/tool.rs | 18 +++---------- src/bootstrap/src/core/builder/tests.rs | 18 +------------ src/bootstrap/src/core/config/config.rs | 7 ++--- src/bootstrap/src/core/config/mod.rs | 10 +++++-- src/bootstrap/src/core/config/toml/build.rs | 2 ++ src/bootstrap/src/lib.rs | 4 +-- src/bootstrap/src/utils/change_tracker.rs | 5 ++++ 9 files changed, 40 insertions(+), 64 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 043457f64e57..27f259d42079 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -8,8 +8,8 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, - get_tool_target_compiler, prepare_tool_cargo, + SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler, + prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -825,12 +825,7 @@ tool_check_step!(CoverageDump { // so this is mainly for people working on compiletest to run locally. tool_check_step!(Compiletest { path: "src/tools/compiletest", - mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest { - Mode::ToolBootstrap - } else { - Mode::ToolStd - }, - allow_features: COMPILETEST_ALLOW_FEATURES, + mode: |_builder| Mode::ToolBootstrap, default: false, }); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ca2731819e7e..00aea8feab7d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -18,8 +18,8 @@ use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{ - self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType, - TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, + self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, + ToolTargetBuildMode, get_tool_target_compiler, }; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; @@ -36,7 +36,7 @@ use crate::utils::helpers::{ linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify}; +use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -786,26 +786,26 @@ impl Step for CompiletestTest { fn run(self, builder: &Builder<'_>) { let host = self.host; + // Now that compiletest uses only stable Rust, building it always uses + // the stage 0 compiler. However, some of its unit tests need to be able + // to query information from an in-tree compiler, so we treat `--stage` + // as selecting the stage of that secondary compiler. + if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 { eprintln!("\ -ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail +ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`." ); crate::exit!(1); } - let compiler = builder.compiler(builder.top_stage, host); - debug!(?compiler); + let bootstrap_compiler = builder.compiler(0, host); + let staged_compiler = builder.compiler(builder.top_stage, host); - // We need `ToolStd` for the locally-built sysroot because - // compiletest uses unstable features of the `test` crate. - builder.std(compiler, host); let mut cargo = tool::prepare_tool_cargo( builder, - compiler, - // compiletest uses libtest internals; make it use the in-tree std to make sure it never - // breaks when std sources change. - Mode::ToolStd, + bootstrap_compiler, + Mode::ToolBootstrap, host, Kind::Test, "src/tools/compiletest", @@ -816,9 +816,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this // right is important, as `compiletest` is intended to only support one target spec JSON // format, namely that of the staged compiler. - cargo.env("TEST_RUSTC", builder.rustc(compiler)); + cargo.env("TEST_RUSTC", builder.rustc(staged_compiler)); - cargo.allow_features(COMPILETEST_ALLOW_FEATURES); run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 4f096d50ea5c..819e903020c8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -380,7 +380,6 @@ macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr $(,is_external_tool = $external:expr)* - $(,is_unstable_tool = $unstable:expr)* $(,allow_features = $allow_features:expr)? $(,submodules = $submodules:expr)? $(,artifact_kind = $artifact_kind:expr)? @@ -438,19 +437,11 @@ macro_rules! bootstrap_tool { } )* - let is_unstable = false $(|| $unstable)*; - let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; - builder.ensure(ToolBuild { build_compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if is_unstable && !compiletest_wants_stage0 { - // use in-tree libraries for unstable features - Mode::ToolStd - } else { - Mode::ToolBootstrap - }, + mode: Mode::ToolBootstrap, path: $path, source_type: if false $(|| $external)* { SourceType::Submodule @@ -483,8 +474,6 @@ macro_rules! bootstrap_tool { } } -pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "internal_output_capture"; - bootstrap_tool!( // This is marked as an external tool because it includes dependencies // from submodules. Trying to keep the lints in sync between all the repos @@ -495,7 +484,7 @@ bootstrap_tool!( Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; CargoTest, "src/tools/cargotest", "cargotest"; - Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; + Compiletest, "src/tools/compiletest", "compiletest"; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RustInstaller, "src/tools/rust-installer", "rust-installer"; @@ -509,8 +498,7 @@ bootstrap_tool!( CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; - // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. - RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; + RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 66771fbf41c0..88df469e9a09 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2004,21 +2004,6 @@ mod snapshot { .render_steps(), @"[check] rustc 0 -> Compiletest 1 "); } - #[test] - fn check_compiletest_stage1_libtest() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiletest") - .args(&["--set", "build.compiletest-use-stage0-libtest=false"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> Compiletest 2 - "); - } - #[test] fn check_codegen() { let ctx = TestCtx::new(); @@ -2152,8 +2137,7 @@ mod snapshot { insta::assert_snapshot!(steps, @r" [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 + [build] rustdoc 0 "); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 271ce4cb950b..1fcc1174e856 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -310,9 +310,6 @@ pub struct Config { /// sources. pub compiletest_allow_stage0: bool, - /// Whether to use the precompiled stage0 libtest with compiletest. - pub compiletest_use_stage0_libtest: bool, - /// Default value for `--extra-checks` pub tidy_extra_checks: Option, pub is_running_on_ci: bool, @@ -497,7 +494,8 @@ impl Config { optimized_compiler_builtins: build_optimized_compiler_builtins, jobs: build_jobs, compiletest_diff_tool: build_compiletest_diff_tool, - compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest, + // No longer has any effect; kept (for now) to avoid breaking people's configs. + compiletest_use_stage0_libtest: _, tidy_extra_checks: build_tidy_extra_checks, ccache: build_ccache, exclude: build_exclude, @@ -1197,7 +1195,6 @@ impl Config { compiler_docs: build_compiler_docs.unwrap_or(false), compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), compiletest_diff_tool: build_compiletest_diff_tool, - compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), config: toml_path, configure_args: build_configure_args.unwrap_or_default(), control_flow_guard: rust_control_flow_guard.unwrap_or(false), diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 56b87823a365..007ed4aaba13 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -47,11 +47,17 @@ use crate::str::FromStr; #[macro_export] macro_rules! define_config { ($(#[$attr:meta])* struct $name:ident { - $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* + $( + $(#[$field_attr:meta])* + $field:ident: Option<$field_ty:ty> = $field_key:literal, + )* }) => { $(#[$attr])* pub struct $name { - $(pub $field: Option<$field_ty>,)* + $( + $(#[$field_attr])* + pub $field: Option<$field_ty>, + )* } impl Merge for $name { diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index a9d4d3961c9b..c63673dd9808 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -70,6 +70,8 @@ define_config! { jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", compiletest_allow_stage0: Option = "compiletest-allow-stage0", + /// No longer has any effect; kept (for now) to avoid breaking people's configs. + /// FIXME(#146929): Remove this in 2026. compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", tidy_extra_checks: Option = "tidy-extra-checks", ccache: Option = "ccache", diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d798639cc967..dd30f05b7283 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -327,8 +327,8 @@ pub enum Mode { ToolTarget, /// Build a tool which uses the locally built std, placing output in the - /// "stageN-tools" directory. Its usage is quite rare, mainly used by - /// compiletest which needs libtest. + /// "stageN-tools" directory. Its usage is quite rare; historically it was + /// needed by compiletest, but now it is mainly used by `test-float-parse`. ToolStd, /// Build a tool which uses the `rustc_private` mechanism, and thus diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 0123bd6340e5..853fc4e6623e 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -561,4 +561,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.", }, + ChangeInfo { + change_id: 146929, + severity: ChangeSeverity::Info, + summary: "`compiletest` is now always built with the stage 0 compiler, so `build.compiletest-use-stage0-libtest` has no effect.", + }, ]; From 8b1879864b4487c89ee414fa64abe42440fa922b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 22:05:12 +1000 Subject: [PATCH 372/537] `tool_check_step!` no longer needs a builder to determine mode --- src/bootstrap/src/core/build_steps/check.rs | 44 +++++++++------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 27f259d42079..20c54a28dda8 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -654,7 +654,7 @@ macro_rules! tool_check_step { // The part of this path after the final '/' is also used as a display name. path: $path:literal $(, alt_path: $alt_path:literal )* - // Closure that returns `Mode` based on the passed `&Builder<'_>` + // `Mode` to use when checking this tool , mode: $mode:expr // Subset of nightly features that are allowed to be used when checking $(, allow_features: $allow_features:expr )? @@ -682,8 +682,7 @@ macro_rules! tool_check_step { fn make_run(run: RunConfig<'_>) { let target = run.target; - let builder = run.builder; - let mode = $mode(builder); + let mode: Mode = $mode; let compiler = prepare_compiler_for_check(run.builder, target, mode); @@ -704,7 +703,7 @@ macro_rules! tool_check_step { _value }; let extra_features: &[&str] = &[$($($enable_features),*)?]; - let mode = $mode(builder); + let mode: Mode = $mode; run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features); } @@ -767,57 +766,50 @@ fn run_tool_check_step( tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc", - mode: |_builder| Mode::ToolRustcPrivate + mode: Mode::ToolRustcPrivate }); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate }); -tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate }); -tool_check_step!(CargoMiri { - path: "src/tools/miri/cargo-miri", - mode: |_builder| Mode::ToolRustcPrivate -}); -tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate }); +tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate }); +tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate }); +tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate }); +tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate }); tool_check_step!(RustAnalyzer { path: "src/tools/rust-analyzer", - mode: |_builder| Mode::ToolRustcPrivate, + mode: Mode::ToolRustcPrivate, allow_features: tool::RustAnalyzer::ALLOW_FEATURES, enable_features: ["in-rust-tree"], }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); // We want to test the local std tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse", - mode: |_builder| Mode::ToolStd, + mode: Mode::ToolStd, allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES }); tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); -tool_check_step!(Bootstrap { - path: "src/bootstrap", - mode: |_builder| Mode::ToolBootstrap, - default: false -}); +tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); tool_check_step!(CoverageDump { path: "src/tools/coverage-dump", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); @@ -825,18 +817,18 @@ tool_check_step!(CoverageDump { // so this is mainly for people working on compiletest to run locally. tool_check_step!(Compiletest { path: "src/tools/compiletest", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false, }); tool_check_step!(Linkchecker { path: "src/tools/linkchecker", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); tool_check_step!(BumpStage0 { path: "src/tools/bump-stage0", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); From 5e9cab39213b892fdb5eb24d2d27f1ab0918ce46 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 28 Sep 2025 09:46:20 +0100 Subject: [PATCH 373/537] modify ensure_version_or_cargo_install to check existing binary Current implementation uses bin_name to check if it exists, but it should use tool_root_dir/tool_bin_dir/bin_name instead. Otherwise the check fails every time, hence the function falls back to install the binary. --- src/tools/tidy/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 0bfee93796be..874a758bd9b3 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -167,12 +167,16 @@ pub fn ensure_version_or_cargo_install( bin_name: &str, version: &str, ) -> io::Result { + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); + // ignore the process exit code here and instead just let the version number check fail. // we also importantly don't return if the program wasn't installed, // instead we want to continue to the fallback. 'ck: { // FIXME: rewrite as if-let chain once this crate is 2024 edition. - let Ok(output) = Command::new(bin_name).arg("--version").output() else { + let Ok(output) = Command::new(&bin_path).arg("--version").output() else { break 'ck; }; let Ok(s) = str::from_utf8(&output.stdout) else { @@ -182,12 +186,10 @@ pub fn ensure_version_or_cargo_install( break 'ck; }; if v == version { - return Ok(PathBuf::from(bin_name)); + return Ok(bin_path); } } - let tool_root_dir = build_dir.join("misc-tools"); - let tool_bin_dir = tool_root_dir.join("bin"); eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); // use --force to ensure that if the required version is bumped, we update it. // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. @@ -213,7 +215,6 @@ pub fn ensure_version_or_cargo_install( if !cargo_exit_code.success() { return Err(io::Error::other("cargo install failed")); } - let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); assert!( matches!(bin_path.try_exists(), Ok(true)), "cargo install did not produce the expected binary" From 7a7cb05f11a81e261e22f9ae291755b6343f7095 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 27 Sep 2025 13:28:25 +0000 Subject: [PATCH 374/537] Do not validate MIR if code does not type-check. --- compiler/rustc_interface/src/passes.rs | 26 ++++++++++++++------------ tests/crashes/129095.rs | 13 ------------- tests/crashes/134174.rs | 17 ----------------- tests/crashes/134654.rs | 15 --------------- tests/crashes/135570.rs | 15 --------------- tests/crashes/136381.rs | 18 ------------------ tests/crashes/137190-1.rs | 10 ---------- tests/crashes/137468.rs | 16 ---------------- 8 files changed, 14 insertions(+), 116 deletions(-) delete mode 100644 tests/crashes/129095.rs delete mode 100644 tests/crashes/134174.rs delete mode 100644 tests/crashes/134654.rs delete mode 100644 tests/crashes/135570.rs delete mode 100644 tests/crashes/136381.rs delete mode 100644 tests/crashes/137190-1.rs delete mode 100644 tests/crashes/137468.rs diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 761a5c809182..c1bba0b01975 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1122,18 +1122,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); - - // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item - // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs - // in MIR optimizations that may only be reachable through codegen, or other codepaths - // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. - if tcx.sess.opts.unstable_opts.validate_mir { - sess.time("ensuring_final_MIR_is_computable", || { - tcx.par_hir_body_owners(|def_id| { - tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); - }); - }); - } } /// Runs the type-checking, region checking and other miscellaneous analysis @@ -1199,6 +1187,20 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally. let _ = tcx.all_diagnostic_items(()); }); + + // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item + // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs + // in MIR optimizations that may only be reachable through codegen, or other codepaths + // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. + // Nevertheless, wait after type checking is finished, as optimizing code that does not + // type-check is very prone to ICEs. + if tcx.sess.opts.unstable_opts.validate_mir { + sess.time("ensuring_final_MIR_is_computable", || { + tcx.par_hir_body_owners(|def_id| { + tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); + }); + }); + } } /// Runs the codegen backend, after which the AST and analysis can diff --git a/tests/crashes/129095.rs b/tests/crashes/129095.rs deleted file mode 100644 index b1bb74708c2d..000000000000 --- a/tests/crashes/129095.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: rust-lang/rust#129095 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -pub fn function_with_bytes() -> &'static [u8] { - BYTES -} - -pub fn main() { - assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); -} diff --git a/tests/crashes/134174.rs b/tests/crashes/134174.rs deleted file mode 100644 index 899cdc6faf35..000000000000 --- a/tests/crashes/134174.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #134175 -//@compile-flags: -Zvalidate-mir -Zinline-mir=yes -use std::vec::IntoIter; - -pub(crate) trait Foo: Iterator::Key> { - type Key; -} - -impl Foo for IntoIter {} - -fn sum_foo>(f: F) -> i32 { - f.fold(0, |a, b| a + b) -} - -fn main() { - let x = sum_foo(vec![11, 10, 1].into_iter()); -} diff --git a/tests/crashes/134654.rs b/tests/crashes/134654.rs deleted file mode 100644 index f2323fe4ecdc..000000000000 --- a/tests/crashes/134654.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #134654 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir -//@ only-x86_64 - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -fn function_with_bytes() -> &'static [u8] { - BYTES -} - -fn main() { - function_with_bytes::() == &[]; -} diff --git a/tests/crashes/135570.rs b/tests/crashes/135570.rs deleted file mode 100644 index 7919ceb26d50..000000000000 --- a/tests/crashes/135570.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #135570 -//@compile-flags: -Zvalidate-mir -Zmir-enable-passes=+Inline -Copt-level=0 -Zmir-enable-passes=+GVN -//@ only-x86_64 - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -fn function_with_bytes( -) -> &'static [u8] { - BYTES -} - -fn main() { - function_with_bytes::() == &[]; -} diff --git a/tests/crashes/136381.rs b/tests/crashes/136381.rs deleted file mode 100644 index 13ccc14a2c5b..000000000000 --- a/tests/crashes/136381.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #136381 -//@ compile-flags: -Zvalidate-mir -Zmir-enable-passes=+GVN -#![feature(trait_upcasting)] - -trait A {} -trait B: A { - fn c(&self); -} -impl B for i32 { - fn c(self) { - todo!(); - } -} - -fn main() { - let baz: &dyn B = &1; - let bar: &dyn A = baz; -} diff --git a/tests/crashes/137190-1.rs b/tests/crashes/137190-1.rs deleted file mode 100644 index bdfe883b7120..000000000000 --- a/tests/crashes/137190-1.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #137190 -//@ compile-flags: -Zmir-opt-level=2 -Zvalidate-mir -trait A { - fn b(&self); -} -trait C: A {} -impl C for () {} -fn main() { - (&() as &dyn C as &dyn A).b(); -} diff --git a/tests/crashes/137468.rs b/tests/crashes/137468.rs deleted file mode 100644 index cceb0502bd21..000000000000 --- a/tests/crashes/137468.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #137468 -//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+GVN -Zvalidate-mir -trait Supertrait {} - -trait Identity { - type Selff; -} - -trait Trait

: Supertrait<()> + Supertrait<

::Selff> {} - -impl

Trait

for () {} - -fn main() { - let x: &dyn Trait<()> = &(); - let x: &dyn Supertrait<()> = x; -} From 7fcbc5ea465a4e280d3b7a84fc3f781e9a120ed0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 28 Sep 2025 12:08:44 -0400 Subject: [PATCH 375/537] Add a leading dash to linker plugin arguments in the gcc codegen --- compiler/rustc_codegen_cranelift/src/lib.rs | 4 ++++ compiler/rustc_codegen_gcc/src/lib.rs | 4 ++++ compiler/rustc_codegen_llvm/src/lib.rs | 13 ++++++++++++- compiler/rustc_codegen_ssa/src/back/link.rs | 6 ++++++ compiler/rustc_codegen_ssa/src/back/linker.rs | 13 +++++++++++-- compiler/rustc_codegen_ssa/src/traits/backend.rs | 11 ++++++++++- .../codegen-backend/auxiliary/the_backend.rs | 4 ++++ 7 files changed, 51 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8e34436fb5e0..5fd7c4d4f41b 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -165,6 +165,10 @@ impl CodegenBackend for CraneliftCodegenBackend { "" } + fn name(&self) -> &'static str { + "cranelift" + } + fn init(&self, sess: &Session) { use rustc_session::config::{InstrumentCoverage, Lto}; match sess.lto() { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f76f933cad4a..ec7eab8489ab 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -184,6 +184,10 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "gcc" + } + fn init(&self, _sess: &Session) { #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 13bdb7cb1a27..e96eb304c50c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -231,6 +231,10 @@ impl CodegenBackend for LlvmCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "llvm" + } + fn init(&self, sess: &Session) { llvm_util::init(sess); // Make sure llvm is inited } @@ -349,7 +353,14 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &LlvmArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d6c304c1b147..db2f2dd65b0b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -79,6 +79,7 @@ pub fn link_binary( codegen_results: CodegenResults, metadata: EncodedMetadata, outputs: &OutputFilenames, + codegen_backend: &'static str, ) { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); @@ -154,6 +155,7 @@ pub fn link_binary( &codegen_results, &metadata, path.as_ref(), + codegen_backend, ); } } @@ -680,6 +682,7 @@ fn link_natively( codegen_results: &CodegenResults, metadata: &EncodedMetadata, tmpdir: &Path, + codegen_backend: &'static str, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); @@ -705,6 +708,7 @@ fn link_natively( codegen_results, metadata, self_contained_components, + codegen_backend, ); linker::disable_localization(&mut cmd); @@ -2208,6 +2212,7 @@ fn linker_with_args( codegen_results: &CodegenResults, metadata: &EncodedMetadata, self_contained_components: LinkSelfContainedComponents, + codegen_backend: &'static str, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( @@ -2216,6 +2221,7 @@ fn linker_with_args( flavor, self_contained_components.are_any_components_enabled(), &codegen_results.crate_info.target_cpu, + codegen_backend, ); let link_output_kind = link_output_kind(sess, crate_type); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 624ab1b50848..e644a43f8834 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -52,6 +52,7 @@ pub(crate) fn get_linker<'a>( flavor: LinkerFlavor, self_contained: bool, target_cpu: &'a str, + codegen_backend: &'static str, ) -> Box { let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe"); @@ -154,6 +155,7 @@ pub(crate) fn get_linker<'a>( is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), uses_lld: flavor.uses_lld(), + codegen_backend, }) as Box, LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box, LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box, @@ -367,6 +369,7 @@ struct GccLinker<'a> { is_ld: bool, is_gnu: bool, uses_lld: bool, + codegen_backend: &'static str, } impl<'a> GccLinker<'a> { @@ -423,9 +426,15 @@ impl<'a> GccLinker<'a> { if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; + let prefix = if self.codegen_backend == "gcc" { + // The GCC linker plugin requires a leading dash. + "-" + } else { + "" + }; self.link_args(&[ - &format!("-plugin-opt={opt_level}"), - &format!("-plugin-opt=mcpu={}", self.target_cpu), + &format!("-plugin-opt={prefix}{opt_level}"), + &format!("-plugin-opt={prefix}mcpu={}", self.target_cpu), ]); } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 29ec7eb1da3b..2400160075e2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -41,6 +41,8 @@ pub trait CodegenBackend { /// Called before `init` so that all other functions are able to emit translatable diagnostics. fn locale_resource(&self) -> &'static str; + fn name(&self) -> &'static str; + fn init(&self, _sess: &Session) {} fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} @@ -96,7 +98,14 @@ pub trait CodegenBackend { metadata: EncodedMetadata, outputs: &OutputFilenames, ) { - link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &ArArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 8449479287f0..48f328f4fad3 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -33,6 +33,10 @@ impl CodegenBackend for TheBackend { "" } + fn name(&self) -> &'static str { + "the-backend" + } + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { Box::new(CodegenResults { modules: vec![], From 599e8db8389111d5c27934c5294879d9caf262e1 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 27 Sep 2025 00:14:32 +0000 Subject: [PATCH 376/537] Use MirPatch in simplify_branches. --- compiler/rustc_mir_transform/src/patch.rs | 30 +++++++++++++++---- .../src/simplify_branches.rs | 19 +++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index d831ab50b1ac..cc8ea76011bf 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -11,6 +11,8 @@ use tracing::debug; /// once with `apply`. This is useful for MIR transformation passes. pub(crate) struct MirPatch<'tcx> { term_patch_map: FxHashMap>, + /// Set of statements that should be replaced by `Nop`. + nop_statements: Vec, new_blocks: Vec>, new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec>, @@ -33,6 +35,7 @@ impl<'tcx> MirPatch<'tcx> { pub(crate) fn new(body: &Body<'tcx>) -> Self { let mut result = MirPatch { term_patch_map: Default::default(), + nop_statements: vec![], new_blocks: vec![], new_statements: vec![], new_locals: vec![], @@ -212,6 +215,15 @@ impl<'tcx> MirPatch<'tcx> { self.term_patch_map.insert(block, new); } + /// Mark given statement to be replaced by a `Nop`. + /// + /// This method only works on statements from the initial body, and cannot be used to remove + /// statements from `add_statement` or `add_assign`. + #[tracing::instrument(level = "debug", skip(self))] + pub(crate) fn nop_statement(&mut self, loc: Location) { + self.nop_statements.push(loc); + } + /// Queues the insertion of a statement at a given location. The statement /// currently at that location, and all statements that follow, are shifted /// down. If multiple statements are queued for addition at the same @@ -257,11 +269,8 @@ impl<'tcx> MirPatch<'tcx> { bbs.extend(self.new_blocks); body.local_decls.extend(self.new_locals); - // The order in which we patch terminators does not change the result. - #[allow(rustc::potential_query_instability)] - for (src, patch) in self.term_patch_map { - debug!("MirPatch: patching block {:?}", src); - bbs[src].terminator_mut().kind = patch; + for loc in self.nop_statements { + bbs[loc.block].statements[loc.statement_index].make_nop(); } let mut new_statements = self.new_statements; @@ -285,6 +294,17 @@ impl<'tcx> MirPatch<'tcx> { .insert(loc.statement_index, Statement::new(source_info, stmt)); delta += 1; } + + // The order in which we patch terminators does not change the result. + #[allow(rustc::potential_query_instability)] + for (src, patch) in self.term_patch_map { + debug!("MirPatch: patching block {:?}", src); + let bb = &mut bbs[src]; + if let TerminatorKind::Unreachable = patch { + bb.statements.clear(); + } + bb.terminator_mut().kind = patch; + } } fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 886f4d6e5090..ed94a058ec6d 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -2,6 +2,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::trace; +use crate::patch::MirPatch; + pub(super) enum SimplifyConstCondition { AfterConstProp, Final, @@ -19,8 +21,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyConstCondition on {:?}", body.source); let typing_env = body.typing_env(tcx); - 'blocks: for block in body.basic_blocks_mut() { - for stmt in block.statements.iter_mut() { + let mut patch = MirPatch::new(body); + + 'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() { + for (statement_index, stmt) in block.statements.iter().enumerate() { // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic @@ -28,17 +32,16 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { - stmt.make_nop(); + patch.nop_statement(Location { block: bb, statement_index }); } else { - block.statements.clear(); - block.terminator_mut().kind = TerminatorKind::Unreachable; + patch.patch_terminator(bb, TerminatorKind::Unreachable); continue 'blocks; } } } - let terminator = block.terminator_mut(); - terminator.kind = match terminator.kind { + let terminator = block.terminator(); + let terminator = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { @@ -58,7 +61,9 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { }, _ => continue, }; + patch.patch_terminator(bb, terminator); } + patch.apply(body); } fn is_required(&self) -> bool { From 632f2cb8a47cc16d7e1e6231ac25ba4711c32be8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 28 Sep 2025 22:32:21 +0200 Subject: [PATCH 377/537] Remove one loop in `extract_cfg_from_attrs` --- src/librustdoc/clean/types.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c2cf39c4be06..d4f0a196eda8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1085,7 +1085,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator let mut changed_auto_active_status = None; // First we get all `doc(auto_cfg)` attributes. - for attr in attrs.clone() { + for attr in attrs { if let Some(ident) = attr.ident() && ident.name == sym::doc && let Some(attrs) = attr.meta_item_list() @@ -1146,13 +1146,9 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } } } - } - } - - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because - // `doc(cfg())` overrides `cfg()`). - for attr in attrs { - if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { + // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because + // `doc(cfg())` overrides `cfg()`). + } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well for (feature, _) in features { From c3e0b29e79f347edf7e0ae559bfec2d3cdf353d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 Aug 2025 19:35:22 +0000 Subject: [PATCH 378/537] Point at fn bound that introduced lifetime obligation ``` error[E0597]: `c` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:19:20 | LL | fn simple<'a>(x: &'a i32) { | -- lifetime `'a` defined here ... LL | let c = async move || { println!("{}", *x); }; | - binding `c` declared here LL | outlives::<'a>(c()); | ---------------^--- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | note: requirement that `c` is borrowed for `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} | ^^ ``` When encountering a `ConstraintCategory::Predicate` in a funtion call, point at the `Span` for that `Predicate` to explain where the lifetime obligation originates from. --- .../rustc_borrowck/src/borrowck_errors.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 9 +++ ...thout-precise-captures-we-are-powerless.rs | 14 +++++ ...t-precise-captures-we-are-powerless.stderr | 57 ++++++++++++++++++- ...ation-not-general-enough-ice-133252.stderr | 6 ++ .../precise-capturing/migration-note.rs | 2 + .../precise-capturing/migration-note.stderr | 54 +++++++++++------- ...er-to-static-comparing-against-free.stderr | 6 ++ .../propagate-multiple-requirements.stderr | 6 ++ .../nll/local-outlives-static-via-hrtb.stderr | 10 ++++ ...insensitive-scopes-issue-117146.nll.stderr | 5 ++ ...sitive-scopes-issue-117146.polonius.stderr | 5 ++ .../regions-infer-proc-static-upvar.stderr | 6 ++ .../regions-pattern-typing-issue-19552.stderr | 6 ++ tests/ui/static/static-lifetime-bound.stderr | 6 ++ 15 files changed, 170 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index c9be5575da5c..bc985cbe1335 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -426,7 +426,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { } pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> { - struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) + struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path) } pub(crate) fn cannot_return_reference_to_local( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7e20a5133e07..3b268f538cf2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3031,6 +3031,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let mut err = self.path_does_not_live_long_enough(borrow_span, &name); + if let BorrowExplanation::MustBeValidFor { ref path, region_name, .. } = explanation { + for constraint in path { + if let ConstraintCategory::Predicate(pred) = constraint.category + && !pred.is_dummy() + { + err.span_note(pred, format!("requirement that {name} is borrowed for `{region_name}` introduced here")); + } + } + } if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { let region_name = annotation.emit(self, &mut err); diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs index 19a31d1889b8..f97ec779b32c 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs @@ -44,4 +44,18 @@ fn through_field_and_ref_move<'a>(x: &S<'a>) { outlives::<'a>(call_once(c)); //~ ERROR explicit lifetime required in the type of `x` } +struct T; +impl T { + fn outlives<'a>(&'a self, _: impl Sized + 'a) {} +} +fn through_method<'a>(x: &'a i32) { + let c = async || { println!("{}", *x); }; //~ ERROR `x` does not live long enough + T.outlives::<'a>(c()); + T.outlives::<'a>(call_once(c)); + + let c = async move || { println!("{}", *x); }; + T.outlives::<'a>(c()); //~ ERROR `c` does not live long enough + T.outlives::<'a>(call_once(c)); +} + fn main() {} diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index b7259074bf64..e99ff763b9a2 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -28,6 +28,12 @@ LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed + | +note: requirement that `c` is borrowed for `'a` introduced here + --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 + | +LL | fn outlives<'a>(_: impl Sized + 'a) {} + | ^^ error[E0597]: `x` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:26:13 @@ -73,6 +79,12 @@ LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed + | +note: requirement that `c` is borrowed for `'a` introduced here + --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 + | +LL | fn outlives<'a>(_: impl Sized + 'a) {} + | ^^ error[E0505]: cannot move out of `c` because it is borrowed --> $DIR/without-precise-captures-we-are-powerless.rs:32:30 @@ -129,6 +141,12 @@ LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed + | +note: requirement that `c` is borrowed for `'a` introduced here + --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 + | +LL | fn outlives<'a>(_: impl Sized + 'a) {} + | ^^ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/without-precise-captures-we-are-powerless.rs:44:5 @@ -141,7 +159,44 @@ help: add explicit lifetime `'a` to the type of `x` LL | fn through_field_and_ref_move<'a>(x: &'a S<'a>) { | ++ -error: aborting due to 10 previous errors +error[E0597]: `x` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:52:13 + | +LL | fn through_method<'a>(x: &'a i32) { + | -- lifetime `'a` defined here +LL | let c = async || { println!("{}", *x); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | T.outlives::<'a>(c()); +LL | T.outlives::<'a>(call_once(c)); + | ------------------------------ argument requires that `x` is borrowed for `'a` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `c` does not live long enough + --> $DIR/without-precise-captures-we-are-powerless.rs:57:22 + | +LL | fn through_method<'a>(x: &'a i32) { + | -- lifetime `'a` defined here +... +LL | let c = async move || { println!("{}", *x); }; + | - binding `c` declared here +LL | T.outlives::<'a>(c()); + | -----------------^--- + | | | + | | borrowed value does not live long enough + | argument requires that `c` is borrowed for `'a` +LL | T.outlives::<'a>(call_once(c)); +LL | } + | - `c` dropped here while still borrowed + | +note: requirement that `c` is borrowed for `'a` introduced here + --> $DIR/without-precise-captures-we-are-powerless.rs:49:47 + | +LL | fn outlives<'a>(&'a self, _: impl Sized + 'a) {} + | ^^ + +error: aborting due to 12 previous errors Some errors have detailed explanations: E0505, E0597, E0621. For more information about an error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 5389226f7a7a..393f7b1a61df 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -22,6 +22,12 @@ LL | force_send(async_load(¬_static)); ... LL | } | - `not_static` dropped here while still borrowed + | +note: requirement that `not_static` is borrowed for `'1` introduced here + --> $DIR/implementation-not-general-enough-ice-133252.rs:16:18 + | +LL | fn force_send(_: T) {} + | ^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs index 7587e89409aa..25b594e9b1ec 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.rs +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -32,6 +32,7 @@ fn needs_static() { //~| NOTE borrowed value does not live long enoug fn needs_static(_: impl Sized + 'static) {} + //~^ NOTE requirement that `x` is borrowed for `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } @@ -79,6 +80,7 @@ fn needs_static_mut() { //~| NOTE borrowed value does not live long enough fn needs_static(_: impl Sized + 'static) {} + //~^ NOTE requirement that `x` is borrowed for `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index aa0f64000915..e42a6f15c7e5 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -1,5 +1,5 @@ error[E0597]: `x` does not live long enough - --> $DIR/migration-note.rs:182:17 + --> $DIR/migration-note.rs:184:17 | LL | let x = vec![0]; | - binding `x` declared here @@ -50,6 +50,11 @@ LL | LL | } | - `x` dropped here while still borrowed | +note: requirement that `x` is borrowed for `'static` introduced here + --> $DIR/migration-note.rs:34:37 + | +LL | fn needs_static(_: impl Sized + 'static) {} + | ^^^^^^^ note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:29:13 | @@ -61,7 +66,7 @@ LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/migration-note.rs:48:8 + --> $DIR/migration-note.rs:49:8 | LL | let x = vec![1]; | - binding `x` declared here @@ -76,7 +81,7 @@ LL | } | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:43:13 + --> $DIR/migration-note.rs:44:13 | LL | let a = display_len(&x); | ^^^^^^^^^^^^^^^ @@ -90,7 +95,7 @@ LL | let a = display_len(&x.clone()); | ++++++++ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/migration-note.rs:66:5 + --> $DIR/migration-note.rs:67:5 | LL | let a = display_len_mut(&mut x); | ------ first mutable borrow occurs here @@ -102,7 +107,7 @@ LL | println!("{a}"); | - first borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:63:13 + --> $DIR/migration-note.rs:64:13 | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +117,7 @@ LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { | ++++++++ error[E0597]: `x` does not live long enough - --> $DIR/migration-note.rs:76:29 + --> $DIR/migration-note.rs:77:29 | LL | let mut x = vec![1]; | ----- binding `x` declared here @@ -126,8 +131,13 @@ LL | LL | } | - `x` dropped here while still borrowed | +note: requirement that `x` is borrowed for `'static` introduced here + --> $DIR/migration-note.rs:82:37 + | +LL | fn needs_static(_: impl Sized + 'static) {} + | ^^^^^^^ note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:76:13 + --> $DIR/migration-note.rs:77:13 | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +147,7 @@ LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { | ++++++++ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/migration-note.rs:95:8 + --> $DIR/migration-note.rs:97:8 | LL | let mut x = vec![1]; | ----- binding `x` declared here @@ -152,7 +162,7 @@ LL | } | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:90:13 + --> $DIR/migration-note.rs:92:13 | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +176,7 @@ LL | let a = display_len_mut(&mut x.clone()); | ++++++++ error[E0506]: cannot assign to `s.f` because it is borrowed - --> $DIR/migration-note.rs:115:5 + --> $DIR/migration-note.rs:117:5 | LL | let a = display_field(&s.f); | ---- `s.f` is borrowed here @@ -178,7 +188,7 @@ LL | println!("{a}"); | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:112:13 + --> $DIR/migration-note.rs:114:13 | LL | let a = display_field(&s.f); | ^^^^^^^^^^^^^^^^^^^ @@ -188,7 +198,7 @@ LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ error[E0506]: cannot assign to `s.f` because it is borrowed - --> $DIR/migration-note.rs:131:5 + --> $DIR/migration-note.rs:133:5 | LL | let a = display_field(&mut s.f); | -------- `s.f` is borrowed here @@ -200,7 +210,7 @@ LL | println!("{a}"); | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:128:13 + --> $DIR/migration-note.rs:130:13 | LL | let a = display_field(&mut s.f); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +220,7 @@ LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ error[E0503]: cannot use `s.f` because it was mutably borrowed - --> $DIR/migration-note.rs:143:5 + --> $DIR/migration-note.rs:145:5 | LL | let a = display_field(&mut s.f); | -------- `s.f` is borrowed here @@ -222,7 +232,7 @@ LL | println!("{a}"); | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:140:13 + --> $DIR/migration-note.rs:142:13 | LL | let a = display_field(&mut s.f); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +242,7 @@ LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ error[E0597]: `z.f` does not live long enough - --> $DIR/migration-note.rs:159:25 + --> $DIR/migration-note.rs:161:25 | LL | let z = Z { f: vec![1] }; | - binding `z` declared here @@ -248,7 +258,7 @@ LL | } | = note: values in a scope are dropped in the opposite order they are defined note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:159:13 + --> $DIR/migration-note.rs:161:13 | LL | x = display_len(&z.f); | ^^^^^^^^^^^^^^^^^ @@ -258,7 +268,7 @@ LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ error[E0716]: temporary value dropped while borrowed - --> $DIR/migration-note.rs:170:40 + --> $DIR/migration-note.rs:172:40 | LL | let x = { let x = display_len(&mut vec![0]); x }; | ^^^^^^^ - - borrow later used here @@ -268,7 +278,7 @@ LL | let x = { let x = display_len(&mut vec![0]); x }; | = note: consider using a `let` binding to create a longer lived value note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:170:23 + --> $DIR/migration-note.rs:172:23 | LL | let x = { let x = display_len(&mut vec![0]); x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +289,7 @@ LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/migration-note.rs:198:10 + --> $DIR/migration-note.rs:200:10 | LL | let x = String::new(); | - binding `x` declared here @@ -294,12 +304,12 @@ LL | } | - borrow might be used here, when `y` is dropped and runs the destructor for type `impl Sized` | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules - --> $DIR/migration-note.rs:195:13 + --> $DIR/migration-note.rs:197:13 | LL | let y = capture_apit(&x); | ^^^^^^^^^^^^^^^^ note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable - --> $DIR/migration-note.rs:189:21 + --> $DIR/migration-note.rs:191:21 | LL | fn capture_apit(x: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index e13653f34234..136da57daec1 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -69,6 +69,12 @@ LL | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> LL | }) LL | } | - `a` dropped here while still borrowed + | +note: requirement that `a` is borrowed for `'static` introduced here + --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:13:8 + | +LL | F: for<'x> FnOnce(Cell<&'a u32>, Cell<&'x u32>), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 15f48d88c379..8e18f546ebd4 100644 --- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -13,6 +13,12 @@ LL | z = &local_arr; ... LL | } | - `local_arr` dropped here while still borrowed + | +note: requirement that `local_arr` is borrowed for `'static` introduced here + --> $DIR/propagate-multiple-requirements.rs:4:21 + | +LL | fn once U>(f: F, s: S, t: T) -> U { + | ^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index a98f11ce5136..cc01a3cfc0b9 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -12,6 +12,11 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | +note: requirement that `local` is borrowed for `'static` introduced here + --> $DIR/local-outlives-static-via-hrtb.rs:15:53 + | +LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} + | ^^^^^^^^^^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:15:42 | @@ -32,6 +37,11 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | +note: requirement that `local` is borrowed for `'static` introduced here + --> $DIR/local-outlives-static-via-hrtb.rs:19:30 + | +LL | for<'a> &'a T: Reference, + | ^^^^^^^^^^^^^^^^^^^^^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:19:5 | diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 6e47b8e59f5c..56ad78ba4b42 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -13,6 +13,11 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | +note: requirement that `a` is borrowed for `'static` introduced here + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 6e47b8e59f5c..56ad78ba4b42 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -13,6 +13,11 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | +note: requirement that `a` is borrowed for `'static` introduced here + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | diff --git a/tests/ui/regions/regions-infer-proc-static-upvar.stderr b/tests/ui/regions/regions-infer-proc-static-upvar.stderr index 919fcffdc531..1a76b5f00f94 100644 --- a/tests/ui/regions/regions-infer-proc-static-upvar.stderr +++ b/tests/ui/regions/regions-infer-proc-static-upvar.stderr @@ -11,6 +11,12 @@ LL | | }); | |______- argument requires that `x` is borrowed for `'static` LL | } | - `x` dropped here while still borrowed + | +note: requirement that `x` is borrowed for `'static` introduced here + --> $DIR/regions-infer-proc-static-upvar.rs:4:19 + | +LL | fn foo(_p: F) { } + | ^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr index 1d3d5e831c39..2c8ce20f09e4 100644 --- a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr +++ b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -10,6 +10,12 @@ LL | [ word ] => { assert_static(word); } LL | } LL | } | - `line` dropped here while still borrowed + | +note: requirement that `line` is borrowed for `'static` introduced here + --> $DIR/regions-pattern-typing-issue-19552.rs:1:21 + | +LL | fn assert_static(_t: T) {} + | ^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/static/static-lifetime-bound.stderr b/tests/ui/static/static-lifetime-bound.stderr index 8b0d3a0bf4cf..e530e4669d7f 100644 --- a/tests/ui/static/static-lifetime-bound.stderr +++ b/tests/ui/static/static-lifetime-bound.stderr @@ -10,6 +10,12 @@ LL | f(&x); | argument requires that `x` is borrowed for `'static` LL | } | - `x` dropped here while still borrowed + | +note: requirement that `x` is borrowed for `'static` introduced here + --> $DIR/static-lifetime-bound.rs:1:10 + | +LL | fn f<'a: 'static>(_: &'a i32) {} + | ^^^^^^^ error: aborting due to 1 previous error From 7a0319f01d08e541c8e16febaa68c5fa8b66b586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 Aug 2025 20:14:01 +0000 Subject: [PATCH 379/537] Point at lifetime requirement origin in more cases --- .../rustc_borrowck/src/borrowck_errors.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 17 +--------------- .../src/diagnostics/explain_borrow.rs | 13 ++++++++++++ ...t-precise-captures-we-are-powerless.stderr | 14 +++++++++---- .../borrowck/fn-item-check-type-params.stderr | 12 +++++++++++ ...ation-not-general-enough-ice-133252.stderr | 2 +- tests/ui/borrowck/issue-17545.stderr | 3 +++ .../bugs/hrtb-implied-1.stderr | 5 +++++ .../precise-capturing/migration-note.rs | 4 ++-- .../precise-capturing/migration-note.stderr | 4 ++-- ...er-to-static-comparing-against-free.stderr | 2 +- .../propagate-multiple-requirements.stderr | 2 +- .../nll/local-outlives-static-via-hrtb.stderr | 20 +++++++++---------- ...insensitive-scopes-issue-117146.nll.stderr | 10 +++++----- ...sitive-scopes-issue-117146.polonius.stderr | 10 +++++----- .../regions-infer-proc-static-upvar.stderr | 2 +- .../regions-pattern-typing-issue-19552.stderr | 2 +- tests/ui/static/static-lifetime-bound.stderr | 2 +- tests/ui/static/static-region-bound.stderr | 6 ++++++ .../wf-in-where-clause-static.current.stderr | 6 ++++++ .../wf/wf-in-where-clause-static.next.stderr | 6 ++++++ 21 files changed, 93 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index bc985cbe1335..7c9011505d64 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -480,7 +480,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { } pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> { - struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) + struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed") } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3b268f538cf2..efb622e2155c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2992,6 +2992,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.buffer_error(err); } + #[tracing::instrument(level = "debug", skip(self, explanation))] fn report_local_value_does_not_live_long_enough( &self, location: Location, @@ -3001,13 +3002,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - debug!( - "report_local_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - location, name, borrow, drop_span, borrow_spans - ); - let borrow_span = borrow_spans.var_or_use_path_span(); if let BorrowExplanation::MustBeValidFor { category, @@ -3031,15 +3025,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let mut err = self.path_does_not_live_long_enough(borrow_span, &name); - if let BorrowExplanation::MustBeValidFor { ref path, region_name, .. } = explanation { - for constraint in path { - if let ConstraintCategory::Predicate(pred) = constraint.category - && !pred.is_dummy() - { - err.span_note(pred, format!("requirement that {name} is borrowed for `{region_name}` introduced here")); - } - } - } if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { let region_name = annotation.emit(self, &mut err); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 7ca07bb9b434..a0ea8b085569 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -416,6 +416,19 @@ impl<'tcx> BorrowExplanation<'tcx> { { self.add_object_lifetime_default_note(tcx, err, unsize_ty); } + + for constraint in path { + if let ConstraintCategory::Predicate(pred) = constraint.category + && !pred.is_dummy() + { + err.span_note( + pred, + format!("requirement for `{region_name}` introduced here"), + ); + break; + } + } + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); } _ => {} diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index e99ff763b9a2..e0776c81dff3 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -29,7 +29,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement that `c` is borrowed for `'a` introduced here +note: requirement for `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -80,7 +80,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement that `c` is borrowed for `'a` introduced here +note: requirement for `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -101,6 +101,12 @@ LL | outlives::<'a>(c()); | argument requires that `c` is borrowed for `'a` LL | outlives::<'a>(call_once(c)); | ^ move out of `c` occurs here + | +note: requirement for `'a` introduced here + --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 + | +LL | fn outlives<'a>(_: impl Sized + 'a) {} + | ^^ error[E0597]: `x` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:36:13 @@ -142,7 +148,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement that `c` is borrowed for `'a` introduced here +note: requirement for `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -190,7 +196,7 @@ LL | T.outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement that `c` is borrowed for `'a` introduced here +note: requirement for `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:49:47 | LL | fn outlives<'a>(&'a self, _: impl Sized + 'a) {} diff --git a/tests/ui/borrowck/fn-item-check-type-params.stderr b/tests/ui/borrowck/fn-item-check-type-params.stderr index aafb7e66ef55..8da0201134b0 100644 --- a/tests/ui/borrowck/fn-item-check-type-params.stderr +++ b/tests/ui/borrowck/fn-item-check-type-params.stderr @@ -27,6 +27,12 @@ LL | want(&String::new(), extend_lt); | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` + | +note: requirement for `'static` introduced here + --> $DIR/fn-item-check-type-params.rs:47:33 + | +LL | fn want(_: I, _: impl Fn(I) -> O) {} + | ^^^^^^^^^^ error[E0716]: temporary value dropped while borrowed --> $DIR/fn-item-check-type-params.rs:54:26 @@ -36,6 +42,12 @@ LL | let val = extend_lt(&String::from("blah blah blah")); | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` + | +note: requirement for `'static` introduced here + --> $DIR/fn-item-check-type-params.rs:22:21 + | +LL | (T, Option): Displayable, + | ^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 393f7b1a61df..dab969586efd 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -23,7 +23,7 @@ LL | force_send(async_load(¬_static)); LL | } | - `not_static` dropped here while still borrowed | -note: requirement that `not_static` is borrowed for `'1` introduced here +note: requirement for `'1` introduced here --> $DIR/implementation-not-general-enough-ice-133252.rs:16:18 | LL | fn force_send(_: T) {} diff --git a/tests/ui/borrowck/issue-17545.stderr b/tests/ui/borrowck/issue-17545.stderr index 45e977e39477..dc0a84b0ab42 100644 --- a/tests/ui/borrowck/issue-17545.stderr +++ b/tests/ui/borrowck/issue-17545.stderr @@ -10,6 +10,9 @@ LL | | )); | | -- temporary value is freed at the end of this statement | |______| | argument requires that borrow lasts for `'a` + | +note: requirement for `'a` introduced here + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 8bb72833e301..72f9a477dafc 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -14,6 +14,11 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | for<'a> I::Item<'a>: Debug, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: requirement for `'static` introduced here + --> $DIR/hrtb-implied-1.rs:26:26 + | +LL | for<'a> I::Item<'a>: Debug, + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs index 25b594e9b1ec..211def333200 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.rs +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -32,7 +32,7 @@ fn needs_static() { //~| NOTE borrowed value does not live long enoug fn needs_static(_: impl Sized + 'static) {} - //~^ NOTE requirement that `x` is borrowed for `'static` introduced here + //~^ NOTE requirement for `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } @@ -80,7 +80,7 @@ fn needs_static_mut() { //~| NOTE borrowed value does not live long enough fn needs_static(_: impl Sized + 'static) {} - //~^ NOTE requirement that `x` is borrowed for `'static` introduced here + //~^ NOTE requirement for `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index e42a6f15c7e5..c06b14a41139 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -50,7 +50,7 @@ LL | LL | } | - `x` dropped here while still borrowed | -note: requirement that `x` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/migration-note.rs:34:37 | LL | fn needs_static(_: impl Sized + 'static) {} @@ -131,7 +131,7 @@ LL | LL | } | - `x` dropped here while still borrowed | -note: requirement that `x` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/migration-note.rs:82:37 | LL | fn needs_static(_: impl Sized + 'static) {} diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 136da57daec1..eb110e868aa5 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -70,7 +70,7 @@ LL | }) LL | } | - `a` dropped here while still borrowed | -note: requirement that `a` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:13:8 | LL | F: for<'x> FnOnce(Cell<&'a u32>, Cell<&'x u32>), diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 8e18f546ebd4..51e4d77c91a1 100644 --- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -14,7 +14,7 @@ LL | z = &local_arr; LL | } | - `local_arr` dropped here while still borrowed | -note: requirement that `local_arr` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/propagate-multiple-requirements.rs:4:21 | LL | fn once U>(f: F, s: S, t: T) -> U { diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index cc01a3cfc0b9..ff2be3a2b28e 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -12,16 +12,16 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | -note: requirement that `local` is borrowed for `'static` introduced here - --> $DIR/local-outlives-static-via-hrtb.rs:15:53 - | -LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} - | ^^^^^^^^^^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:15:42 | LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^ +note: requirement for `'static` introduced here + --> $DIR/local-outlives-static-via-hrtb.rs:15:53 + | +LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} + | ^^^^^^^^^^^^ error[E0597]: `local` does not live long enough --> $DIR/local-outlives-static-via-hrtb.rs:25:45 @@ -37,16 +37,16 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | -note: requirement that `local` is borrowed for `'static` introduced here - --> $DIR/local-outlives-static-via-hrtb.rs:19:30 - | -LL | for<'a> &'a T: Reference, - | ^^^^^^^^^^^^^^^^^^^^^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:19:5 | LL | for<'a> &'a T: Reference, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: requirement for `'static` introduced here + --> $DIR/local-outlives-static-via-hrtb.rs:19:30 + | +LL | for<'a> &'a T: Reference, + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 56ad78ba4b42..fdc3fc059c53 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -13,16 +13,16 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | -note: requirement that `a` is borrowed for `'static` introduced here - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 - | -LL | fn bad &()>(_: F) {} - | ^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} | ^^^^^^^^^^^^^^ +note: requirement for `'static` introduced here + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 56ad78ba4b42..fdc3fc059c53 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -13,16 +13,16 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | -note: requirement that `a` is borrowed for `'static` introduced here - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 - | -LL | fn bad &()>(_: F) {} - | ^^^ note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} | ^^^^^^^^^^^^^^ +note: requirement for `'static` introduced here + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + | +LL | fn bad &()>(_: F) {} + | ^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 diff --git a/tests/ui/regions/regions-infer-proc-static-upvar.stderr b/tests/ui/regions/regions-infer-proc-static-upvar.stderr index 1a76b5f00f94..ff833de0ad01 100644 --- a/tests/ui/regions/regions-infer-proc-static-upvar.stderr +++ b/tests/ui/regions/regions-infer-proc-static-upvar.stderr @@ -12,7 +12,7 @@ LL | | }); LL | } | - `x` dropped here while still borrowed | -note: requirement that `x` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/regions-infer-proc-static-upvar.rs:4:19 | LL | fn foo(_p: F) { } diff --git a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr index 2c8ce20f09e4..76cd18dfa132 100644 --- a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr +++ b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -11,7 +11,7 @@ LL | } LL | } | - `line` dropped here while still borrowed | -note: requirement that `line` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/regions-pattern-typing-issue-19552.rs:1:21 | LL | fn assert_static(_t: T) {} diff --git a/tests/ui/static/static-lifetime-bound.stderr b/tests/ui/static/static-lifetime-bound.stderr index e530e4669d7f..354a1327beea 100644 --- a/tests/ui/static/static-lifetime-bound.stderr +++ b/tests/ui/static/static-lifetime-bound.stderr @@ -11,7 +11,7 @@ LL | f(&x); LL | } | - `x` dropped here while still borrowed | -note: requirement that `x` is borrowed for `'static` introduced here +note: requirement for `'static` introduced here --> $DIR/static-lifetime-bound.rs:1:10 | LL | fn f<'a: 'static>(_: &'a i32) {} diff --git a/tests/ui/static/static-region-bound.stderr b/tests/ui/static/static-region-bound.stderr index a47c94571022..e7747216a57b 100644 --- a/tests/ui/static/static-region-bound.stderr +++ b/tests/ui/static/static-region-bound.stderr @@ -7,6 +7,12 @@ LL | f(x); | ---- argument requires that borrow lasts for `'static` LL | } | - temporary value is freed at the end of this statement + | +note: requirement for `'static` introduced here + --> $DIR/static-region-bound.rs:3:8 + | +LL | fn f(_: T) {} + | ^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-in-where-clause-static.current.stderr b/tests/ui/wf/wf-in-where-clause-static.current.stderr index d0bb89884c68..53cc6093f540 100644 --- a/tests/ui/wf/wf-in-where-clause-static.current.stderr +++ b/tests/ui/wf/wf-in-where-clause-static.current.stderr @@ -6,6 +6,12 @@ LL | let s = foo(&String::from("blah blah blah")); | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` + | +note: requirement for `'static` introduced here + --> $DIR/wf-in-where-clause-static.rs:12:17 + | +LL | &'static S: Static, + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-in-where-clause-static.next.stderr b/tests/ui/wf/wf-in-where-clause-static.next.stderr index d0bb89884c68..53cc6093f540 100644 --- a/tests/ui/wf/wf-in-where-clause-static.next.stderr +++ b/tests/ui/wf/wf-in-where-clause-static.next.stderr @@ -6,6 +6,12 @@ LL | let s = foo(&String::from("blah blah blah")); | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` + | +note: requirement for `'static` introduced here + --> $DIR/wf-in-where-clause-static.rs:12:17 + | +LL | &'static S: Static, + | ^^^^^^ error: aborting due to 1 previous error From 4973903cd204dd2cd36e15267de72ed6d954e3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 31 Aug 2025 20:42:01 +0000 Subject: [PATCH 380/537] reword note --- .../rustc_borrowck/src/diagnostics/explain_borrow.rs | 2 +- .../without-precise-captures-we-are-powerless.stderr | 10 +++++----- tests/ui/borrowck/fn-item-check-type-params.stderr | 4 ++-- ...implementation-not-general-enough-ice-133252.stderr | 2 +- tests/ui/borrowck/issue-17545.stderr | 2 +- .../bugs/hrtb-implied-1.stderr | 2 +- .../ui/impl-trait/precise-capturing/migration-note.rs | 4 ++-- .../impl-trait/precise-capturing/migration-note.stderr | 4 ++-- ...ted-shorter-to-static-comparing-against-free.stderr | 2 +- .../propagate-multiple-requirements.stderr | 2 +- tests/ui/nll/local-outlives-static-via-hrtb.stderr | 4 ++-- ...location-insensitive-scopes-issue-117146.nll.stderr | 2 +- ...ion-insensitive-scopes-issue-117146.polonius.stderr | 2 +- .../ui/regions/regions-infer-proc-static-upvar.stderr | 2 +- .../regions/regions-pattern-typing-issue-19552.stderr | 2 +- tests/ui/static/static-lifetime-bound.stderr | 2 +- tests/ui/static/static-region-bound.stderr | 2 +- tests/ui/wf/wf-in-where-clause-static.current.stderr | 2 +- tests/ui/wf/wf-in-where-clause-static.next.stderr | 2 +- 19 files changed, 27 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index a0ea8b085569..66c43a07c80c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -423,7 +423,7 @@ impl<'tcx> BorrowExplanation<'tcx> { { err.span_note( pred, - format!("requirement for `{region_name}` introduced here"), + format!("requirement that the value outlives `{region_name}` introduced here"), ); break; } diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index e0776c81dff3..4aae9807dd2e 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -29,7 +29,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -80,7 +80,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -102,7 +102,7 @@ LL | outlives::<'a>(c()); LL | outlives::<'a>(call_once(c)); | ^ move out of `c` occurs here | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -148,7 +148,7 @@ LL | outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:7:33 | LL | fn outlives<'a>(_: impl Sized + 'a) {} @@ -196,7 +196,7 @@ LL | T.outlives::<'a>(call_once(c)); LL | } | - `c` dropped here while still borrowed | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $DIR/without-precise-captures-we-are-powerless.rs:49:47 | LL | fn outlives<'a>(&'a self, _: impl Sized + 'a) {} diff --git a/tests/ui/borrowck/fn-item-check-type-params.stderr b/tests/ui/borrowck/fn-item-check-type-params.stderr index 8da0201134b0..7a0a7752a14b 100644 --- a/tests/ui/borrowck/fn-item-check-type-params.stderr +++ b/tests/ui/borrowck/fn-item-check-type-params.stderr @@ -28,7 +28,7 @@ LL | want(&String::new(), extend_lt); | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/fn-item-check-type-params.rs:47:33 | LL | fn want(_: I, _: impl Fn(I) -> O) {} @@ -43,7 +43,7 @@ LL | let val = extend_lt(&String::from("blah blah blah")); | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/fn-item-check-type-params.rs:22:21 | LL | (T, Option): Displayable, diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index dab969586efd..7b840d54ed03 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -23,7 +23,7 @@ LL | force_send(async_load(¬_static)); LL | } | - `not_static` dropped here while still borrowed | -note: requirement for `'1` introduced here +note: requirement that the value outlives `'1` introduced here --> $DIR/implementation-not-general-enough-ice-133252.rs:16:18 | LL | fn force_send(_: T) {} diff --git a/tests/ui/borrowck/issue-17545.stderr b/tests/ui/borrowck/issue-17545.stderr index dc0a84b0ab42..63fd57cd2336 100644 --- a/tests/ui/borrowck/issue-17545.stderr +++ b/tests/ui/borrowck/issue-17545.stderr @@ -11,7 +11,7 @@ LL | | )); | |______| | argument requires that borrow lasts for `'a` | -note: requirement for `'a` introduced here +note: requirement that the value outlives `'a` introduced here --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 72f9a477dafc..77a637c470cc 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -14,7 +14,7 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | for<'a> I::Item<'a>: Debug, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/hrtb-implied-1.rs:26:26 | LL | for<'a> I::Item<'a>: Debug, diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs index 211def333200..412d8af98845 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.rs +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -32,7 +32,7 @@ fn needs_static() { //~| NOTE borrowed value does not live long enoug fn needs_static(_: impl Sized + 'static) {} - //~^ NOTE requirement for `'static` introduced here + //~^ NOTE requirement that the value outlives `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } @@ -80,7 +80,7 @@ fn needs_static_mut() { //~| NOTE borrowed value does not live long enough fn needs_static(_: impl Sized + 'static) {} - //~^ NOTE requirement for `'static` introduced here + //~^ NOTE requirement that the value outlives `'static` introduced here needs_static(a); //~^ NOTE argument requires that `x` is borrowed for `'static` } diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index c06b14a41139..880e7878477a 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -50,7 +50,7 @@ LL | LL | } | - `x` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/migration-note.rs:34:37 | LL | fn needs_static(_: impl Sized + 'static) {} @@ -131,7 +131,7 @@ LL | LL | } | - `x` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/migration-note.rs:82:37 | LL | fn needs_static(_: impl Sized + 'static) {} diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index eb110e868aa5..af07745a00af 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -70,7 +70,7 @@ LL | }) LL | } | - `a` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:13:8 | LL | F: for<'x> FnOnce(Cell<&'a u32>, Cell<&'x u32>), diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr index 51e4d77c91a1..4136ac418deb 100644 --- a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr +++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -14,7 +14,7 @@ LL | z = &local_arr; LL | } | - `local_arr` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/propagate-multiple-requirements.rs:4:21 | LL | fn once U>(f: F, s: S, t: T) -> U { diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index ff2be3a2b28e..263d271b6b3d 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -17,7 +17,7 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^ -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/local-outlives-static-via-hrtb.rs:15:53 | LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} @@ -42,7 +42,7 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | for<'a> &'a T: Reference, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/local-outlives-static-via-hrtb.rs:19:30 | LL | for<'a> &'a T: Reference, diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index fdc3fc059c53..804b3f00a264 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -18,7 +18,7 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | fn bad &()>(_: F) {} | ^^^^^^^^^^^^^^ -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 | LL | fn bad &()>(_: F) {} diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index fdc3fc059c53..804b3f00a264 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -18,7 +18,7 @@ note: due to a current limitation of the type system, this implies a `'static` l | LL | fn bad &()>(_: F) {} | ^^^^^^^^^^^^^^ -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 | LL | fn bad &()>(_: F) {} diff --git a/tests/ui/regions/regions-infer-proc-static-upvar.stderr b/tests/ui/regions/regions-infer-proc-static-upvar.stderr index ff833de0ad01..158d74ed06d9 100644 --- a/tests/ui/regions/regions-infer-proc-static-upvar.stderr +++ b/tests/ui/regions/regions-infer-proc-static-upvar.stderr @@ -12,7 +12,7 @@ LL | | }); LL | } | - `x` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/regions-infer-proc-static-upvar.rs:4:19 | LL | fn foo(_p: F) { } diff --git a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr index 76cd18dfa132..a8fd827bc695 100644 --- a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr +++ b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -11,7 +11,7 @@ LL | } LL | } | - `line` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/regions-pattern-typing-issue-19552.rs:1:21 | LL | fn assert_static(_t: T) {} diff --git a/tests/ui/static/static-lifetime-bound.stderr b/tests/ui/static/static-lifetime-bound.stderr index 354a1327beea..51be79be5db8 100644 --- a/tests/ui/static/static-lifetime-bound.stderr +++ b/tests/ui/static/static-lifetime-bound.stderr @@ -11,7 +11,7 @@ LL | f(&x); LL | } | - `x` dropped here while still borrowed | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/static-lifetime-bound.rs:1:10 | LL | fn f<'a: 'static>(_: &'a i32) {} diff --git a/tests/ui/static/static-region-bound.stderr b/tests/ui/static/static-region-bound.stderr index e7747216a57b..8472738daa49 100644 --- a/tests/ui/static/static-region-bound.stderr +++ b/tests/ui/static/static-region-bound.stderr @@ -8,7 +8,7 @@ LL | f(x); LL | } | - temporary value is freed at the end of this statement | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/static-region-bound.rs:3:8 | LL | fn f(_: T) {} diff --git a/tests/ui/wf/wf-in-where-clause-static.current.stderr b/tests/ui/wf/wf-in-where-clause-static.current.stderr index 53cc6093f540..788fe2c3faa0 100644 --- a/tests/ui/wf/wf-in-where-clause-static.current.stderr +++ b/tests/ui/wf/wf-in-where-clause-static.current.stderr @@ -7,7 +7,7 @@ LL | let s = foo(&String::from("blah blah blah")); | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/wf-in-where-clause-static.rs:12:17 | LL | &'static S: Static, diff --git a/tests/ui/wf/wf-in-where-clause-static.next.stderr b/tests/ui/wf/wf-in-where-clause-static.next.stderr index 53cc6093f540..788fe2c3faa0 100644 --- a/tests/ui/wf/wf-in-where-clause-static.next.stderr +++ b/tests/ui/wf/wf-in-where-clause-static.next.stderr @@ -7,7 +7,7 @@ LL | let s = foo(&String::from("blah blah blah")); | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` | -note: requirement for `'static` introduced here +note: requirement that the value outlives `'static` introduced here --> $DIR/wf-in-where-clause-static.rs:12:17 | LL | &'static S: Static, From 58f5260b960004090bfa9e7ef5068d6554ac9f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Sep 2025 20:58:44 +0000 Subject: [PATCH 381/537] Address review comment --- .../src/diagnostics/explain_borrow.rs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 66c43a07c80c..67e33b37416c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -417,16 +417,20 @@ impl<'tcx> BorrowExplanation<'tcx> { self.add_object_lifetime_default_note(tcx, err, unsize_ty); } - for constraint in path { - if let ConstraintCategory::Predicate(pred) = constraint.category - && !pred.is_dummy() - { - err.span_note( - pred, - format!("requirement that the value outlives `{region_name}` introduced here"), - ); - break; - } + if let Some(pred) = path + .iter() + .filter_map(|constraint| match constraint.category { + ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred), + _ => None, + }) + .next() + { + err.span_note( + pred, + format!( + "requirement that the value outlives `{region_name}` introduced here" + ), + ); } self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); From c5313fed76a99942edb4c7f94607fa3d2d6da21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Sep 2025 21:13:53 +0000 Subject: [PATCH 382/537] Point at multiple outlives requirements instead of just the first one ``` error[E0716]: temporary value dropped while borrowed --> $DIR/multiple-sources-for-outlives-requirement.rs:5:38 | LL | fn foo<'b>() { | -- lifetime `'b` defined here LL | outlives_indir::<'_, 'b, _>(&mut 1u32); | ---------------------------------^^^^-- temporary value is freed at the end of this statement | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'b` | note: requirements that the value outlives `'b` introduced here --> $DIR/multiple-sources-for-outlives-requirement.rs:1:23 | LL | fn outlives_indir<'a: 'b, 'b, T: 'a>(_x: T) {} | ^^ ^^ ``` --- .../src/diagnostics/explain_borrow.rs | 13 +++++++----- ...ltiple-sources-for-outlives-requirement.rs | 11 ++++++++++ ...le-sources-for-outlives-requirement.stderr | 20 +++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 tests/ui/regions/multiple-sources-for-outlives-requirement.rs create mode 100644 tests/ui/regions/multiple-sources-for-outlives-requirement.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 67e33b37416c..638d89f5bcbd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -417,18 +417,21 @@ impl<'tcx> BorrowExplanation<'tcx> { self.add_object_lifetime_default_note(tcx, err, unsize_ty); } - if let Some(pred) = path + let mut preds = path .iter() .filter_map(|constraint| match constraint.category { ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred), _ => None, }) - .next() - { + .collect::>(); + preds.sort(); + preds.dedup(); + if !preds.is_empty() { + let s = if preds.len() == 1 { "" } else { "s" }; err.span_note( - pred, + preds, format!( - "requirement that the value outlives `{region_name}` introduced here" + "requirement{s} that the value outlives `{region_name}` introduced here" ), ); } diff --git a/tests/ui/regions/multiple-sources-for-outlives-requirement.rs b/tests/ui/regions/multiple-sources-for-outlives-requirement.rs new file mode 100644 index 000000000000..720cd1cf6eec --- /dev/null +++ b/tests/ui/regions/multiple-sources-for-outlives-requirement.rs @@ -0,0 +1,11 @@ +fn outlives_indir<'a: 'b, 'b, T: 'a>(_x: T) {} +//~^ NOTE: requirements that the value outlives `'b` introduced here + +fn foo<'b>() { //~ NOTE: lifetime `'b` defined here + outlives_indir::<'_, 'b, _>(&mut 1u32); //~ ERROR: temporary value dropped while borrowed + //~^ NOTE: argument requires that borrow lasts for `'b` + //~| NOTE: creates a temporary value which is freed while still in use + //~| NOTE: temporary value is freed at the end of this statement +} + +fn main() {} diff --git a/tests/ui/regions/multiple-sources-for-outlives-requirement.stderr b/tests/ui/regions/multiple-sources-for-outlives-requirement.stderr new file mode 100644 index 000000000000..4cdaf950e155 --- /dev/null +++ b/tests/ui/regions/multiple-sources-for-outlives-requirement.stderr @@ -0,0 +1,20 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/multiple-sources-for-outlives-requirement.rs:5:38 + | +LL | fn foo<'b>() { + | -- lifetime `'b` defined here +LL | outlives_indir::<'_, 'b, _>(&mut 1u32); + | ---------------------------------^^^^-- temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | argument requires that borrow lasts for `'b` + | +note: requirements that the value outlives `'b` introduced here + --> $DIR/multiple-sources-for-outlives-requirement.rs:1:23 + | +LL | fn outlives_indir<'a: 'b, 'b, T: 'a>(_x: T) {} + | ^^ ^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0716`. From 8f7d61b9efe1f44701f87fe4647eb1f39d20f434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 25 Nov 2024 21:52:08 +0000 Subject: [PATCH 383/537] Detect unconstructable re-exported tuple structs When a tuple-struct is re-exported that has inaccessible fields at the `use` scope, the type's constructor cannot be accessed through that re-export. We now account for this case and extend the resulting resolution error. We also check if the constructor would be accessible directly, not through the re-export, and if so, we suggest using the full path instead. ``` error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33 | LL | let crate::Foo(x) = crate::Foo(42); | ^^^^^^^^^^ | note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 | LL | pub use my_mod::Foo; | ^^^^^^^^^^^ help: the type can be constructed directly, because its fields are available from the current scope | LL | let crate::Foo(x) = crate::my_mod::Foo(42); | ~~~~~~~~~~~~~~~~~~ ``` Fix #133343. --- compiler/rustc_resolve/src/ident.rs | 33 +++++++ .../rustc_resolve/src/late/diagnostics.rs | 99 ++++++++++++------- compiler/rustc_resolve/src/lib.rs | 6 ++ ...ue-to-inaccessible-field-in-reexport.fixed | 20 ++++ ...e-due-to-inaccessible-field-in-reexport.rs | 20 ++++ ...e-to-inaccessible-field-in-reexport.stderr | 36 +++++++ 6 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 51489019950a..4415300777f9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -901,6 +901,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, + module, finalize, shadowing, ); @@ -1025,6 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option>, shadowed_glob: Option>, parent_scope: &ParentScope<'ra>, + module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, ) -> Result, (Determinacy, Weak)> { @@ -1076,6 +1078,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } + // If we encounter a re-export for a type with private fields, it will not be able to + // be constructed through this re-export. We track that case here to expand later + // privacy errors with appropriate information. + if let Res::Def(_, def_id) = binding.res() { + let struct_ctor = match def_id.as_local() { + Some(def_id) => self.struct_constructors.get(&def_id).cloned(), + None => { + let ctor = self.cstore().ctor_untracked(def_id); + ctor.map(|(ctor_kind, ctor_def_id)| { + let ctor_res = Res::Def( + DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind), + ctor_def_id, + ); + let ctor_vis = self.tcx.visibility(ctor_def_id); + let field_visibilities = self + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.tcx.visibility(field_id)) + .collect(); + (ctor_res, ctor_vis, field_visibilities) + }) + } + }; + if let Some((_, _, fields)) = struct_ctor + && fields.iter().any(|vis| !self.is_accessible_from(*vis, module)) + { + self.inaccessible_ctor_reexport.insert(path_span, binding.span); + } + } + self.record_use(ident, binding, used); return Ok(binding); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9e3c09388366..8c2ddda7f983 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1942,44 +1942,77 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return true; }; + let update_message = + |this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| { + match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(*pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + PathSource::Expr(Some(Expr { + kind: ExprKind::Call(path, args), + span: call_span, + .. + })) => { + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + this.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + // Use spans of the tuple struct definition. + this.r + .field_idents(def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::>()) + } + _ => None, + } + }; let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span) + && is_accessible + { + err.span_note( + *use_span, + "the type is accessed through this re-export, but the type's constructor \ + is not visible in this import's scope due to private fields", + ); + if is_accessible + && fields + .iter() + .all(|vis| self.r.is_accessible_from(*vis, self.parent_scope.module)) + { + err.span_suggestion_verbose( + span, + "the type can be constructed directly, because its fields are \ + available from the current scope", + // Using `tcx.def_path_str` causes the compiler to hang. + // We don't need to handle foreign crate types because in that case you + // can't access the ctor either way. + format!( + "crate{}", // The method already has leading `::`. + self.r.tcx.def_path(def_id).to_string_no_crate_verbose(), + ), + Applicability::MachineApplicable, + ); + } + update_message(self, err, &source); + } if !is_expected(ctor_def) || is_accessible { return true; } - let field_spans = match source { - // e.g. `if let Enum::TupleVariant(field1, field2) = _` - PathSource::TupleStruct(_, pattern_spans) => { - err.primary_message( - "cannot match against a tuple struct which contains private fields", - ); - - // Use spans of the tuple struct pattern. - Some(Vec::from(pattern_spans)) - } - // e.g. `let _ = Enum::TupleVariant(field1, field2);` - PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, args), - span: call_span, - .. - })) => { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - self.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - // Use spans of the tuple struct definition. - self.r - .field_idents(def_id) - .map(|fields| fields.iter().map(|f| f.span).collect::>()) - } - _ => None, - }; + let field_spans = update_message(self, err, &source); if let Some(spans) = field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8959068b2a67..b44b1c966a43 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1167,6 +1167,11 @@ pub struct Resolver<'ra, 'tcx> { /// Crate-local macro expanded `macro_export` referred to by a module-relative path. macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), + /// When a type is re-exported that has an inaccessible constructor because it has fields that + /// are inaccessible from the import's scope, we mark that as the type won't be able to be built + /// through the re-export. We use this information to extend the existing diagnostic. + inaccessible_ctor_reexport: FxHashMap, + arenas: &'ra ResolverArenas<'ra>, dummy_binding: NameBinding<'ra>, builtin_types_bindings: FxHashMap>, @@ -1595,6 +1600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_map: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), + inaccessible_ctor_reexport: Default::default(), arenas, dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed new file mode 100644 index 000000000000..63cc3333b6b7 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed @@ -0,0 +1,20 @@ +#![allow(dead_code, unused_variables)] +//@ run-rustfix +pub use my_mod::Foo; +//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields +//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + +mod my_mod { + pub struct Foo(u32); + + mod my_sub_mod { + fn my_func() { + let crate::my_mod::Foo(x) = crate::my_mod::Foo(42); + //~^ ERROR cannot initialize a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + //~| ERROR cannot match against a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + } + } +} +fn main() {} diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs new file mode 100644 index 000000000000..0b695f906545 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs @@ -0,0 +1,20 @@ +#![allow(dead_code, unused_variables)] +//@ run-rustfix +pub use my_mod::Foo; +//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields +//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + +mod my_mod { + pub struct Foo(u32); + + mod my_sub_mod { + fn my_func() { + let crate::Foo(x) = crate::Foo(42); + //~^ ERROR cannot initialize a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + //~| ERROR cannot match against a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + } + } +} +fn main() {} diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr new file mode 100644 index 000000000000..6ab324cb32f3 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr @@ -0,0 +1,36 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33 + | +LL | let crate::Foo(x) = crate::Foo(42); + | ^^^^^^^^^^ + | +note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 + | +LL | pub use my_mod::Foo; + | ^^^^^^^^^^^ +help: the type can be constructed directly, because its fields are available from the current scope + | +LL | let crate::Foo(x) = crate::my_mod::Foo(42); + | ++++++++ + +error[E0532]: cannot match against a tuple struct which contains private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:17 + | +LL | let crate::Foo(x) = crate::Foo(42); + | ^^^^^^^^^^ + | +note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 + | +LL | pub use my_mod::Foo; + | ^^^^^^^^^^^ +help: the type can be constructed directly, because its fields are available from the current scope + | +LL | let crate::my_mod::Foo(x) = crate::Foo(42); + | ++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0532. +For more information about an error, try `rustc --explain E0423`. From 0c9d0dfe046f0674f0507df564504ac3bac862d9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 28 Sep 2025 14:40:39 -0700 Subject: [PATCH 384/537] remove explicit deref of AbiAlign for most methods Much of the compiler calls functions on Align projected from AbiAlign. AbiAlign impls Deref to its inner Align, so we can simplify these away. Also, it will minimize disruption when AbiAlign is removed. For now, preserve usages that might resolve to PartialOrd or PartialEq, as those have odd inference. --- compiler/rustc_abi/src/layout.rs | 6 +++--- compiler/rustc_abi/src/lib.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/comments.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs | 2 +- .../rustc_codegen_cranelift/src/debuginfo/types.rs | 6 ++---- compiler/rustc_codegen_cranelift/src/unsize.rs | 6 +++--- .../rustc_codegen_cranelift/src/value_and_place.rs | 6 +++--- compiler/rustc_codegen_gcc/src/context.rs | 6 +++--- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- .../src/debuginfo/metadata/enums/native.rs | 4 ++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 8 ++++---- compiler/rustc_const_eval/src/interpret/operator.rs | 2 +- compiler/rustc_const_eval/src/util/alignment.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 +- .../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 2 +- .../rustc_mir_transform/src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- compiler/rustc_mir_transform/src/known_panics_lint.rs | 2 +- compiler/rustc_target/src/callconv/arm.rs | 2 +- compiler/rustc_target/src/callconv/loongarch.rs | 2 +- compiler/rustc_target/src/callconv/nvptx64.rs | 4 ++-- compiler/rustc_target/src/callconv/powerpc64.rs | 2 +- compiler/rustc_target/src/callconv/riscv.rs | 2 +- compiler/rustc_target/src/callconv/xtensa.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 10 +++++----- compiler/rustc_ty_utils/src/layout/invariant.rs | 6 +++--- .../clippy_lints/src/casts/cast_ptr_alignment.rs | 4 ++-- .../clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- src/tools/miri/src/machine.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout/tests.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs | 6 +++--- .../rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 4 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 2 +- 40 files changed, 66 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5004d0c80220..d56fbb5cb94f 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1169,7 +1169,7 @@ impl LayoutCalculator { // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must // not depend on the layout of the tail. let max_field_align = - fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); + fields_excluding_tail.iter().map(|f| f.align.bytes()).max().unwrap_or(1); let largest_niche_size = fields_excluding_tail .iter() .filter_map(|f| f.largest_niche) @@ -1189,7 +1189,7 @@ impl LayoutCalculator { } else { // Returns `log2(effective-align)`. The calculation assumes that size is an // integer multiple of align, except for ZSTs. - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let size = layout.size.bytes(); let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. @@ -1488,7 +1488,7 @@ impl LayoutCalculator { for i in layout.fields.index_by_increasing_offset() { let offset = layout.fields.offset(i); let f = &fields[FieldIdx::new(i)]; - write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); + write!(s, "[o{}a{}s{}", offset.bytes(), f.align.bytes(), f.size.bytes()).unwrap(); if let Some(n) = f.largest_niche { write!( s, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 369874521e57..9a364f9be184 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2159,7 +2159,7 @@ impl LayoutData { /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). pub fn is_1zst(&self) -> bool { - self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 + self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1 } /// Returns `true` if the type is a ZST and not unsized. diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index c74efeb59f3f..d1b2b9a502ac 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -89,7 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>( format!("{:?}", local), format!("{:?}", ty), size.bytes(), - align.abi.bytes(), + align.bytes(), if extra.is_empty() { "" } else { " " }, extra, )); diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 2031842062d9..7a909a740b05 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -233,7 +233,7 @@ pub(super) fn from_casted_value<'tcx>( // It may also be smaller for example when the type is a wrapper around an integer with a // larger alignment than the integer. std::cmp::max(abi_param_size, layout_size), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); let mut block_params_iter = block_params.iter().copied(); for (offset, _) in abi_params { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 41e11e1de616..2cc5b82ddd34 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -846,7 +846,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), - NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::AlignOf => layout.align.bytes(), NullOp::OffsetOf(fields) => fx .tcx .offset_of_subfield( diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 286e02b986b3..4c438742f3d2 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -304,7 +304,7 @@ impl DebugContext { entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes())); + entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.bytes())); let mut expr = Expression::new(); expr.op_addr(address_for_data(data_id)); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index 25b922c8be4c..0d49f32373ca 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -166,7 +166,7 @@ impl DebugContext { let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes())); + tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.bytes())); for (i, (ty, dw_ty)) in components.into_iter().enumerate() { let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); @@ -178,9 +178,7 @@ impl DebugContext { member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); member_entry.set( gimli::DW_AT_alignment, - AttributeValue::Udata( - FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(), - ), + AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.bytes()), ); member_entry.set( gimli::DW_AT_data_member_location, diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 643c7feb89a2..d994f3e32ec3 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -167,7 +167,7 @@ pub(crate) fn size_and_align_of<'tcx>( if layout.is_sized() { return ( fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, layout.align.bytes() as i64), ); } @@ -186,7 +186,7 @@ pub(crate) fn size_and_align_of<'tcx>( // times the unit size. ( fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, unit.align.bytes() as i64), ) } ty::Foreign(_) => { @@ -224,7 +224,7 @@ pub(crate) fn size_and_align_of<'tcx>( let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); let unsized_offset_unadjusted = fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64); // Recurse to get the size of the dynamically sized field (must be diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4519fa1a270e..04e10cf17088 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -383,7 +383,7 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.create_stack_slot( u32::try_from(layout.size.bytes()).unwrap(), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout } } @@ -641,8 +641,8 @@ impl<'tcx> CPlace<'tcx> { let size = dst_layout.size.bytes(); // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum // alignment that fits in a `u8` if the actual alignment is larger. - let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128); - let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128); + let src_align = src_layout.align.bytes().try_into().unwrap_or(128); + let dst_align = dst_layout.align.bytes().try_into().unwrap_or(128); fx.bcx.emit_small_memory_copy( fx.target_config, to_addr, diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 9815fb07eaae..c9ae96777de4 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -147,7 +147,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .unwrap(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); // For types with size 1, the alignment can be 1 and only 1 // So, we can skip the call to ``get_aligned`. // In the future, we can add a GCC API to query the type align, @@ -186,9 +186,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { (i128_type, u128_type) } else { /*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap(); - let i128_align = layout.align.abi.bytes(); + let i128_align = layout.align.bytes(); let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); - let u128_align = layout.align.abi.bytes();*/ + let u128_align = layout.align.bytes();*/ // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 4b74c04ed7ae..1e4ace4ca922 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1043,7 +1043,7 @@ fn create_member_type<'ll, 'tcx>( file_metadata, line_number, layout.size.bits(), - layout.align.abi.bits() as u32, + layout.align.bits() as u32, offset.bits(), flags, type_di_node, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 62d38d463aba..1ae6e6e5eeca 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -289,7 +289,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( file_metadata, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, DIFlags::FlagZero, tag_member_di_node, create_DIArray(DIB(cx), &[]), @@ -449,7 +449,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( file_di_node, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, Size::ZERO.bits(), discr, DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 013108d1286e..ba80352916b0 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -297,7 +297,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let align = if name == sym::unaligned_volatile_load { 1 } else { - result.layout.align.abi.bytes() as u32 + result.layout.align.bytes() as u32 }; unsafe { llvm::LLVMSetAlignment(load, align); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index d48c7cf874a0..b2c60db9c679 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -193,7 +193,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( // the offset again. bx.switch_to_block(maybe_reg); - if gr_type && layout.align.abi.bytes() > 8 { + if gr_type && layout.align.bytes() > 8 { reg_off_v = bx.add(reg_off_v, bx.const_i32(15)); reg_off_v = bx.and(reg_off_v, bx.const_i32(-16)); } @@ -761,7 +761,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use // alignment greater than 16 where necessary. - if layout.layout.align.abi.bytes() > 8 { + if layout.layout.align.bytes() > 8 { unreachable!("all instances of VaArgSafe have an alignment <= 8"); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2602bf82095c..0a4b0f8d4949 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -617,7 +617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::NullOp::AlignOf => { assert!(bx.cx().type_is_sized(ty)); - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 577012151e49..e1bd8014d7a2 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -21,7 +21,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); if layout.is_sized() { let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); return (size, align); } match t.kind() { @@ -49,7 +49,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // All slice sizes must fit into `isize`, so this multiplication cannot // wrap -- neither signed nor unsigned. bx.unchecked_sumul(info.unwrap(), bx.const_usize(unit.size.bytes())), - bx.const_usize(unit.align.abi.bytes()), + bx.const_usize(unit.align.bytes()), ) } ty::Foreign(_) => { @@ -82,7 +82,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // This function does not return so we can now return whatever we want. let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); (size, align) } ty::Adt(..) | ty::Tuple(..) => { @@ -94,7 +94,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let i = layout.fields.count() - 1; let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); debug!( "DST {} offset of dyn field: {}, statically sized align: {}", t, unsized_offset_unadjusted, sized_align diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 74f8a0a7b093..f0819423aa0f 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -528,7 +528,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`"); } - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); ImmTy::from_uint(val, usize_layout()) } OffsetOf(fields) => { diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 9507b24f603e..9aafc7efd8a6 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -37,7 +37,7 @@ where debug!( "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", place, - layout.align.abi.bytes(), + layout.align.bytes(), pack.bytes() ); false diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index b1f295987505..1dea7e4252d7 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -129,7 +129,7 @@ fn check_validity_requirement_lax<'tcx>( if let Some(pointee) = this.ty.builtin_deref(false) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. - if pointee.align.abi.bytes() > 1 { + if pointee.align.bytes() > 1 { // 0x01-filling is not aligned. return Ok(false); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 81deb35920af..0458fa1204e8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -138,7 +138,7 @@ fn is_valid_cmse_inputs<'tcx>( for (index, ty) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; - let align = layout.layout.align().abi.bytes(); + let align = layout.layout.align().bytes(); let size = layout.layout.size().bytes(); accum += size; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index e2f09fdcb4b4..a3e9054fdcb8 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -104,7 +104,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( .expect("failed to build vtable representation"); assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let ptr_size = tcx.data_layout.pointer_size(); let ptr_align = tcx.data_layout.pointer_align().abi; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 5c984984d3cc..491e910ff6f8 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -476,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { }; let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), - NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), + NullOp::AlignOf if layout.is_sized() => layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebec3d125003..29f6879aacd0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -618,7 +618,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let val = match null_op { NullOp::SizeOf => arg_layout.size.bytes(), - NullOp::AlignOf => arg_layout.align.abi.bytes(), + NullOp::AlignOf => arg_layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index aaacc5866a2a..5fffba55f17b 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -609,7 +609,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let op_layout = self.ecx.layout_of(ty).ok()?; let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), - NullOp::AlignOf => op_layout.align.abi.bytes(), + NullOp::AlignOf => op_layout.align.bytes(), NullOp::OffsetOf(fields) => self .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 70830fa07b6e..abc9a404e2ea 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -77,7 +77,7 @@ where } } - let align = arg.layout.align.abi.bytes(); + let align = arg.layout.align.bytes(); let total = arg.layout.size; arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total)); } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 9213d73e24ea..bc3c9601fa3d 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -322,7 +322,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index 44977de7fcbc..dc32dd87a7e7 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -21,7 +21,7 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { /// the pass mode used for aggregates in arg and ret position fn classify_aggregate(arg: &mut ArgAbi<'_, Ty>) { - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let size = arg.layout.size; let reg = match align_bytes { @@ -60,7 +60,7 @@ where // "`extern \"ptx-kernel\"` doesn't allow passing types other than primitives and structs" // ); - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let unit = match align_bytes { 1 => Reg::i8(), diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 89ec85e4b666..be1d13816eff 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -89,7 +89,7 @@ where // Aggregates larger than i64 should be padded at the tail to fill out a whole number // of i64s or i128s, depending on the aggregate alignment. Always use an array for // this, even if there is only a single element. - let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() }; + let reg = if arg.layout.align.bytes() > 8 { Reg::i128() } else { Reg::i64() }; arg.cast_to(Uniform::consecutive( reg, size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()), diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 161e2c1645f9..16de3fe070dd 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -328,7 +328,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index a73a70a1a0c0..561ee98787de 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -48,7 +48,7 @@ where } let size = arg.layout.size.bits(); - let needed_align = arg.layout.align.abi.bits(); + let needed_align = arg.layout.align.bits(); let mut must_use_stack = false; // Determine the number of GPRs needed to pass the current argument diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index a02e8ecf613f..7f626e8c4e88 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -361,7 +361,7 @@ pub(crate) mod rustc { ty::Ref(region, ty, mutability) => { let layout = layout_of(cx, *ty)?; - let referent_align = layout.align.abi.bytes_usize(); + let referent_align = layout.align.bytes_usize(); let referent_size = layout.size.bytes_usize(); Ok(Tree::Ref(Reference { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f59bc2117d53..317d101dafe0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -795,7 +795,7 @@ fn variant_info_for_adt<'tcx>( name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -804,7 +804,7 @@ fn variant_info_for_adt<'tcx>( VariantInfo { name: n, kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, - align: layout.align.abi.bytes(), + align: layout.align.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, fields: field_info, } @@ -877,7 +877,7 @@ fn variant_info_for_coroutine<'tcx>( name: *name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -905,7 +905,7 @@ fn variant_info_for_coroutine<'tcx>( }), offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), // Include the type name if there is no field name, or if the name is the // __awaitee placeholder symbol which means a child future being `.await`ed. type_name: (field_name.is_none() || field_name == Some(sym::__awaitee)) @@ -946,7 +946,7 @@ fn variant_info_for_coroutine<'tcx>( name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))), kind: SizeKind::Exact, size: variant_size.bytes(), - align: variant_layout.align.abi.bytes(), + align: variant_layout.align.bytes(), fields, } }) diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182c..b768269215fa 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - if !layout.size.bytes().is_multiple_of(layout.align.abi.bytes()) { + if !layout.size.bytes().is_multiple_of(layout.align.bytes()) { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } if layout.size.bytes() >= tcx.data_layout.obj_size_bound() { @@ -300,8 +300,8 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou if variant.align.abi > layout.align.abi { bug!( "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", - layout.align.abi.bytes(), - variant.align.abi.bytes(), + layout.align.bytes(), + variant.align.bytes(), ) } // Skip empty variants. diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index d78da9396faf..7d14ba7fcf13 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -43,8 +43,8 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f expr.span, format!( "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", - from_layout.align.abi.bytes(), - to_layout.align.abi.bytes(), + from_layout.align.bytes(), + to_layout.align.bytes(), ), ); } diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs index 92910cf8adf5..ff5320719aa2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -72,7 +72,7 @@ fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned, to: &Ty<'_>) cx.tcx .layout_of(cx.typing_env().as_query_input(to_mid_ty)) .is_ok_and(|layout| { - let align = u128::from(layout.align.abi.bytes()); + let align = u128::from(layout.align.bytes()); u128::from(val) <= align }) } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index d307636e782f..412640a112c0 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1341,7 +1341,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { name = ecx.tcx.def_path_str(def_id), krate = ecx.tcx.crate_name(def_id.krate), decl_size = extern_decl_layout.size.bytes(), - decl_align = extern_decl_layout.align.abi.bytes(), + decl_align = extern_decl_layout.align.bytes(), shim_size = info.size.bytes(), shim_align = info.align.bytes(), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 523ddad94666..8be5eaca63b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -150,7 +150,7 @@ fn check_size_and_align( ) { let l = eval_goal(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); - assert_eq!(l.align.abi.bytes(), align, "align mismatch"); + assert_eq!(l.align.bytes(), align, "align mismatch"); } #[track_caller] @@ -162,7 +162,7 @@ fn check_size_and_align_expr( ) { let l = eval_expr(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); - assert_eq!(l.align.abi.bytes(), align, "align mismatch"); + assert_eq!(l.align.bytes(), align, "align mismatch"); } #[track_caller] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 3e658cb93ed8..fc7d97fff465 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -2085,7 +2085,7 @@ impl<'db> Evaluator<'db> { if let Some(layout) = self.layout_cache.borrow().get(&ty.to_nextsolver(interner)) { return Ok(layout .is_sized() - .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); + .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))); } if let DefWithBodyId::VariantId(f) = locals.body.owner && let Some((AdtId::EnumId(e), _)) = ty.as_adt() @@ -2104,7 +2104,7 @@ impl<'db> Evaluator<'db> { let layout = layout?; Ok(layout .is_sized() - .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))) + .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))) } /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should @@ -2797,7 +2797,7 @@ impl<'db> Evaluator<'db> { )?; // FIXME: there is some leak here let size = layout.size.bytes_usize(); - let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize)?; + let addr = self.heap_allocate(size, layout.align.bytes() as usize)?; self.write_memory(addr, &result)?; IntervalAndTy { interval: Interval { addr, size }, ty } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index f67778b0f12f..38480493048e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -767,7 +767,7 @@ impl Evaluator<'_> { "align_of generic arg is not provided".into(), )); }; - let align = self.layout(ty.to_nextsolver(interner))?.align.abi.bytes(); + let align = self.layout(ty.to_nextsolver(interner))?.align.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { @@ -1431,7 +1431,7 @@ impl Evaluator<'_> { field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst); let sized_part_size = layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); - let sized_part_align = layout.align.abi.bytes() as usize; + let sized_part_align = layout.align.bytes() as usize; let (unsized_part_size, unsized_part_align) = self.size_align_of_unsized(&last_field_ty, metadata, locals)?; let align = sized_part_align.max(unsized_part_align) as isize; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 027a386abe8c..17767955d474 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -6094,7 +6094,7 @@ impl Layout { } pub fn align(&self) -> u64 { - self.0.align.abi.bytes() + self.0.align.bytes() } pub fn niches(&self) -> Option { From b71c4690409e8ce98a502216623a9264efaaa3e4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Sep 2025 18:44:19 +1000 Subject: [PATCH 385/537] Fix some crash-test directives --- tests/crashes/125772.rs | 2 +- tests/crashes/131292.rs | 2 +- tests/crashes/34127.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/crashes/125772.rs b/tests/crashes/125772.rs index 2965cfc9e7c3..2b6cffd9463a 100644 --- a/tests/crashes/125772.rs +++ b/tests/crashes/125772.rs @@ -1,5 +1,5 @@ //@ known-bug: rust-lang/rust#125772 -//@ only-x86_64 +//@ only-64bit #![feature(generic_const_exprs)] struct Outer(); diff --git a/tests/crashes/131292.rs b/tests/crashes/131292.rs index 01e0eca0bd6d..05b93d06b055 100644 --- a/tests/crashes/131292.rs +++ b/tests/crashes/131292.rs @@ -1,5 +1,5 @@ //@ known-bug: #131292 -//@ only-x86_64 +//@ needs-asm-support use std::arch::asm; unsafe fn f6() { diff --git a/tests/crashes/34127.rs b/tests/crashes/34127.rs index ea36b48ecba0..26ebe722475f 100644 --- a/tests/crashes/34127.rs +++ b/tests/crashes/34127.rs @@ -1,6 +1,6 @@ //@ compile-flags: -g -Copt-level=0 -Z verify-llvm-ir //@ known-bug: #34127 -//@ only-x86_64 +//@ only-64bit pub fn main() { let _a = [(); 1 << 63]; From eceb48534a4fdabfaf378ea02a2c5cd43b8c52a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Sep 2025 03:28:52 +0000 Subject: [PATCH 386/537] Make replacement suggestion `_` in type verbose ``` error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/in-signature.rs:6:21 | LL | fn arr_fn() -> [u8; _] { | ^ not allowed in type signatures | help: replace with the correct return type | LL - fn arr_fn() -> [u8; _] { LL + fn arr_fn() -> [u8; 3] { | ``` --- compiler/rustc_hir_analysis/src/collect.rs | 4 +- .../generic_arg_infer/in-signature.stderr | 36 +++-- tests/ui/error-codes/E0121.stderr | 11 +- tests/ui/fn/issue-80179.stderr | 21 ++- tests/ui/fn/suggest-return-closure.stderr | 30 ++-- tests/ui/fn/suggest-return-future.stderr | 22 ++- ...r-return-ty-for-fn-sig-issue-125488.stderr | 44 ++++-- tests/ui/suggestions/return-cycle-2.stderr | 11 +- tests/ui/suggestions/return-cycle.stderr | 11 +- ...uggest-fn-ptr-for-fn-item-in-fn-ret.stderr | 11 +- .../type-alias-impl-trait/issue-77179.stderr | 11 +- tests/ui/typeck/issue-80779.stderr | 22 ++- tests/ui/typeck/issue-98260.stderr | 11 +- .../typeck_type_placeholder_item.stderr | 141 +++++++++++------- .../typeck_type_placeholder_item_help.stderr | 11 +- tests/ui/variance/leaking-unnameables.stderr | 11 +- 16 files changed, 258 insertions(+), 150 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b72e743f95b0..02baaec37138 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1140,7 +1140,7 @@ fn recover_infer_ret_ty<'tcx>( // recursive function definition to leak out into the fn sig. let mut recovered_ret_ty = None; if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { - diag.span_suggestion( + diag.span_suggestion_verbose( infer_ret_ty.span, "replace with the correct return type", suggestable_ret_ty, @@ -1152,7 +1152,7 @@ fn recover_infer_ret_ty<'tcx>( tcx.param_env(def_id), ret_ty, ) { - diag.span_suggestion( + diag.span_suggestion_verbose( infer_ret_ty.span, "replace with an appropriate return type", sugg, diff --git a/tests/ui/const-generics/generic_arg_infer/in-signature.stderr b/tests/ui/const-generics/generic_arg_infer/in-signature.stderr index b6f2662a9393..d7a7ab52c83d 100644 --- a/tests/ui/const-generics/generic_arg_infer/in-signature.stderr +++ b/tests/ui/const-generics/generic_arg_infer/in-signature.stderr @@ -2,29 +2,39 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/in-signature.rs:6:21 | LL | fn arr_fn() -> [u8; _] { - | -----^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `[u8; 3]` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn arr_fn() -> [u8; _] { +LL + fn arr_fn() -> [u8; 3] { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/in-signature.rs:11:24 | LL | fn ty_fn() -> Bar { - | ---------^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `Bar` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn ty_fn() -> Bar { +LL + fn ty_fn() -> Bar { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/in-signature.rs:16:25 | LL | fn ty_fn_mixed() -> Bar<_, _> { - | ----^--^- - | | | | - | | | not allowed in type signatures - | | not allowed in type signatures - | help: replace with the correct return type: `Bar` + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn ty_fn_mixed() -> Bar<_, _> { +LL + fn ty_fn_mixed() -> Bar { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/in-signature.rs:21:20 diff --git a/tests/ui/error-codes/E0121.stderr b/tests/ui/error-codes/E0121.stderr index b169373f6439..074929c4e74f 100644 --- a/tests/ui/error-codes/E0121.stderr +++ b/tests/ui/error-codes/E0121.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/E0121.rs:1:13 | LL | fn foo() -> _ { 5 } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `i32` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn foo() -> _ { 5 } +LL + fn foo() -> i32 { 5 } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/E0121.rs:3:13 diff --git a/tests/ui/fn/issue-80179.stderr b/tests/ui/fn/issue-80179.stderr index f5d6c44db751..95158da3cff6 100644 --- a/tests/ui/fn/issue-80179.stderr +++ b/tests/ui/fn/issue-80179.stderr @@ -2,21 +2,26 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-80179.rs:10:24 | LL | fn returns_fn_ptr() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `fn() -> i32` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn returns_fn_ptr() -> _ { +LL + fn returns_fn_ptr() -> fn() -> i32 { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80179.rs:18:25 | LL | fn returns_closure() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl Fn() -> i32` + | ^ not allowed in type signatures | = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html +help: replace with an appropriate return type + | +LL - fn returns_closure() -> _ { +LL + fn returns_closure() -> impl Fn() -> i32 { + | error: aborting due to 2 previous errors diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr index 1860d1ca5d92..0639c23c75ad 100644 --- a/tests/ui/fn/suggest-return-closure.stderr +++ b/tests/ui/fn/suggest-return-closure.stderr @@ -2,34 +2,40 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/suggest-return-closure.rs:1:17 | LL | fn fn_once() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl FnOnce()` + | ^ not allowed in type signatures | = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html +help: replace with an appropriate return type + | +LL - fn fn_once() -> _ { +LL + fn fn_once() -> impl FnOnce() { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/suggest-return-closure.rs:13:16 | LL | fn fn_mut() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl FnMut(char)` + | ^ not allowed in type signatures | = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html +help: replace with an appropriate return type + | +LL - fn fn_mut() -> _ { +LL + fn fn_mut() -> impl FnMut(char) { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/suggest-return-closure.rs:33:13 | LL | fn fun() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl Fn() -> i32` + | ^ not allowed in type signatures | = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html +help: replace with an appropriate return type + | +LL - fn fun() -> _ { +LL + fn fun() -> impl Fn() -> i32 { + | error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/suggest-return-closure.rs:24:9 diff --git a/tests/ui/fn/suggest-return-future.stderr b/tests/ui/fn/suggest-return-future.stderr index a4c8b5d8c4b5..7c097e506713 100644 --- a/tests/ui/fn/suggest-return-future.stderr +++ b/tests/ui/fn/suggest-return-future.stderr @@ -2,19 +2,25 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/suggest-return-future.rs:7:13 | LL | fn foo() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl Future` + | ^ not allowed in type signatures + | +help: replace with an appropriate return type + | +LL - fn foo() -> _ { +LL + fn foo() -> impl Future { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/suggest-return-future.rs:15:13 | LL | fn bar() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl Future` + | ^ not allowed in type signatures + | +help: replace with an appropriate return type + | +LL - fn bar() -> _ { +LL + fn bar() -> impl Future { + | error: aborting due to 2 previous errors diff --git a/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr index 8b7c5e1681ad..839e4265e031 100644 --- a/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr +++ b/tests/ui/return/infer-return-ty-for-fn-sig-issue-125488.stderr @@ -2,37 +2,49 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:8:24 | LL | fn f1(s: S<'_>) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `S<'_>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn f1(s: S<'_>) -> _ { +LL + fn f1(s: S<'_>) -> S<'_> { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:13:24 | LL | fn f2(s: S<'_>) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `S<'_>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn f2(s: S<'_>) -> _ { +LL + fn f2(s: S<'_>) -> S<'_> { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:23:24 | LL | fn f3(s: S<'_>) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `S<'_>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn f3(s: S<'_>) -> _ { +LL + fn f3(s: S<'_>) -> S<'_> { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/infer-return-ty-for-fn-sig-issue-125488.rs:28:24 | LL | fn f4(s: S<'_>) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `S<'_>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn f4(s: S<'_>) -> _ { +LL + fn f4(s: S<'_>) -> S<'_> { + | error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/return-cycle-2.stderr b/tests/ui/suggestions/return-cycle-2.stderr index 23de2309e877..e852cd34a72a 100644 --- a/tests/ui/suggestions/return-cycle-2.stderr +++ b/tests/ui/suggestions/return-cycle-2.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/return-cycle-2.rs:6:34 | LL | fn as_ref(_: i32, _: i32) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `Token<&'static T>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn as_ref(_: i32, _: i32) -> _ { +LL + fn as_ref(_: i32, _: i32) -> Token<&'static T> { + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/return-cycle.stderr b/tests/ui/suggestions/return-cycle.stderr index 604704904410..cd46c2daa40b 100644 --- a/tests/ui/suggestions/return-cycle.stderr +++ b/tests/ui/suggestions/return-cycle.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/return-cycle.rs:6:17 | LL | fn new() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `Token<()>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn new() -> _ { +LL + fn new() -> Token<()> { + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr b/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr index bf7790e2307e..9880dd95d864 100644 --- a/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr +++ b/tests/ui/suggestions/suggest-fn-ptr-for-fn-item-in-fn-ret.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/suggest-fn-ptr-for-fn-item-in-fn-ret.rs:7:13 | LL | fn bar() -> _ { Wrapper(foo) } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `Wrapper` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn bar() -> _ { Wrapper(foo) } +LL + fn bar() -> Wrapper { Wrapper(foo) } + | error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr index c0f197ec48c3..222edfb90a7b 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.stderr +++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr @@ -11,10 +11,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-77179.rs:8:22 | LL | fn test() -> Pointer<_> { - | --------^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `Pointer` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test() -> Pointer<_> { +LL + fn test() -> Pointer { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/issue-77179.rs:19:25 diff --git a/tests/ui/typeck/issue-80779.stderr b/tests/ui/typeck/issue-80779.stderr index 2261ba616545..90c80fa2ea6f 100644 --- a/tests/ui/typeck/issue-80779.stderr +++ b/tests/ui/typeck/issue-80779.stderr @@ -2,19 +2,25 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-80779.rs:10:28 | LL | pub fn g(_: T<'static>) -> _ {} - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `()` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - pub fn g(_: T<'static>) -> _ {} +LL + pub fn g(_: T<'static>) -> () {} + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/issue-80779.rs:5:29 | LL | pub fn f<'a>(val: T<'a>) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `()` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - pub fn f<'a>(val: T<'a>) -> _ { +LL + pub fn f<'a>(val: T<'a>) -> () { + | error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-98260.stderr b/tests/ui/typeck/issue-98260.stderr index b7debd335b0f..f380db55cdff 100644 --- a/tests/ui/typeck/issue-98260.stderr +++ b/tests/ui/typeck/issue-98260.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/issue-98260.rs:3:27 | LL | fn a(aa: B) -> Result<_, B> { - | -------^---- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `Result<(), B>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn a(aa: B) -> Result<_, B> { +LL + fn a(aa: B) -> Result<(), B> { + | error: aborting due to 1 previous error diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 87750ee6dc14..240dc1ae8ab9 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -48,20 +48,27 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:7:14 | LL | fn test() -> _ { 5 } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `i32` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test() -> _ { 5 } +LL + fn test() -> i32 { 5 } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:10:16 | LL | fn test2() -> (_, _) { (5, 5) } - | -^--^- - | || | - | || not allowed in type signatures - | |not allowed in type signatures - | help: replace with the correct return type: `(i32, i32)` + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test2() -> (_, _) { (5, 5) } +LL + fn test2() -> (i32, i32) { (5, 5) } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:13:15 @@ -189,19 +196,25 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:47:26 | LL | fn test11(x: &usize) -> &_ { - | -^ - | || - | |not allowed in type signatures - | help: replace with the correct return type: `&&usize` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test11(x: &usize) -> &_ { +LL + fn test11(x: &usize) -> &&usize { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:52:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { - | --------------^ - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `*const *const usize` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - unsafe fn test12(x: *const usize) -> *const *const _ { +LL + unsafe fn test12(x: *const usize) -> *const *const usize { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods --> $DIR/typeck_type_placeholder_item.rs:58:24 @@ -261,20 +274,27 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:80:21 | LL | fn fn_test() -> _ { 5 } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `i32` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn fn_test() -> _ { 5 } +LL + fn fn_test() -> i32 { 5 } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:83:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } - | -^--^- - | || | - | || not allowed in type signatures - | |not allowed in type signatures - | help: replace with the correct return type: `(i32, i32)` + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn fn_test2() -> (_, _) { (5, 5) } +LL + fn fn_test2() -> (i32, i32) { (5, 5) } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables --> $DIR/typeck_type_placeholder_item.rs:86:22 @@ -374,20 +394,27 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:134:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } - | -^--^- - | || | - | || not allowed in type signatures - | |not allowed in type signatures - | help: replace with the correct return type: `(i32, i32)` + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn fn_test12(x: i32) -> (_, _) { (x, x) } +LL + fn fn_test12(x: i32) -> (i32, i32) { (x, x) } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:137:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } - | ------^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `(i32, i32)` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn fn_test13(x: _) -> (i32, _) { (x, x) } +LL + fn fn_test13(x: _) -> (i32, i32) { (x, x) } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods --> $DIR/typeck_type_placeholder_item.rs:142:31 @@ -528,10 +555,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:226:31 | LL | fn value() -> Option<&'static _> { - | ----------------^- - | | | - | | not allowed in type signatures - | help: replace with the correct return type: `Option<&'static u8>` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn value() -> Option<&'static _> { +LL + fn value() -> Option<&'static u8> { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:231:17 @@ -549,10 +579,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:235:31 | LL | fn evens_squared(n: usize) -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with an appropriate return type: `impl Iterator` + | ^ not allowed in type signatures + | +help: replace with an appropriate return type + | +LL - fn evens_squared(n: usize) -> _ { +LL + fn evens_squared(n: usize) -> impl Iterator { + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item.rs:240:10 @@ -570,10 +603,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:40:24 | LL | fn test9(&self) -> _ { () } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `()` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test9(&self) -> _ { () } +LL + fn test9(&self) -> () { () } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods --> $DIR/typeck_type_placeholder_item.rs:43:27 @@ -585,10 +621,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:107:31 | LL | fn fn_test9(&self) -> _ { () } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `()` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn fn_test9(&self) -> _ { () } +LL + fn fn_test9(&self) -> () { () } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods --> $DIR/typeck_type_placeholder_item.rs:110:34 diff --git a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr index 2fce00e7a8e9..3f21ff6d4ec9 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:4:15 | LL | fn test1() -> _ { Some(42) } - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `Option` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn test1() -> _ { Some(42) } +LL + fn test1() -> Option { Some(42) } + | error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/typeck_type_placeholder_item_help.rs:7:14 diff --git a/tests/ui/variance/leaking-unnameables.stderr b/tests/ui/variance/leaking-unnameables.stderr index 92afe952801d..59bdc33040de 100644 --- a/tests/ui/variance/leaking-unnameables.stderr +++ b/tests/ui/variance/leaking-unnameables.stderr @@ -2,10 +2,13 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/leaking-unnameables.rs:8:18 | LL | pub fn f() -> _ { - | ^ - | | - | not allowed in type signatures - | help: replace with the correct return type: `fn()` + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - pub fn f() -> _ { +LL + pub fn f() -> fn() { + | error: aborting due to 1 previous error From 50171eb172a9418e8a20ad7d813d256305add5f0 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 29 Sep 2025 04:07:42 +0000 Subject: [PATCH 387/537] Prepare for merging from rust-lang/rust This updates the rust-version file to f957826bff7a68b267ce75b1ea56352aed0cca0a. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 8854fb95997b..1f90d4e5e498 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -caccb4d0368bd918ef6668af8e13834d07040417 +f957826bff7a68b267ce75b1ea56352aed0cca0a From 68a7c250788833305f73f816b284aafa9e62370a Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 27 Sep 2025 20:57:50 +0300 Subject: [PATCH 388/537] Use `Iterator::eq` and (dogfood) `eq_by` in compiler and library --- compiler/rustc_ast/src/ast.rs | 3 +-- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_ast/src/tokenstream.rs | 4 +--- compiler/rustc_attr_parsing/src/parser.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 3 +-- .../src/deriving/coerce_pointee.rs | 15 ++++----------- compiler/rustc_builtin_macros/src/format.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_hir/src/hir.rs | 5 +---- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +--- compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/method/suggest.rs | 4 +--- compiler/rustc_parse/src/lib.rs | 1 + .../rustc_parse/src/parser/tokenstream/tests.rs | 2 +- library/alloc/src/collections/btree/map.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/lib.rs | 1 + 17 files changed, 20 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3e8fddd9954e..082d5e88ac75 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -114,8 +114,7 @@ impl PartialEq for Path { impl PartialEq<&[Symbol]> for Path { #[inline] fn eq(&self, names: &&[Symbol]) -> bool { - self.segments.len() == names.len() - && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2) + self.segments.iter().eq(*names) } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index f1951049b476..5fe218776e53 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -15,6 +15,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(macro_metavar_expr)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index a5d8fbfac612..4111182c3b7d 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,9 +48,7 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 - && tts.len() == tts2.len() - && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) + delim == delim2 && tts.iter().eq_by(tts2.iter(), |a, b| a.eq_unspanned(b)) } _ => false, } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 4f903594225e..3f4f56790157 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -49,7 +49,7 @@ impl<'a> PathParser<'a> { } pub fn segments_is(&self, segments: &[Symbol]) -> bool { - self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) + self.segments().map(|segment| &segment.name).eq(segments) } pub fn word(&self) -> Option { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index f4a923797e2d..ddc59bfe1414 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -377,8 +377,7 @@ mod llvm_enzyme { (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { let a = &a.item.path; let b = &b.item.path; - a.segments.len() == b.segments.len() - && a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident) + a.segments.iter().eq_by(&b.segments, |a, b| a.ident == b.ident) } _ => false, } diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 75db5d77783e..5b378de8bbdd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -356,21 +356,14 @@ fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool { bounds.iter().any(is_maybe_sized_bound) } -fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool { - path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol) -} - fn is_sized_marker(path: &ast::Path) -> bool { const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized]; const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized]; - if path.segments.len() == 4 && path.is_global() { - path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE) - } else if path.segments.len() == 3 { - path_segment_is_exact_match(&path.segments, &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments, &STD_UNSIZE) + let segments = || path.segments.iter().map(|segment| segment.ident.name); + if path.is_global() { + segments().skip(1).eq(CORE_UNSIZE) || segments().skip(1).eq(STD_UNSIZE) } else { - *path == sym::Sized + segments().eq(CORE_UNSIZE) || segments().eq(STD_UNSIZE) || *path == sym::Sized } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index d70888205a51..bffc0407e811 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -768,7 +768,7 @@ fn report_missing_placeholders( if !found_foreign && invalid_refs.is_empty() { // Show example if user didn't use any format specifiers - let show_example = used.iter().all(|used| !used); + let show_example = !used.contains(&true); if !show_example { if unused.len() > 1 { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4541e2cd3b41..57cf62ea6121 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -11,6 +11,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 493236718a86..bc1c47e95c3a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1298,10 +1298,7 @@ impl AttributeExt for Attribute { #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { match &self { - Attribute::Unparsed(n) => { - n.path.segments.len() == name.len() - && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) - } + Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name), _ => false, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7ca8580e0986..c8943d4634e2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2803,9 +2803,7 @@ impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> { if let Some((assoc, fn_sig)) = self.similar_assoc(call_name) && fn_sig.inputs()[1..] .iter() - .zip(input_types.iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == input_types.len() + .eq_by(input_types, |expected, found| self.may_coerce(*expected, found)) { let assoc_name = assoc.name(); err.span_suggestion_verbose( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 43a23822fd1e..acc0481e457f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![feature(never_type)] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 024b9ee08c22..44602e628994 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1914,9 +1914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ref args) = call_args && fn_sig.inputs()[1..] .iter() - .zip(args.into_iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == args.len() + .eq_by(args, |expected, found| self.may_coerce(*expected, *found)) { err.span_suggestion_verbose( item_name.span, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 88b67d792deb..c26c7b9122af 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -9,6 +9,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index 19b2c98f5af8..63177a727449 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -15,7 +15,7 @@ fn sp(a: u32, b: u32) -> Span { } fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { - a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) + a.iter().eq_by(b.iter(), |x, y| x.eq_unspanned(y)) } #[test] diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 9dfbbd913225..adcb444d08c6 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2413,7 +2413,7 @@ impl Default for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) + self.iter().eq(other) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c2cf39c4be06..4eb32585ffb9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1685,7 +1685,7 @@ impl Type { match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) + a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache)) } (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c4f24e09ddbf..d7ffb25f8bd8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,6 +13,7 @@ #![feature(if_let_guard)] #![feature(iter_advance_by)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![feature(rustc_private)] #![feature(test)] #![warn(rustc::internal)] From 97333f8c9a0f774cc8d0025bbc51848e1f60427d Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 23 Sep 2025 17:14:51 +0200 Subject: [PATCH 389/537] std: implement `hostname` --- library/std/src/net/hostname.rs | 22 +++++++ library/std/src/net/mod.rs | 6 +- library/std/src/sys/net/hostname/mod.rs | 14 +++++ library/std/src/sys/net/hostname/unix.rs | 62 +++++++++++++++++++ .../std/src/sys/net/hostname/unsupported.rs | 6 ++ library/std/src/sys/net/hostname/windows.rs | 24 +++++++ library/std/src/sys/net/mod.rs | 3 + .../std/src/sys/pal/windows/c/bindings.txt | 2 + .../std/src/sys/pal/windows/c/windows_sys.rs | 2 + 9 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 library/std/src/net/hostname.rs create mode 100644 library/std/src/sys/net/hostname/mod.rs create mode 100644 library/std/src/sys/net/hostname/unix.rs create mode 100644 library/std/src/sys/net/hostname/unsupported.rs create mode 100644 library/std/src/sys/net/hostname/windows.rs diff --git a/library/std/src/net/hostname.rs b/library/std/src/net/hostname.rs new file mode 100644 index 000000000000..b1010cec6005 --- /dev/null +++ b/library/std/src/net/hostname.rs @@ -0,0 +1,22 @@ +use crate::ffi::OsString; + +/// Returns the system hostname. +/// +/// This can error out in platform-specific error cases; +/// for example, uefi and wasm, where hostnames aren't +/// supported. +/// +/// # Underlying system calls +/// +/// | Platform | System call | +/// |----------|---------------------------------------------------------------------------------------------------------| +/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) | +/// | Windows | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) | +/// +/// Note that platform-specific behavior [may change in the future][changes]. +/// +/// [changes]: crate::io#platform-specific-behavior +#[unstable(feature = "gethostname", issue = "135142")] +pub fn hostname() -> crate::io::Result { + crate::sys::net::hostname() +} diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index 40f1a93e39de..3e4447eb33f2 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -1,7 +1,8 @@ //! Networking primitives for TCP/UDP communication. //! //! This module provides networking functionality for the Transmission Control and User -//! Datagram Protocols, as well as types for IP and socket addresses. +//! Datagram Protocols, as well as types for IP and socket addresses and functions related +//! to network properties. //! //! # Organization //! @@ -24,6 +25,8 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use core::net::AddrParseError; +#[unstable(feature = "gethostname", issue = "135142")] +pub use self::hostname::hostname; #[stable(feature = "rust1", since = "1.0.0")] pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] @@ -35,6 +38,7 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::udp::UdpSocket; +mod hostname; mod ip_addr; mod socket_addr; mod tcp; diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs new file mode 100644 index 000000000000..a4b5b76059d3 --- /dev/null +++ b/library/std/src/sys/net/hostname/mod.rs @@ -0,0 +1,14 @@ +cfg_select! { + target_family = "unix" => { + mod unix; + pub use unix::hostname; + } + target_os = "windows" => { + mod windows; + pub use windows::hostname; + } + _ => { + mod unsupported; + pub use unsupported::hostname; + } +} diff --git a/library/std/src/sys/net/hostname/unix.rs b/library/std/src/sys/net/hostname/unix.rs new file mode 100644 index 000000000000..bc6fa82a38f0 --- /dev/null +++ b/library/std/src/sys/net/hostname/unix.rs @@ -0,0 +1,62 @@ +use crate::ffi::OsString; +use crate::io; +use crate::os::unix::ffi::OsStringExt; +use crate::sys::pal::os::errno; + +pub fn hostname() -> io::Result { + // Query the system for the maximum host name length. + let host_name_max = match unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) } { + // If this fails (possibly because there is no maximum length), then + // assume a maximum length of _POSIX_HOST_NAME_MAX (255). + -1 => 255, + max => max as usize, + }; + + // Reserve space for the nul terminator too. + let mut buf = Vec::::try_with_capacity(host_name_max + 1)?; + loop { + // SAFETY: `buf.capacity()` bytes of `buf` are writable. + let r = unsafe { libc::gethostname(buf.as_mut_ptr().cast(), buf.capacity()) }; + match (r != 0).then(errno) { + None => { + // Unfortunately, the UNIX specification says that the name will + // be truncated if it does not fit in the buffer, without returning + // an error. As additionally, the truncated name may still be null- + // terminated, there is no reliable way to detect truncation. + // Fortunately, most platforms ignore what the specification says + // and return an error (mostly ENAMETOOLONG). Should that not be + // the case, the following detects truncation if the null-terminator + // was omitted. Note that this check does not impact performance at + // all as we need to find the length of the string anyways. + // + // Use `strnlen` as it does not place an initialization requirement + // on the bytes after the nul terminator. + // + // SAFETY: `buf.capacity()` bytes of `buf` are accessible, and are + // initialized up to and including a possible nul terminator. + let len = unsafe { libc::strnlen(buf.as_ptr().cast(), buf.capacity()) }; + if len < buf.capacity() { + // If the string is nul-terminated, we assume that is has not + // been truncated, as the capacity *should be* enough to hold + // `HOST_NAME_MAX` bytes. + // SAFETY: `len + 1` bytes have been initialized (we exclude + // the nul terminator from the string). + unsafe { buf.set_len(len) }; + return Ok(OsString::from_vec(buf)); + } + } + // As `buf.capacity()` is always less than or equal to `isize::MAX` + // (Rust allocations cannot exceed that limit), the only way `EINVAL` + // can be returned is if the system uses `EINVAL` to report that the + // name does not fit in the provided buffer. In that case (or in the + // case of `ENAMETOOLONG`), resize the buffer and try again. + Some(libc::EINVAL | libc::ENAMETOOLONG) => {} + // Other error codes (e.g. EPERM) have nothing to do with the buffer + // size and should be returned to the user. + Some(err) => return Err(io::Error::from_raw_os_error(err)), + } + + // Resize the buffer (according to `Vec`'s resizing rules) and try again. + buf.try_reserve(buf.capacity() + 1)?; + } +} diff --git a/library/std/src/sys/net/hostname/unsupported.rs b/library/std/src/sys/net/hostname/unsupported.rs new file mode 100644 index 000000000000..d868f68f32dd --- /dev/null +++ b/library/std/src/sys/net/hostname/unsupported.rs @@ -0,0 +1,6 @@ +use crate::ffi::OsString; +use crate::io::{Error, Result}; + +pub fn hostname() -> Result { + Err(Error::UNSUPPORTED_PLATFORM) +} diff --git a/library/std/src/sys/net/hostname/windows.rs b/library/std/src/sys/net/hostname/windows.rs new file mode 100644 index 000000000000..24eed100f32d --- /dev/null +++ b/library/std/src/sys/net/hostname/windows.rs @@ -0,0 +1,24 @@ +use crate::ffi::OsString; +use crate::io::Result; +use crate::mem::MaybeUninit; +use crate::os::windows::ffi::OsStringExt; +use crate::sys::pal::c; +use crate::sys::pal::winsock::{self, cvt}; + +pub fn hostname() -> Result { + winsock::startup(); + + // The documentation of GetHostNameW says that a buffer size of 256 is + // always enough. + let mut buffer = [const { MaybeUninit::::uninit() }; 256]; + // SAFETY: these parameters specify a valid, writable region of memory. + cvt(unsafe { c::GetHostNameW(buffer.as_mut_ptr().cast(), buffer.len() as i32) })?; + // Use `lstrlenW` here as it does not require the bytes after the nul + // terminator to be initialized. + // SAFETY: if `GetHostNameW` returns successfully, the name is nul-terminated. + let len = unsafe { c::lstrlenW(buffer.as_ptr().cast()) }; + // SAFETY: the length of the name is `len`, hence `len` bytes have been + // initialized by `GetHostNameW`. + let name = unsafe { buffer[..len as usize].assume_init_ref() }; + Ok(OsString::from_wide(name)) +} diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs index dffc4ea7f81a..bfe5cf531287 100644 --- a/library/std/src/sys/net/mod.rs +++ b/library/std/src/sys/net/mod.rs @@ -2,3 +2,6 @@ /// `UdpSocket` as well as related functionality like DNS resolving. mod connection; pub use connection::*; + +mod hostname; +pub use hostname::hostname; diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index abc1c19827fe..9009aa09f48e 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2170,6 +2170,7 @@ GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW GetFullPathNameW +GetHostNameW GetLastError GetModuleFileNameW GetModuleHandleA @@ -2270,6 +2271,7 @@ LPPROGRESS_ROUTINE LPPROGRESS_ROUTINE_CALLBACK_REASON LPTHREAD_START_ROUTINE LPWSAOVERLAPPED_COMPLETION_ROUTINE +lstrlenW M128A MAX_PATH MAXIMUM_REPARSE_DATA_BUFFER_SIZE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 989a1246650c..98f277b33780 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -49,6 +49,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); +windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE); @@ -134,6 +135,7 @@ windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : * windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32); +windows_targets::link!("kernel32.dll" "system" fn lstrlenW(lpstring : PCWSTR) -> i32); windows_targets::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32); windows_targets::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32); From 04ee9915897ba66a768440e1aaeaf1e63f14ba02 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:16:10 +0100 Subject: [PATCH 390/537] Fix removed version of `doc_auto_cfg`, `doc_cfg_hide` --- compiler/rustc_feature/src/removed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 3c51f91331a6..539d67e0b6bc 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -102,9 +102,9 @@ declare_features! ( /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (removed, doc_auto_cfg, "1.58.0", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows `#[doc(cfg_hide(...))]`. - (removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.58.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`"), 90420), From 9c97ba700e8d4059f8394efa19e6e9487def7afb Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 29 Sep 2025 11:20:40 +0200 Subject: [PATCH 391/537] add joboet to library review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 2d58c616bc27..a04f8d280723 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1382,6 +1382,7 @@ libs = [ "@tgross35", "@thomcc", "@ibraheemdev", + "@joboet", ] infra-ci = [ "@Mark-Simulacrum", From af8fd78142bf394ac904402adb736f4c2f1efbc6 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 29 Sep 2025 11:24:20 +0200 Subject: [PATCH 392/537] Emit allocator attributes for allocator shim This emits the same attributes we place on allocator declarations (and allocator definitions using `#[global_allocator]`) on the definitions in the allocator shim as well, making sure that the attributes are not lost if the allocator shim participates in LTO. --- compiler/rustc_codegen_llvm/src/allocator.rs | 30 +++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index abd631203973..896d6755c752 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -5,9 +5,10 @@ use rustc_ast::expand::allocator::{ }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; +use rustc_span::sym; use rustc_symbol_mangling::mangle_internal_symbol; use crate::attributes::llfn_attrs_from_instance; @@ -59,7 +60,26 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false); + let alloc_attr_flag = match method.name { + sym::alloc => CodegenFnAttrFlags::ALLOCATOR, + sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR, + sym::realloc => CodegenFnAttrFlags::REALLOCATOR, + sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED, + _ => unreachable!("Unknown allocator method!"), + }; + + let mut attrs = CodegenFnAttrs::new(); + attrs.flags |= alloc_attr_flag; + create_wrapper_function( + tcx, + &cx, + &from_name, + Some(&to_name), + &args, + output, + false, + &attrs, + ); } } @@ -72,6 +92,7 @@ pub(crate) unsafe fn codegen( &[usize, usize], // size, align None, true, + &CodegenFnAttrs::new(), ); unsafe { @@ -93,6 +114,7 @@ pub(crate) unsafe fn codegen( &[], None, false, + &CodegenFnAttrs::new(), ); } @@ -139,6 +161,7 @@ fn create_wrapper_function( args: &[&Type], output: Option<&Type>, no_return: bool, + attrs: &CodegenFnAttrs, ) { let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void())); let llfn = declare_simple_fn( @@ -150,8 +173,7 @@ fn create_wrapper_function( ty, ); - let attrs = CodegenFnAttrs::new(); - llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None); + llfn_attrs_from_instance(cx, tcx, llfn, attrs, None); let no_return = if no_return { // -> ! DIFlagNoReturn From 2e63708d39553ed882a20a198cdc0f269bb6cd30 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Sep 2025 13:43:25 +0200 Subject: [PATCH 393/537] Improve code comments --- src/librustdoc/clean/types.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d4f0a196eda8..e4d33416883c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1084,7 +1084,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator let mut changed_auto_active_status = None; - // First we get all `doc(auto_cfg)` attributes. + // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes. for attr in attrs { if let Some(ident) = attr.ident() && ident.name == sym::doc @@ -1146,11 +1146,9 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } } } - // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because - // `doc(cfg())` overrides `cfg()`). } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { - // treat #[target_feature(enable = "feat")] attributes as if they were - // #[doc(cfg(target_feature = "feat"))] attributes as well + // Treat `#[target_feature(enable = "feat")]` attributes as if they were + // `#[doc(cfg(target_feature = "feat"))]` attributes as well. for (feature, _) in features { cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); } From 5df0be398845fa8b239f3e722c25b8369498df5c Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 26 Aug 2025 08:52:54 -0400 Subject: [PATCH 394/537] Make macOS dist build configuration match where reasonable --- src/ci/github-actions/jobs.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 8303699ce8a6..4384ec767697 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -430,7 +430,8 @@ auto: # Ensure that host tooling is built to support our minimum support macOS version. MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 - SELECT_XCODE: /Applications/Xcode_15.2.app + SELECT_XCODE: /Applications/Xcode_15.4.app + USE_XCODE_CLANG: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos @@ -450,21 +451,24 @@ auto: - name: dist-aarch64-apple env: - SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin + SCRIPT: >- + ./x.py dist bootstrap + --include-default-paths + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin RUST_CONFIGURE_ARGS: >- --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - --set llvm.ninja=false --set rust.lto=thin --set rust.codegen-units=1 - SELECT_XCODE: /Applications/Xcode_15.4.app - USE_XCODE_CLANG: 1 # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else # supports the hardware. MACOSX_DEPLOYMENT_TARGET: 11.0 MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + SELECT_XCODE: /Applications/Xcode_15.4.app + USE_XCODE_CLANG: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos From 098a56890f25eaca5063988b0b0840fad83db250 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Sep 2025 13:52:33 +0200 Subject: [PATCH 395/537] Fn-trait goals, eagerly instantiate binder to avoid overflow from proving `for<'a> opaque<'a>: Sized` --- .../src/solve/assembly/structural_traits.rs | 5 +- .../src/solve/effect_goals.rs | 21 ++- .../src/solve/normalizes_to/mod.rs | 135 ++++++++---------- .../src/solve/trait_goals.rs | 46 +++--- 4 files changed, 90 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c40739d12e68..9b3dc1f691fb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine( pub(in crate::solve) fn extract_fn_def_from_const_callable( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder, I::FunctionId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder, I::FunctionId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); @@ -673,7 +673,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( && cx.fn_is_const(def_id) { Ok(( - sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())), + sig.instantiate(cx, args) + .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), def_id, args, )) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index cb72c1cd92b8..65a5edf6b725 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -234,12 +234,12 @@ where let self_ty = goal.predicate.self_ty(); let (inputs_and_output, def_id, args) = structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; + let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); let requirements = cx .const_conditions(def_id.into()) .iter_instantiated(cx, args) @@ -251,15 +251,12 @@ where }) .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]); - let pred = inputs_and_output - .map_bound(|(inputs, _)| { - ty::TraitRef::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())], - ) - }) - .to_host_effect_clause(cx, goal.predicate.constness); + let pred = ty::Binder::dummy(ty::TraitRef::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + )) + .to_host_effect_clause(cx, goal.predicate.constness); Self::probe_and_consider_implied_clause( ecx, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 653c59c5d424..0674b3d42ab4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -451,23 +451,22 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), inputs], - ), - term: output.into(), - }) - .upcast(cx); + let pred = ty::ProjectionPredicate { + projection_term: ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + ), + term: output.into(), + } + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, @@ -497,76 +496,56 @@ where goal_kind, env_region, )?; + let AsyncCallableRelevantTypes { + tupled_inputs_ty, + output_coroutine_ty, + coroutine_return_ty, + } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( - |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::new( - cx, - cx.require_trait_lang_item(SolverTraitLangItem::Sized), - [output_ty], - ) - }, + let output_is_sized_pred = ty::TraitRef::new( + cx, + cx.require_trait_lang_item(SolverTraitLangItem::Sized), + [output_coroutine_ty], ); - let pred = tupled_inputs_and_output_and_coroutine - .map_bound( - |AsyncCallableRelevantTypes { - tupled_inputs_ty, - output_coroutine_ty, - coroutine_return_ty, - }| { - let (projection_term, term) = if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::CallOnceFuture) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ), - output_coroutine_ty.into(), - ) - } else if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::CallRefFuture) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - env_region.into(), - ], - ), - output_coroutine_ty.into(), - ) - } else if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::AsyncFnOnceOutput) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - ], - ), - coroutine_return_ty.into(), - ) - } else { - panic!( - "no such associated type in `AsyncFn*`: {:?}", - goal.predicate.def_id() - ) - }; - ty::ProjectionPredicate { projection_term, term } - }, - ) - .upcast(cx); + let (projection_term, term) = + if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallOnceFuture) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallRefFuture) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [ + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::AsyncFnOnceOutput) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + coroutine_return_ty.into(), + ) + } else { + panic!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) + }; + let pred = ty::ProjectionPredicate { projection_term, term }.upcast(cx); Self::probe_and_consider_implied_clause( ecx, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 3974114e9b43..e790ecd595be 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -369,18 +369,16 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, _)| { - ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) - }) - .upcast(cx); + let pred = + ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -408,28 +406,26 @@ where // This region doesn't matter because we're throwing away the coroutine type Region::new_static(cx), )?; + let AsyncCallableRelevantTypes { + tupled_inputs_ty, + output_coroutine_ty, + coroutine_return_ty: _, + } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( - |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { - ty::TraitRef::new( - cx, - cx.require_trait_lang_item(SolverTraitLangItem::Sized), - [output_coroutine_ty], - ) - }, + let output_is_sized_pred = ty::TraitRef::new( + cx, + cx.require_trait_lang_item(SolverTraitLangItem::Sized), + [output_coroutine_ty], ); - let pred = tupled_inputs_and_output_and_coroutine - .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| { - ty::TraitRef::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ) - }) - .upcast(cx); + let pred = ty::TraitRef::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ) + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), From 0f2b79c36dcc4ec66125d6fa87694c7f5d39ebe8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Sep 2025 13:57:41 +0200 Subject: [PATCH 396/537] add tests --- .../opaques/overflow-hr-fn-trait-sized-1.rs | 25 +++++++++++++++++++ .../opaques/overflow-hr-fn-trait-sized-2.rs | 14 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-1.rs create mode 100644 tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-2.rs diff --git a/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-1.rs b/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-1.rs new file mode 100644 index 000000000000..e35e48dfcecb --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-1.rs @@ -0,0 +1,25 @@ +//@ ignore-compare-mode-next-solver +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#220. Builtin `Fn`-trait +// candidates required `for<'latebound> Output<'latebound>: Sized` which ended +// up resulting in overflow if the return type is an opaque in the defining scope. +// +// We now eagerly instantiate the binder of the function definition which avoids +// that overflow by relating the lifetime of the opaque to something from the +// input. +fn flat_map(_: F, _: G) +where + F: FnOnce(T) -> I, + I: Iterator, + G: Fn(::Item) -> usize, +{ +} + +fn rarw<'a>(_: &'a ()) -> impl Iterator { + flat_map(rarw, |x| x.len()); + std::iter::empty() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-2.rs b/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-2.rs new file mode 100644 index 000000000000..1d64e422d893 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/overflow-hr-fn-trait-sized-2.rs @@ -0,0 +1,14 @@ +//@ ignore-compare-mode-next-solver +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#204, see +// the sibling test for more details. + +fn constrain<'a, F: FnOnce(&'a ())>(_: F) {} +fn foo<'a>(_: &'a ()) -> impl Sized + use<'a> { + constrain(foo); + () +} + +fn main() {} From 07806a1132f156ffad8c9edaed08825cd09fbce5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Sep 2025 13:57:51 +0200 Subject: [PATCH 397/537] cleanup `try_evaluate_added_goals` --- .../src/solve/eval_ctxt/mod.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 85110530ae9b..f25003bbfe92 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -633,28 +633,19 @@ where // the certainty of all the goals. #[instrument(level = "trace", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result { - let mut response = Ok(Certainty::overflow(false)); for _ in 0..FIXPOINT_STEP_LIMIT { - // FIXME: This match is a bit ugly, it might be nice to change the inspect - // stuff to use a closure instead. which should hopefully simplify this a bit. match self.evaluate_added_goals_step() { - Ok(Some(cert)) => { - response = Ok(cert); - break; - } Ok(None) => {} + Ok(Some(cert)) => return Ok(cert), Err(NoSolution) => { - response = Err(NoSolution); - break; + self.tainted = Err(NoSolution); + return Err(NoSolution); } } } - if response.is_err() { - self.tainted = Err(NoSolution); - } - - response + debug!("try_evaluate_added_goals: encountered overflow"); + Ok(Certainty::overflow(false)) } /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning. From 9f667cdd243d905848ccfc031f4c1373828c9a7d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 29 Sep 2025 10:34:19 -0400 Subject: [PATCH 398/537] Add `overlapping_assoc_constraints` param to `lower_bounds` --- .../src/collect/item_bounds.rs | 20 ++++++++++++++++--- .../src/collect/predicates_of.rs | 18 +++++++++++++++-- .../src/hir_ty_lowering/bounds.rs | 4 +++- .../src/hir_ty_lowering/mod.rs | 1 + 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index ba54fa8cc0db..9841fafc82c1 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -12,7 +12,7 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::predicates_of::assert_only_contains_predicates_from; -use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter}; +use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter}; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + item_ty, + hir_bounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); match filter { PredicateFilter::All @@ -347,7 +354,14 @@ fn opaque_type_bounds<'tcx>( ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + item_ty, + hir_bounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); // Implicit bounds are added to opaque types unless a `?Trait` bound is found match filter { PredicateFilter::All diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index dd3590f9ac5d..ffdf2a2f4c0c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; -use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, +}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus @@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, ty::List::empty(), PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); icx.lowerer().add_sizedness_bounds( &mut bounds, @@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, bound_vars, PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); predicates.extend(bounds); } @@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let self_param_ty = tcx.types.self_param; let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + self_param_ty, + superbounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); match filter { PredicateFilter::All | PredicateFilter::SelfOnly @@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> { &mut bounds, bound_vars, filter, + OverlappingAsssocItemConstraints::Allowed, ); } @@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, bound_vars, PredicateFilter::ConstIfConst, + OverlappingAsssocItemConstraints::Allowed, ); } _ => {} @@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, ty::List::empty(), PredicateFilter::ConstIfConst, + OverlappingAsssocItemConstraints::Allowed, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a59520f16feb..8682fdc54942 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -339,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, bound_vars: &'tcx ty::List, predicate_filter: PredicateFilter, + overlapping_assoc_constraints: OverlappingAsssocItemConstraints, ) where 'tcx: 'hir, { @@ -363,7 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { param_ty, bounds, predicate_filter, - OverlappingAsssocItemConstraints::Allowed, + overlapping_assoc_constraints, ); } hir::GenericBound::Outlives(lifetime) => { @@ -604,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds, projection_ty.bound_vars(), predicate_filter, + OverlappingAsssocItemConstraints::Allowed, ); } PredicateFilter::SelfOnly diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index cc5c0d0ad6ce..eb660804c2b5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2497,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut bounds, ty::List::empty(), PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); self.add_sizedness_bounds( &mut bounds, From adf9cbd69ccd9c1e973fe179fbf3e53b23b4a5ae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:31:54 +0000 Subject: [PATCH 399/537] Add a dummy codegen backend This allows building a rustc capable of running the frontend without any backend present. While this may not seem all that useful, it allows running the frontend of rustc to report errors or running miri to interpret a program without any backend present. This is useful when you are trying to say run miri in the browser as upstream LLVM can't be compiled for wasm yet. Or to run rustc itself in miri like I did a while ago and caught some UB. --- compiler/rustc_interface/src/util.rs | 74 ++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 76ccd12797e5..6a6e64773f35 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,3 +1,4 @@ +use std::any::Any; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -6,13 +7,20 @@ use std::{env, thread}; use rustc_ast as ast; use rustc_attr_parsing::{ShouldEmit, validate_attr}; +use rustc_codegen_ssa::back::archive::ArArchiveBuilderBuilder; +use rustc_codegen_ssa::back::link::link_binary; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_codegen_ssa::{CodegenResults, CrateInfo}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; use rustc_errors::LintBuffer; -use rustc_metadata::{DylibError, load_symbol_from_dylib}; -use rustc_middle::ty::CurrentGcx; -use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple}; +use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::ty::{CurrentGcx, TyCtxt}; +use rustc_session::config::{ + Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple, +}; use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint}; use rustc_span::edit_distance::find_best_match_for_name; @@ -316,12 +324,13 @@ pub fn get_codegen_backend( let backend = backend_name .or(target.default_codegen_backend.as_deref()) .or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND")) - .unwrap_or("llvm"); + .unwrap_or("dummy"); match backend { filename if filename.contains('.') => { load_backend_from_dylib(early_dcx, filename.as_ref()) } + "dummy" => || Box::new(DummyCodegenBackend), #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name), @@ -334,6 +343,63 @@ pub fn get_codegen_backend( unsafe { load() } } +struct DummyCodegenBackend; + +impl CodegenBackend for DummyCodegenBackend { + fn locale_resource(&self) -> &'static str { + "" + } + + fn name(&self) -> &'static str { + "dummy" + } + + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box { + Box::new(CodegenResults { + modules: vec![], + allocator_module: None, + crate_info: CrateInfo::new(tcx, String::new()), + }) + } + + fn join_codegen( + &self, + ongoing_codegen: Box, + _sess: &Session, + _outputs: &OutputFilenames, + ) -> (CodegenResults, FxIndexMap) { + (*ongoing_codegen.downcast().unwrap(), FxIndexMap::default()) + } + + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { + // JUSTIFICATION: TyCtxt no longer available here + #[allow(rustc::bad_opt_access)] + if sess.opts.crate_types.iter().any(|&crate_type| crate_type != CrateType::Rlib) { + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + sess.dcx().fatal(format!( + "crate type {} not supported by the dummy codegen backend", + sess.opts.crate_types[0], + )); + } + + link_binary( + sess, + &ArArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); + } +} + // This is used for rustdoc, but it uses similar machinery to codegen backend // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. From 66b664c9961e54282fbaccef72f90dfa7dd1418f Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Mon, 29 Sep 2025 16:05:44 +0100 Subject: [PATCH 400/537] more rename --- compiler/rustc_borrowck/src/lib.rs | 7 +++-- .../src/region_infer/opaque_types/mod.rs | 29 +++++++++++-------- compiler/rustc_borrowck/src/root_cx.rs | 14 ++++----- compiler/rustc_hir_typeck/src/opaque_types.rs | 8 ++--- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- 7 files changed, 36 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d799eb1f8c6e..268cb47fd126 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -116,7 +116,10 @@ pub fn provide(providers: &mut Providers) { /// Provider for `query mir_borrowck`. Similar to `typeck`, this must /// only be called for typeck roots which will then borrowck all /// nested bodies as well. -fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<&HiddenTypes<'_>, ErrorGuaranteed> { +fn mir_borrowck( + tcx: TyCtxt<'_>, + def: LocalDefId, +) -> Result<&DefinitionSiteHiddenTypes<'_>, ErrorGuaranteed> { assert!(!tcx.is_typeck_child(def.to_def_id())); let (input_body, _) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); @@ -127,7 +130,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<&HiddenTypes<'_>, Er Err(guar) } else if input_body.should_skip() { debug!("Skipping borrowck because of injected body"); - let opaque_types = HiddenTypes(Default::default()); + let opaque_types = DefinitionSiteHiddenTypes(Default::default()); Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 6aa3345d4d42..8d89f3e0d870 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries}; use rustc_infer::traits::ObligationCause; use rustc_macros::extension; -use rustc_middle::mir::{Body, ConstraintCategory, HiddenTypes}; +use rustc_middle::mir::{Body, ConstraintCategory, DefinitionSiteHiddenTypes}; use rustc_middle::ty::{ self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, @@ -131,7 +131,7 @@ fn nll_var_to_universal_region<'tcx>( /// and errors if we end up with distinct hidden types. fn add_hidden_type<'tcx>( tcx: TyCtxt<'tcx>, - hidden_types: &mut HiddenTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, def_id: LocalDefId, hidden_ty: OpaqueHiddenType<'tcx>, ) { @@ -156,7 +156,7 @@ fn add_hidden_type<'tcx>( } fn get_hidden_type<'tcx>( - hidden_types: &HiddenTypes<'tcx>, + hidden_types: &DefinitionSiteHiddenTypes<'tcx>, def_id: LocalDefId, ) -> Option>> { hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) @@ -183,12 +183,12 @@ struct DefiningUse<'tcx> { /// /// It also means that this whole function is not really soundness critical as we /// recheck all uses of the opaques regardless. -pub(crate) fn compute_hidden_types<'tcx>( +pub(crate) fn compute_definition_site_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, universal_region_relations: &Frozen>, constraints: &MirTypeckRegionConstraints<'tcx>, location_map: Rc, - hidden_types: &mut HiddenTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec> { let mut errors = Vec::new(); @@ -211,14 +211,19 @@ pub(crate) fn compute_hidden_types<'tcx>( // After applying member constraints, we now check whether all member regions ended // up equal to one of their choice regions and compute the actual hidden type of // the opaque type definition. This is stored in the `root_cx`. - compute_hidden_types_from_defining_uses(&rcx, hidden_types, &defining_uses, &mut errors); + compute_definition_site_hidden_types_from_defining_uses( + &rcx, + hidden_types, + &defining_uses, + &mut errors, + ); errors } #[instrument(level = "debug", skip_all, ret)] fn collect_defining_uses<'tcx>( rcx: &mut RegionCtxt<'_, 'tcx>, - hidden_types: &mut HiddenTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], errors: &mut Vec>, ) -> Vec> { @@ -271,9 +276,9 @@ fn collect_defining_uses<'tcx>( defining_uses } -fn compute_hidden_types_from_defining_uses<'tcx>( +fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( rcx: &RegionCtxt<'_, 'tcx>, - hidden_types: &mut HiddenTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, defining_uses: &[DefiningUse<'tcx>], errors: &mut Vec>, ) { @@ -483,14 +488,14 @@ impl<'tcx> FallibleTypeFolder> for ToArgRegionsFolder<'_, 'tcx> { /// /// It does this by equating the hidden type of each use with the instantiated final /// hidden type of the opaque. -pub(crate) fn apply_hidden_types<'tcx>( +pub(crate) fn apply_definition_site_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, region_bound_pairs: &RegionBoundPairs<'tcx>, known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], constraints: &mut MirTypeckRegionConstraints<'tcx>, - hidden_types: &mut HiddenTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec> { let tcx = infcx.tcx; @@ -561,7 +566,7 @@ pub(crate) fn apply_hidden_types<'tcx>( errors } -/// In theory `apply_hidden_types` could introduce new uses of opaque types. +/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types. /// We do not check these new uses so this could be unsound. /// /// We detect any new uses and simply delay a bug if they occur. If this results in diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index d9599bbdd461..21c11e128735 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -12,12 +12,12 @@ use smallvec::SmallVec; use crate::consumers::BorrowckConsumer; use crate::nll::compute_closure_requirements_modulo_opaques; use crate::region_infer::opaque_types::{ - apply_hidden_types, clone_and_resolve_opaque_types, compute_hidden_types, - detect_opaque_types_added_while_handling_opaque_types, + apply_definition_site_hidden_types, clone_and_resolve_opaque_types, + compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types, }; use crate::type_check::{Locations, constraint_conversion}; use crate::{ - ClosureRegionRequirements, CollectRegionConstraintsResult, HiddenTypes, + ClosureRegionRequirements, CollectRegionConstraintsResult, DefinitionSiteHiddenTypes, PropagatedBorrowCheckResults, borrowck_check_region_constraints, borrowck_collect_region_constraints, }; @@ -27,7 +27,7 @@ use crate::{ pub(super) struct BorrowCheckRootCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, root_def_id: LocalDefId, - hidden_types: HiddenTypes<'tcx>, + hidden_types: DefinitionSiteHiddenTypes<'tcx>, /// The region constraints computed by [borrowck_collect_region_constraints]. This uses /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before /// their parents. @@ -72,7 +72,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars } - pub(super) fn finalize(self) -> Result<&'tcx HiddenTypes<'tcx>, ErrorGuaranteed> { + pub(super) fn finalize(self) -> Result<&'tcx DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> { if let Some(guar) = self.tainted_by_errors { Err(guar) } else { @@ -88,7 +88,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &input.universal_region_relations, &mut input.constraints, ); - input.deferred_opaque_type_errors = compute_hidden_types( + input.deferred_opaque_type_errors = compute_definition_site_hidden_types( &input.infcx, &input.universal_region_relations, &input.constraints, @@ -103,7 +103,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.collect_region_constraints_results.values_mut().zip(per_body_info) { if input.deferred_opaque_type_errors.is_empty() { - input.deferred_opaque_type_errors = apply_hidden_types( + input.deferred_opaque_type_errors = apply_definition_site_hidden_types( &input.infcx, &input.body_owned, &input.universal_region_relations.universal_regions, diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index a47fa202acfe..4c1fe69405e9 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -35,8 +35,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } debug!(?opaque_types); - self.compute_hidden_types(&opaque_types); - self.apply_hidden_types(&opaque_types); + self.compute_definition_site_hidden_types(&opaque_types); + self.apply_definition_site_hidden_types(&opaque_types); } } @@ -71,7 +71,7 @@ impl<'tcx> UsageKind<'tcx> { } impl<'tcx> FnCtxt<'_, 'tcx> { - fn compute_hidden_types( + fn compute_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { @@ -203,7 +203,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { UsageKind::HasDefiningUse } - fn apply_hidden_types( + fn apply_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index a63030b11452..feaad5bb96eb 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,7 +27,7 @@ macro_rules! arena_types { rustc_middle::mir::Body<'tcx> >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, - [decode] borrowck_result: rustc_middle::mir::HiddenTypes<'tcx>, + [decode] borrowck_result: rustc_middle::mir::DefinitionSiteHiddenTypes<'tcx>, [] resolver: rustc_data_structures::steal::Steal<( rustc_middle::ty::ResolverAstLowering, std::sync::Arc, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 791565e387e8..2e6c9f207e26 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -87,7 +87,7 @@ impl Debug for CoroutineLayout<'_> { /// All the opaque types that have had their hidden type fully computed. /// Unlike the value in `TypeckResults`, this has unerased regions. #[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct HiddenTypes<'tcx>(pub FxIndexMap>); +pub struct DefinitionSiteHiddenTypes<'tcx>(pub FxIndexMap>); /// The result of the `mir_const_qualif` query. /// diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1efb29c788d4..895c8c0295a0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1244,7 +1244,7 @@ rustc_queries! { /// Borrow-checks the given typeck root, e.g. functions, const/static items, /// and its children, e.g. closures, inline consts. - query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::HiddenTypes<'tcx>, ErrorGuaranteed> { + query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } } From f4a865fea72cbbd1478cada7af19c1bcf0b9d588 Mon Sep 17 00:00:00 2001 From: Oblarg Date: Mon, 29 Sep 2025 11:04:24 -0400 Subject: [PATCH 401/537] move test per review feedback --- .../crates/ide/src/hover/tests.rs | 42 ++++++++ .../rust-analyzer/crates/mbe/src/tests.rs | 97 ------------------- 2 files changed, 42 insertions(+), 97 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 1ea11a215f83..8bc0b3f6ab3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -4796,6 +4796,48 @@ fn main() { ); } +#[test] +fn const_generic_negative_literal_macro_expansion() { + // Test that negative literals work correctly in const generics + // when used through macro expansion. This ensures the transcriber + // doesn't wrap negative literals in parentheses, which would create + // invalid syntax like Foo::<(-1)> instead of Foo::<-1>. + check( + r#" +struct Foo { + pub value: i16, +} + +impl Foo { + pub fn new(value: i16) -> Self { + Self { value } + } +} + +macro_rules! create_foo { + ($val:expr) => { + Foo::<$val>::new($val) + }; +} + +fn main() { + let v$0alue = create_foo!(-1); +} +"#, + expect![[r#" + *value* + + ```rust + let value: Foo<-1> + ``` + + --- + + size = 2, align = 2, no Drop + "#]], + ); +} + #[test] fn hover_self_param_shows_type() { check( diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs index 589e169d30a3..56034516ef3b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -476,100 +476,3 @@ fn minus_belongs_to_literal() { --"#]], ); } - -#[test] -fn negative_literals_in_const_generics() { - // Test that negative literals work correctly in declarative macros - // when used as const generic arguments. The issue was that expressions - // like -1 would be wrapped in parentheses, creating invalid syntax - // Foo::<(-1)> instead of the correct Foo::<-1>. - let decl = r#" -($val:expr) => { - struct Foo { - pub value: i16, - } - - impl Foo { - pub fn new(value: i16) -> Self { - Self { value } - } - } - - Foo::<$val>::new($val) -}; -"#; - let check = |args, expect| check(Edition::CURRENT, Edition::CURRENT, decl, args, expect); - - // Test negative integer literal - should produce Foo::<-1>, not Foo::<(-1)> - check( - "-1", - expect![[r#" - SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024 - IDENT struct 0:Root[0000, 0]@22..28#ROOT2024 - IDENT Foo 0:Root[0000, 0]@29..32#ROOT2024 - PUNCH < [alone] 0:Root[0000, 0]@32..33#ROOT2024 - IDENT const 0:Root[0000, 0]@33..38#ROOT2024 - IDENT I 0:Root[0000, 0]@39..40#ROOT2024 - PUNCH : [alone] 0:Root[0000, 0]@40..41#ROOT2024 - IDENT i16 0:Root[0000, 0]@42..45#ROOT2024 - PUNCH > [alone] 0:Root[0000, 0]@45..46#ROOT2024 - SUBTREE {} 0:Root[0000, 0]@47..48#ROOT2024 0:Root[0000, 0]@77..78#ROOT2024 - IDENT pub 0:Root[0000, 0]@57..60#ROOT2024 - IDENT value 0:Root[0000, 0]@61..66#ROOT2024 - PUNCH : [alone] 0:Root[0000, 0]@66..67#ROOT2024 - IDENT i16 0:Root[0000, 0]@68..71#ROOT2024 - PUNCH , [alone] 0:Root[0000, 0]@71..72#ROOT2024 - IDENT impl 0:Root[0000, 0]@84..88#ROOT2024 - PUNCH < [alone] 0:Root[0000, 0]@88..89#ROOT2024 - IDENT const 0:Root[0000, 0]@89..94#ROOT2024 - IDENT I 0:Root[0000, 0]@95..96#ROOT2024 - PUNCH : [alone] 0:Root[0000, 0]@96..97#ROOT2024 - IDENT i16 0:Root[0000, 0]@98..101#ROOT2024 - PUNCH > [alone] 0:Root[0000, 0]@101..102#ROOT2024 - IDENT Foo 0:Root[0000, 0]@103..106#ROOT2024 - PUNCH < [alone] 0:Root[0000, 0]@106..107#ROOT2024 - IDENT I 0:Root[0000, 0]@107..108#ROOT2024 - PUNCH > [alone] 0:Root[0000, 0]@108..109#ROOT2024 - SUBTREE {} 0:Root[0000, 0]@110..111#ROOT2024 0:Root[0000, 0]@194..195#ROOT2024 - IDENT pub 0:Root[0000, 0]@120..123#ROOT2024 - IDENT fn 0:Root[0000, 0]@124..126#ROOT2024 - IDENT new 0:Root[0000, 0]@127..130#ROOT2024 - SUBTREE () 0:Root[0000, 0]@130..131#ROOT2024 0:Root[0000, 0]@141..142#ROOT2024 - IDENT value 0:Root[0000, 0]@131..136#ROOT2024 - PUNCH : [alone] 0:Root[0000, 0]@136..137#ROOT2024 - IDENT i16 0:Root[0000, 0]@138..141#ROOT2024 - PUNCH - [joint] 0:Root[0000, 0]@143..144#ROOT2024 - PUNCH > [alone] 0:Root[0000, 0]@144..145#ROOT2024 - IDENT Self 0:Root[0000, 0]@146..150#ROOT2024 - SUBTREE {} 0:Root[0000, 0]@151..152#ROOT2024 0:Root[0000, 0]@188..189#ROOT2024 - IDENT Self 0:Root[0000, 0]@165..169#ROOT2024 - SUBTREE {} 0:Root[0000, 0]@170..171#ROOT2024 0:Root[0000, 0]@178..179#ROOT2024 - IDENT value 0:Root[0000, 0]@172..177#ROOT2024 - IDENT Foo 0:Root[0000, 0]@201..204#ROOT2024 - PUNCH : [joint] 0:Root[0000, 0]@204..205#ROOT2024 - PUNCH : [joint] 0:Root[0000, 0]@205..206#ROOT2024 - PUNCH < [joint] 0:Root[0000, 0]@206..207#ROOT2024 - PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024 - LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024 - PUNCH > [joint] 0:Root[0000, 0]@211..212#ROOT2024 - PUNCH : [joint] 0:Root[0000, 0]@212..213#ROOT2024 - PUNCH : [alone] 0:Root[0000, 0]@213..214#ROOT2024 - IDENT new 0:Root[0000, 0]@214..217#ROOT2024 - SUBTREE () 0:Root[0000, 0]@217..218#ROOT2024 0:Root[0000, 0]@222..223#ROOT2024 - PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024 - LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024 - - struct Foo{ - pub value:i16, - } - impl Foo{ - pub fn new(value:i16) -> Self { - Self { - value - } - } - - } - Foo::<-1>::new(-1)"#]], - ); -} From 1a16755ea02e36828b1a235c3051a8f8341a741d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 29 Sep 2025 15:55:38 +0000 Subject: [PATCH 402/537] flatten conditional block --- .../rustc_hir_analysis/src/constrained_generic_params.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 44d7f3a5e8bc..6bcf06399e06 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -209,11 +209,8 @@ pub(crate) fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // then the projection only applies if `T` is known, but it still // does not determine `U`. + parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p)) { - let inputs = parameters_for(tcx, projection.projection_term, true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); - relies_only_on_inputs - } { input_parameters.extend(parameters_for(tcx, projection.term, false)); predicates.swap(i, j); From 06a6dcd4d276826a7600302c08a0d448e23c1d33 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Sep 2025 14:27:21 +0200 Subject: [PATCH 403/537] Move doc cfg propagation pass before items stripping passes --- src/librustdoc/passes/mod.rs | 4 ++-- tests/rustdoc-ui/issues/issue-91713.stdout | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 475d05b7d0e7..f45df8d2d0d5 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -77,11 +77,11 @@ pub(crate) enum Condition { pub(crate) const PASSES: &[Pass] = &[ CHECK_DOC_CFG, CHECK_DOC_TEST_VISIBILITY, + PROPAGATE_DOC_CFG, STRIP_ALIASED_NON_LOCAL, STRIP_HIDDEN, STRIP_PRIVATE, STRIP_PRIV_IMPORTS, - PROPAGATE_DOC_CFG, PROPAGATE_STABILITY, COLLECT_INTRA_DOC_LINKS, COLLECT_TRAIT_IMPLS, @@ -94,11 +94,11 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), ConditionalPass::always(CHECK_DOC_CFG), + ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), - ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), ConditionalPass::always(PROPAGATE_DOC_CFG), ConditionalPass::always(PROPAGATE_STABILITY), ConditionalPass::always(RUN_LINTS), diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index 30aadfe89f42..d34714be6c94 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,11 +1,11 @@ Available passes for running rustdoc: check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs check_doc_test_visibility - run various visibility-related lints on doctests + propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items strip-aliased-non-local - strips all non-local private aliased items from the output strip-hidden - strips all `#[doc(hidden)]` items from the output strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate - propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items propagate-stability - propagates stability to child items collect-intra-doc-links - resolves intra-doc links collect-trait-impls - retrieves trait impls for items in the crate @@ -16,11 +16,11 @@ Default passes for rustdoc: collect-trait-impls check_doc_test_visibility check-doc-cfg +collect-intra-doc-links strip-aliased-non-local strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) strip-priv-imports (when --document-private-items) -collect-intra-doc-links propagate-doc-cfg propagate-stability run-lints From 9119eba24de69902ba421151691d7a294d96fa04 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Sep 2025 14:31:21 +0200 Subject: [PATCH 404/537] Add regression test for doc cfg applied on public items inside private items --- tests/rustdoc/doc-auto-cfg-public-in-private.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/rustdoc/doc-auto-cfg-public-in-private.rs diff --git a/tests/rustdoc/doc-auto-cfg-public-in-private.rs b/tests/rustdoc/doc-auto-cfg-public-in-private.rs new file mode 100644 index 000000000000..b78e3f1b932c --- /dev/null +++ b/tests/rustdoc/doc-auto-cfg-public-in-private.rs @@ -0,0 +1,16 @@ +// This test ensures that even though private items are removed from generated docs, +// their `cfg`s will still impact their child items. + +#![feature(doc_cfg)] +#![crate_name = "foo"] + +pub struct X; + +#[cfg(not(feature = "blob"))] +fn foo() { + impl X { + //@ has 'foo/struct.X.html' + //@ has - '//*[@class="stab portability"]' 'Available on non-crate feature blob only.' + pub fn bar() {} + } +} From 9bb4081fb0977c1a8923fff6ebe60fc882bcac1d Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 29 Sep 2025 23:42:01 +0200 Subject: [PATCH 405/537] remove `reverse_{encode, decode}!` --- library/proc_macro/src/bridge/client.rs | 2 +- library/proc_macro/src/bridge/mod.rs | 20 -------------------- library/proc_macro/src/bridge/server.rs | 2 +- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index e7d547966a5d..4e519e56a1ed 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -144,7 +144,7 @@ macro_rules! define_client_side { buf.clear(); api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); - reverse_encode!(buf; $($arg),*); + $($arg.encode(&mut buf, &mut ());)* buf = bridge.dispatch.call(buf); diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index d60a76fff5dc..7fd67ba465ef 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -119,26 +119,6 @@ macro_rules! with_api_handle_types { }; } -// FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to match the ordering in `reverse_decode`. -macro_rules! reverse_encode { - ($writer:ident;) => {}; - ($writer:ident; $first:ident $(, $rest:ident)*) => { - reverse_encode!($writer; $($rest),*); - $first.encode(&mut $writer, &mut ()); - } -} - -// FIXME(eddyb) this calls `decode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. -macro_rules! reverse_decode { - ($reader:ident, $s:ident;) => {}; - ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { - reverse_decode!($reader, $s; $($rest: $rest_ty),*); - let $first = <$first_ty>::decode(&mut $reader, $s); - } -} - #[allow(unsafe_code)] mod arena; #[allow(unsafe_code)] diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 5beda7c3c96e..724ccbd96c59 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -178,7 +178,7 @@ macro_rules! define_dispatcher_impl { $(api_tags::Method::$name(m) => match m { $(api_tags::$name::$method => { let mut call_method = || { - reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); + $(let $arg = <$arg_ty>::decode(&mut reader, handle_store);)* $name::$method(server, $($arg),*) }; // HACK(eddyb) don't use `panic::catch_unwind` in a panic. From 23f340061395300415d551fdac92d28ca2f2fbfb Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 30 Sep 2025 00:01:17 +0200 Subject: [PATCH 406/537] remove unused `#![feature(stmt_expr_attributes)]` --- library/proc_macro/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 162b4fdcc8ae..613abd7024e3 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -27,7 +27,6 @@ #![feature(panic_can_unwind)] #![feature(restricted_std)] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![feature(extend_one)] #![recursion_limit = "256"] #![allow(internal_features)] From d7773f6b1c220d43946bce8010847837ad334b74 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 30 Sep 2025 00:09:12 +0200 Subject: [PATCH 407/537] explicitly implement `!Send` and `!Sync` --- library/proc_macro/src/bridge/client.rs | 17 ++++++----------- library/proc_macro/src/bridge/closure.rs | 4 +--- library/proc_macro/src/bridge/mod.rs | 8 +++----- library/proc_macro/src/bridge/server.rs | 14 ++------------ 4 files changed, 12 insertions(+), 31 deletions(-) diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 4e519e56a1ed..92558f2b7d9c 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -26,18 +26,16 @@ macro_rules! define_client_handles { $( pub(crate) struct $oty { handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, } + impl !Send for $oty {} + impl !Sync for $oty {} + // Forward `Drop::drop` to the inherent `drop` method. impl Drop for $oty { fn drop(&mut self) { $oty { handle: self.handle, - _marker: PhantomData, }.drop(); } } @@ -64,7 +62,6 @@ macro_rules! define_client_handles { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $oty { handle: handle::Handle::decode(r, s), - _marker: PhantomData, } } } @@ -74,12 +71,11 @@ macro_rules! define_client_handles { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct $ity { handle: handle::Handle, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual - // way of doing this, but that requires unstable features. - // rust-analyzer uses this code and avoids unstable features. - _marker: PhantomData<*mut ()>, } + impl !Send for $ity {} + impl !Sync for $ity {} + impl Encode for $ity { fn encode(self, w: &mut Writer, s: &mut S) { self.handle.encode(w, s); @@ -90,7 +86,6 @@ macro_rules! define_client_handles { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $ity { handle: handle::Handle::decode(r, s), - _marker: PhantomData, } } } diff --git a/library/proc_macro/src/bridge/closure.rs b/library/proc_macro/src/bridge/closure.rs index e0e688434dce..e5133907854b 100644 --- a/library/proc_macro/src/bridge/closure.rs +++ b/library/proc_macro/src/bridge/closure.rs @@ -6,9 +6,7 @@ use std::marker::PhantomData; pub(super) struct Closure<'a, A, R> { call: unsafe extern "C" fn(*mut Env, A) -> R, env: *mut Env, - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. + // Prevent Send and Sync impls. // // The `'a` lifetime parameter represents the lifetime of `Env`. _marker: PhantomData<*mut &'a mut ()>, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 7fd67ba465ef..1b09deb6bfe6 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -160,13 +160,11 @@ pub struct BridgeConfig<'a> { /// If 'true', always invoke the default panic hook force_show_panics: bool, - - // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing - // this, but that requires unstable features. rust-analyzer uses this code - // and avoids unstable features. - _marker: marker::PhantomData<*mut ()>, } +impl !Send for BridgeConfig<'_> {} +impl !Sync for BridgeConfig<'_> {} + #[forbid(unsafe_code)] #[allow(non_camel_case_types)] mod api_tags { diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 724ccbd96c59..0bb30698aa1d 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -295,12 +295,7 @@ impl ExecutionStrategy for SameThread { let mut dispatch = |buf| dispatcher.dispatch(buf); - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) + run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) } } @@ -331,12 +326,7 @@ where client.recv().expect("server died while client waiting for reply") }; - run_client(BridgeConfig { - input, - dispatch: (&mut dispatch).into(), - force_show_panics, - _marker: marker::PhantomData, - }) + run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics }) }); while let Some(b) = server.recv() { From 73f6b08022944d24fb5b623494a18cc95df21802 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Mon, 22 Sep 2025 10:59:39 -0700 Subject: [PATCH 408/537] Don't condition RUSTDOC_LIBDIR on `--no-doc` In d94e7ff065cd393a645eb3e9c96ce0418856e95d, `rustdoc_path` was changed to ignore `want_rustdoc` (which is just whether `--no-doc` was passed). But RUSTDOC_LIBDIR wasn't kept in sync. Rather than trying to keep `rustdoc_path` in sync with `RUSTDOC_LIBDIR`, just pass LIBDIR to the rustc shim unconditionally. This fix allows calling `ensure(doc::Step)` from a non-doc top-level Step, even if `--no-doc` was present in the command line. --- src/bootstrap/src/core/builder/cargo.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 9fc4ce669c2a..a404aec51209 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -10,7 +10,7 @@ use crate::core::config::flags::Color; use crate::utils::build_stamp; use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags}; use crate::{ - BootstrapCommand, CLang, Compiler, Config, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode, + BootstrapCommand, CLang, Compiler, Config, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode, RemapScheme, TargetSelection, command, prepare_behaviour_dump_dir, t, }; @@ -851,8 +851,6 @@ impl Builder<'_> { rustflags.arg("-Zmacro-backtrace"); - let want_rustdoc = self.doc_tests != DocTests::No; - // Clear the output directory if the real rustc we're using has changed; // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc. // @@ -881,7 +879,8 @@ impl Builder<'_> { .env("RUSTC_REAL", self.rustc(compiler)) .env("RUSTC_STAGE", build_compiler_stage.to_string()) .env("RUSTC_SYSROOT", sysroot) - .env("RUSTC_LIBDIR", libdir) + .env("RUSTC_LIBDIR", &libdir) + .env("RUSTDOC_LIBDIR", libdir) .env("RUSTDOC", self.bootstrap_out.join("rustdoc")) .env("RUSTDOC_REAL", rustdoc_path) .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); @@ -919,11 +918,6 @@ impl Builder<'_> { rustflags.arg(&format!("-Zstack-protector={stack_protector}")); } - if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc - { - cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); - } - let debuginfo_level = match mode { Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, From 505a2084e683662e1521b3ba64e23e9271f8e192 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 22:57:14 +1000 Subject: [PATCH 409/537] Split off a separate name/value parser for debuginfo test commands --- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/runtest/debugger.rs | 27 ++++++++++--------- .../compiletest/src/runtest/debuginfo.rs | 6 ++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e84a22787668..e864594ade2e 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1121,7 +1121,7 @@ impl Config { line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) } - pub fn parse_name_value_directive( + fn parse_name_value_directive( &self, line: &str, directive: &str, diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index ba824124e875..3d439e98eb7e 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader}; use camino::{Utf8Path, Utf8PathBuf}; -use crate::common::Config; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -20,11 +19,7 @@ pub(super) struct DebuggerCommands { } impl DebuggerCommands { - pub fn parse_from( - file: &Utf8Path, - config: &Config, - debugger_prefix: &str, - ) -> Result { + pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -47,14 +42,10 @@ impl DebuggerCommands { continue; }; - if let Some(command) = - config.parse_name_value_directive(&line, &command_directive, file, line_no) - { + if let Some(command) = parse_name_value(&line, &command_directive) { commands.push(command); } - if let Some(pattern) = - config.parse_name_value_directive(&line, &check_directive, file, line_no) - { + if let Some(pattern) = parse_name_value(&line, &check_directive) { check_lines.push((line_no, pattern)); } } @@ -114,6 +105,18 @@ impl DebuggerCommands { } } +/// Split off from the main `parse_name_value_directive`, so that improvements +/// to directive handling aren't held back by debuginfo test commands. +fn parse_name_value(line: &str, name: &str) -> Option { + if let Some(after_name) = line.strip_prefix(name) + && let Some(value) = after_name.strip_prefix(':') + { + Some(value.to_owned()) + } else { + None + } +} + /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match. fn check_single_line(line: &str, check_line: &str) -> bool { // Allow check lines to leave parts unspecified (e.g., uninitialized diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 071c0863b7e9..9175a38ffa5c 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -59,7 +59,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb") .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands @@ -130,7 +130,7 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test_no_opt(&self) { - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb") .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); @@ -397,7 +397,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb") .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: From ffaf607cf2743f1206a739e02f7b194a4767f9a8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 30 Sep 2025 12:20:42 +1000 Subject: [PATCH 410/537] Remove `parse_negative_name_directive` This isn't actually used for anything, and its presence complicates the migration to `DirectiveLine`. --- src/tools/compiletest/src/directives.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e864594ade2e..01a663b016f7 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1117,10 +1117,6 @@ impl Config { && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':')) } - fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool { - line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) - } - fn parse_name_value_directive( &self, line: &str, @@ -1149,18 +1145,8 @@ impl Config { } fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { - match value { - true => { - if self.parse_negative_name_directive(line, directive) { - *value = false; - } - } - false => { - if self.parse_name_directive(line, directive) { - *value = true; - } - } - } + // If the flag is already true, don't bother looking at the directive. + *value = *value || self.parse_name_directive(line, directive); } fn set_name_value_directive( From e491056ac5722bd404dd6c326c76f457eb08b467 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 22:25:23 +1000 Subject: [PATCH 411/537] Pass around `DirectiveLine` instead of bare strings --- src/tools/compiletest/src/directives.rs | 197 +++++++----------- .../compiletest/src/directives/auxiliary.rs | 35 ++-- src/tools/compiletest/src/directives/cfg.rs | 14 +- src/tools/compiletest/src/directives/needs.rs | 6 +- 4 files changed, 107 insertions(+), 145 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 01a663b016f7..e6916610190e 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -63,9 +63,10 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |DirectiveLine { line_number, raw_directive: ln, .. }| { - parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux); - config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions); + // (dummy comment to force args into vertical layout) + &mut |ref ln: DirectiveLine<'_>| { + parse_and_update_aux(config, ln, testfile, &mut props.aux); + config.parse_and_update_revisions(testfile, ln, &mut props.revisions); }, ); @@ -367,8 +368,8 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { - if !directive.applies_to_test_revision(test_revision) { + &mut |ref ln: DirectiveLine<'_>| { + if !ln.applies_to_test_revision(test_revision) { return; } @@ -378,7 +379,6 @@ impl TestProps { ln, ERROR_PATTERN, testfile, - line_number, &mut self.error_patterns, |r| r, ); @@ -386,7 +386,6 @@ impl TestProps { ln, REGEX_ERROR_PATTERN, testfile, - line_number, &mut self.regex_error_patterns, |r| r, ); @@ -395,7 +394,6 @@ impl TestProps { ln, DOC_FLAGS, testfile, - line_number, &mut self.doc_flags, |r| r, ); @@ -414,7 +412,7 @@ impl TestProps { } if let Some(flags) = - config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number) + config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile) { let flags = split_flags(&flags); for flag in &flags { @@ -425,39 +423,28 @@ impl TestProps { self.compile_flags.extend(flags); } if config - .parse_name_value_directive( - ln, - INCORRECT_COMPILER_FLAGS, - testfile, - line_number, - ) + .parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS, testfile) .is_some() { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } - if let Some(edition) = config.parse_edition(ln, testfile, line_number) { + if let Some(edition) = config.parse_edition(ln, testfile) { // The edition is added at the start, since flags from //@compile-flags must // be passed to rustc last. self.compile_flags.insert(0, format!("--edition={}", edition.trim())); has_edition = true; } - config.parse_and_update_revisions( - testfile, - line_number, - ln, - &mut self.revisions, - ); + config.parse_and_update_revisions(testfile, ln, &mut self.revisions); - if let Some(flags) = - config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number) + if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS, testfile) { self.run_flags.extend(split_flags(&flags)); } if self.pp_exact.is_none() { - self.pp_exact = config.parse_pp_exact(ln, testfile, line_number); + self.pp_exact = config.parse_pp_exact(ln, testfile); } config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); @@ -479,9 +466,7 @@ impl TestProps { ); config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); - if let Some(m) = - config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number) - { + if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE, testfile) { self.pretty_mode = m; } @@ -492,13 +477,12 @@ impl TestProps { ); // Call a helper method to deal with aux-related directives. - parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux); + parse_and_update_aux(config, ln, testfile, &mut self.aux); config.push_name_value_directive( ln, EXEC_ENV, testfile, - line_number, &mut self.exec_env, Config::parse_env, ); @@ -506,7 +490,6 @@ impl TestProps { ln, UNSET_EXEC_ENV, testfile, - line_number, &mut self.unset_exec_env, |r| r.trim().to_owned(), ); @@ -514,7 +497,6 @@ impl TestProps { ln, RUSTC_ENV, testfile, - line_number, &mut self.rustc_env, Config::parse_env, ); @@ -522,7 +504,6 @@ impl TestProps { ln, UNSET_RUSTC_ENV, testfile, - line_number, &mut self.unset_rustc_env, |r| r.trim().to_owned(), ); @@ -530,7 +511,6 @@ impl TestProps { ln, FORBID_OUTPUT, testfile, - line_number, &mut self.forbid_output, |r| r, ); @@ -566,7 +546,7 @@ impl TestProps { } if let Some(code) = config - .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number) + .parse_name_value_directive(ln, FAILURE_STATUS, testfile) .and_then(|code| code.trim().parse::().ok()) { self.failure_status = Some(code); @@ -588,7 +568,6 @@ impl TestProps { ln, ASSEMBLY_OUTPUT, testfile, - line_number, &mut self.assembly_output, |r| r.trim().to_string(), ); @@ -602,7 +581,7 @@ impl TestProps { // Unlike the other `name_value_directive`s this needs to be handled manually, // because it sets a `bool` flag. if let Some(known_bug) = - config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number) + config.parse_name_value_directive(ln, KNOWN_BUG, testfile) { let known_bug = known_bug.trim(); if known_bug == "unknown" @@ -632,24 +611,20 @@ impl TestProps { ln, TEST_MIR_PASS, testfile, - line_number, &mut self.mir_unit_test, |s| s.trim().to_string(), ); config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); if let Some(flags) = - config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number) + config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile) { self.llvm_cov_flags.extend(split_flags(&flags)); } - if let Some(flags) = config.parse_name_value_directive( - ln, - FILECHECK_FLAGS, - testfile, - line_number, - ) { + if let Some(flags) = + config.parse_name_value_directive(ln, FILECHECK_FLAGS, testfile) + { self.filecheck_flags.extend(split_flags(&flags)); } @@ -661,7 +636,6 @@ impl TestProps { ln, directives::CORE_STUBS_COMPILE_FLAGS, testfile, - line_number, ) { let flags = split_flags(&flags); for flag in &flags { @@ -672,12 +646,9 @@ impl TestProps { self.core_stubs_compile_flags.extend(flags); } - if let Some(err_kind) = config.parse_name_value_directive( - ln, - DONT_REQUIRE_ANNOTATIONS, - testfile, - line_number, - ) { + if let Some(err_kind) = + config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS, testfile) + { self.dont_require_annotations .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } @@ -734,7 +705,7 @@ impl TestProps { } } - fn update_fail_mode(&mut self, ln: &str, config: &Config) { + fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let check_ui = |mode: &str| { // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows if config.mode != TestMode::Ui && config.mode != TestMode::Crashes { @@ -769,7 +740,12 @@ impl TestProps { } } - fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) { + fn update_pass_mode( + &mut self, + ln: &DirectiveLine<'_>, + revision: Option<&str>, + config: &Config, + ) { let check_no_run = |s| match (config.mode, s) { (TestMode::Ui, _) => (), (TestMode::Crashes, _) => (), @@ -814,7 +790,7 @@ impl TestProps { self.pass_mode } - pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) { + fn update_add_core_stubs(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS); if add_core_stubs { if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) { @@ -905,10 +881,12 @@ pub(crate) struct CheckDirectiveResult<'ln> { trailing_directive: Option<&'ln str>, } -pub(crate) fn check_directive<'a>( - directive_ln: &'a str, +fn check_directive<'a>( + directive_ln: &DirectiveLine<'a>, mode: TestMode, ) -> CheckDirectiveResult<'a> { + let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln; + let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name) @@ -980,7 +958,7 @@ fn iter_directives( // Perform unknown directive check on Rust files. if testfile.extension() == Some("rs") { let CheckDirectiveResult { is_known_directive, trailing_directive } = - check_directive(directive_line.raw_directive, mode); + check_directive(&directive_line, mode); if !is_known_directive { *poisoned = true; @@ -1014,8 +992,7 @@ impl Config { fn parse_and_update_revisions( &self, testfile: &Utf8Path, - line_number: usize, - line: &str, + line: &DirectiveLine<'_>, existing: &mut Vec, ) { const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ @@ -1028,8 +1005,7 @@ impl Config { const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; - if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number) - { + if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile) { if self.mode == TestMode::RunMake { panic!("`run-make` mode tests do not support revisions: {}", testfile); } @@ -1074,13 +1050,8 @@ impl Config { (name.to_owned(), value.to_owned()) } - fn parse_pp_exact( - &self, - line: &str, - testfile: &Utf8Path, - line_number: usize, - ) -> Option { - if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) { + fn parse_pp_exact(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option { + if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile) { Some(Utf8PathBuf::from(&s)) } else if self.parse_name_directive(line, "pp-exact") { testfile.file_name().map(Utf8PathBuf::from) @@ -1089,7 +1060,9 @@ impl Config { } } - fn parse_custom_normalization(&self, raw_directive: &str) -> Option { + fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option { + let &DirectiveLine { raw_directive, .. } = line; + // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine` // instead of doing it here. let (directive_name, raw_value) = raw_directive.split_once(':')?; @@ -1110,7 +1083,9 @@ impl Config { Some(NormalizeRule { kind, regex, replacement }) } - fn parse_name_directive(&self, line: &str, directive: &str) -> bool { + fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool { + let &DirectiveLine { raw_directive: line, .. } = line; + // Ensure the directive is a whole word. Do not match "ignore-x86" when // the line says "ignore-x86_64". line.starts_with(directive) @@ -1119,11 +1094,12 @@ impl Config { fn parse_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, ) -> Option { + let &DirectiveLine { line_number, raw_directive: line, .. } = line; + let colon = directive.len(); if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') { let value = line[(colon + 1)..].to_owned(); @@ -1140,42 +1116,37 @@ impl Config { } } - fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option { - self.parse_name_value_directive(line, "edition", testfile, line_number) + fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option { + self.parse_name_value_directive(line, "edition", testfile) } - fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { + fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) { // If the flag is already true, don't bother looking at the directive. *value = *value || self.parse_name_directive(line, directive); } fn set_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, value: &mut Option, parse: impl FnOnce(String) -> T, ) { if value.is_none() { - *value = - self.parse_name_value_directive(line, directive, testfile, line_number).map(parse); + *value = self.parse_name_value_directive(line, directive, testfile).map(parse); } } fn push_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, values: &mut Vec, parse: impl FnOnce(String) -> T, ) { - if let Some(value) = - self.parse_name_value_directive(line, directive, testfile, line_number).map(parse) - { + if let Some(value) = self.parse_name_value_directive(line, directive, testfile).map(parse) { values.push(value); } } @@ -1468,8 +1439,8 @@ pub(crate) fn make_test_description( &mut local_poisoned, path, src, - &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { - if !directive.applies_to_test_revision(test_revision) { + &mut |ref ln @ DirectiveLine { line_number, .. }| { + if !ln.applies_to_test_revision(test_revision) { return; } @@ -1493,9 +1464,9 @@ pub(crate) fn make_test_description( decision!(cfg::handle_ignore(config, ln)); decision!(cfg::handle_only(config, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, path, ln, line_number)); - decision!(ignore_backends(config, path, ln, line_number)); - decision!(needs_backends(config, path, ln, line_number)); + decision!(ignore_llvm(config, path, ln)); + decision!(ignore_backends(config, path, ln)); + decision!(needs_backends(config, path, ln)); decision!(ignore_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1535,7 +1506,9 @@ pub(crate) fn make_test_description( } } -fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Cdb) { return IgnoreDecision::Continue; } @@ -1558,7 +1531,9 @@ fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Gdb) { return IgnoreDecision::Continue; } @@ -1606,7 +1581,9 @@ fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Lldb) { return IgnoreDecision::Continue; } @@ -1628,14 +1605,9 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_backends( - config: &Config, - path: &Utf8Path, - line: &str, - line_number: usize, -) -> IgnoreDecision { +fn ignore_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { if let Some(backends_to_ignore) = - config.parse_name_value_directive(line, "ignore-backends", path, line_number) + config.parse_name_value_directive(line, "ignore-backends", path) { for backend in backends_to_ignore.split_whitespace().map(|backend| { match CodegenBackend::try_from(backend) { @@ -1655,15 +1627,8 @@ fn ignore_backends( IgnoreDecision::Continue } -fn needs_backends( - config: &Config, - path: &Utf8Path, - line: &str, - line_number: usize, -) -> IgnoreDecision { - if let Some(needed_backends) = - config.parse_name_value_directive(line, "needs-backends", path, line_number) - { +fn needs_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { + if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends", path) { if !needed_backends .split_whitespace() .map(|backend| match CodegenBackend::try_from(backend) { @@ -1685,9 +1650,9 @@ fn needs_backends( IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { if let Some(needed_components) = - config.parse_name_value_directive(line, "needs-llvm-components", path, line_number) + config.parse_name_value_directive(line, "needs-llvm-components", path) { let components: HashSet<_> = config.llvm_components.split_whitespace().collect(); if let Some(missing_component) = needed_components @@ -1709,7 +1674,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) // Note that these `min` versions will check for not just major versions. if let Some(version_string) = - config.parse_name_value_directive(line, "min-llvm-version", path, line_number) + config.parse_name_value_directive(line, "min-llvm-version", path) { let min_version = extract_llvm_version(&version_string); // Ignore if actual version is smaller than the minimum required version. @@ -1721,7 +1686,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number) + config.parse_name_value_directive(line, "max-llvm-major-version", path) { let max_version = extract_llvm_version(&version_string); // Ignore if actual major version is larger than the maximum required major version. @@ -1735,7 +1700,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number) + config.parse_name_value_directive(line, "min-system-llvm-version", path) { let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version @@ -1748,7 +1713,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_range) = - config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number) + config.parse_name_value_directive(line, "ignore-llvm-version", path) { // Syntax is: "ignore-llvm-version: [- ]" let (v_min, v_max) = @@ -1774,7 +1739,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) } } } else if let Some(version_string) = - config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number) + config.parse_name_value_directive(line, "exact-llvm-major-version", path) { // Syntax is "exact-llvm-major-version: " let version = extract_llvm_version(&version_string); diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 7c1ed2e70062..0675a6feac3f 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -7,6 +7,7 @@ use camino::Utf8Path; use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; +use crate::directives::DirectiveLine; /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] @@ -45,40 +46,28 @@ impl AuxProps { /// and update [`AuxProps`] accordingly. pub(super) fn parse_and_update_aux( config: &Config, - ln: &str, + directive_line: &DirectiveLine<'_>, testfile: &Utf8Path, - line_number: usize, aux: &mut AuxProps, ) { + let &DirectiveLine { raw_directive: ln, .. } = directive_line; + if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) { return; } - config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| { + let ln = directive_line; + + config.push_name_value_directive(ln, AUX_BUILD, testfile, &mut aux.builds, |r| { r.trim().to_string() }); - config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| { + config + .push_name_value_directive(ln, AUX_BIN, testfile, &mut aux.bins, |r| r.trim().to_string()); + config.push_name_value_directive(ln, AUX_CRATE, testfile, &mut aux.crates, parse_aux_crate); + config.push_name_value_directive(ln, PROC_MACRO, testfile, &mut aux.proc_macros, |r| { r.trim().to_string() }); - config.push_name_value_directive( - ln, - AUX_CRATE, - testfile, - line_number, - &mut aux.crates, - parse_aux_crate, - ); - config.push_name_value_directive( - ln, - PROC_MACRO, - testfile, - line_number, - &mut aux.proc_macros, - |r| r.trim().to_string(), - ); - if let Some(r) = - config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number) - { + if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile) { aux.codegen_backend = Some(r.trim().to_owned()); } } diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 802a1d63d1f2..62a4b88a33a6 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,12 +1,14 @@ use std::collections::HashSet; use crate::common::{CompareMode, Config, Debugger}; -use crate::directives::IgnoreDecision; +use crate::directives::{DirectiveLine, IgnoreDecision}; const EXTRA_ARCHS: &[&str] = &["spirv"]; -pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision { +pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { let parsed = parse_cfg_name_directive(config, line, "ignore"); + let &DirectiveLine { raw_directive: line, .. } = line; + match parsed.outcome { MatchOutcome::NoMatch => IgnoreDecision::Continue, MatchOutcome::Match => IgnoreDecision::Ignore { @@ -21,8 +23,10 @@ pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision { } } -pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision { +pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { let parsed = parse_cfg_name_directive(config, line, "only"); + let &DirectiveLine { raw_directive: line, .. } = line; + match parsed.outcome { MatchOutcome::Match => IgnoreDecision::Continue, MatchOutcome::NoMatch => IgnoreDecision::Ignore { @@ -43,9 +47,11 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision { /// or `only-windows`. fn parse_cfg_name_directive<'a>( config: &Config, - line: &'a str, + line: &'a DirectiveLine<'a>, prefix: &str, ) -> ParsedNameDirective<'a> { + let &DirectiveLine { raw_directive: line, .. } = line; + if !line.as_bytes().starts_with(prefix.as_bytes()) { return ParsedNameDirective::not_a_directive(); } diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 3b7a9478717f..c8a729d8aab6 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,10 +1,10 @@ use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; -use crate::directives::{IgnoreDecision, llvm_has_libzstd}; +use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, config: &Config, - ln: &str, + ln: &DirectiveLine<'_>, ) -> IgnoreDecision { // Note that we intentionally still put the needs- prefix here to make the file show up when // grepping for a directive name, even though we could technically strip that. @@ -181,6 +181,8 @@ pub(super) fn handle_needs( }, ]; + let &DirectiveLine { raw_directive: ln, .. } = ln; + let (name, rest) = match ln.split_once([':', ' ']) { Some((name, rest)) => (name, Some(rest)), None => (ln, None), From 0fd6f1113b7209d24d4954ef99165aba09ed27f7 Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Thu, 18 Sep 2025 14:23:58 +0900 Subject: [PATCH 412/537] Add test for unuseful span in type error in some format_args!() invocations --- .../errors/span-format_args-issue-140578.rs | 31 ++++++++++++ .../span-format_args-issue-140578.stderr | 49 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/ui/errors/span-format_args-issue-140578.rs create mode 100644 tests/ui/errors/span-format_args-issue-140578.stderr diff --git a/tests/ui/errors/span-format_args-issue-140578.rs b/tests/ui/errors/span-format_args-issue-140578.rs new file mode 100644 index 000000000000..d086fde09f7b --- /dev/null +++ b/tests/ui/errors/span-format_args-issue-140578.rs @@ -0,0 +1,31 @@ +fn check_format_args() { + print!("{:?} {a} {a:?}", [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn check_format_args_nl() { + println!("{:?} {a} {a:?}", [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn check_multi1() { + println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); + //~^ ERROR type annotations needed +} + +fn check_multi2() { + println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); + //~^ ERROR type annotations needed +} + +fn check_unformatted() { + println!(" //~ ERROR type annotations needed + {:?} {:?} +{a} +{a:?}", + [], + [], +a = 1 + 1); +} + +fn main() {} diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr new file mode 100644 index 000000000000..4c19b4919594 --- /dev/null +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -0,0 +1,49 @@ +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:2:3 + | +LL | print!("{:?} {a} {a:?}", [], a = 1 + 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: this error originates in the macro `print` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:7:3 + | +LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:12:3 + | +LL | println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:17:3 + | +LL | println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed + --> $DIR/span-format_args-issue-140578.rs:22:3 + | +LL | / println!(" +LL | | {:?} {:?} +LL | | {a} +LL | | {a:?}", +LL | | [], +LL | | [], +LL | | a = 1 + 1); + | |__________^ cannot infer type + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0282`. From 1f8bef51e30a087a8b8843c19762952a50087a71 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Tue, 30 Sep 2025 03:04:23 -0500 Subject: [PATCH 413/537] fix tuple child creation --- src/etc/lldb_providers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 65f18baa937e..3eb964d2fbab 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -761,7 +761,8 @@ class MSVCTupleSyntheticProvider: def get_child_at_index(self, index: int) -> SBValue: child: SBValue = self.valobj.GetChildAtIndex(index) - return child.CreateChildAtOffset(str(index), 0, child.GetType()) + offset = self.valobj.GetType().GetFieldAtIndex(index).byte_offset + return self.valobj.CreateChildAtOffset(str(index), offset, child.GetType()) def update(self): pass @@ -772,7 +773,7 @@ class MSVCTupleSyntheticProvider: def get_type_name(self) -> str: name = self.valobj.GetTypeName() # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+ - name = name[7:-1] + name = name[7:-1].strip() return "(" + name + ")" From b13b87a1c3ee3c61b21c4273a87f0b65ccabdde8 Mon Sep 17 00:00:00 2001 From: Tomoaki Kobayashi Date: Thu, 18 Sep 2025 14:42:56 +0900 Subject: [PATCH 414/537] Fix unuseful span in type error in some format_args!() invocations --- .../src/error_reporting/traits/mod.rs | 45 +++++++++++++++---- .../errors/span-format_args-issue-140578.rs | 3 +- .../span-format_args-issue-140578.stderr | 38 +++++++--------- ...745-avoid-expr-from-macro-expansion.stderr | 6 +-- 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index b3d1b8e3888a..9052031ce4fd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; +use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span}; use tracing::{info, instrument}; pub use self::overflow::*; @@ -154,9 +154,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) .collect(); - // Ensure `T: Sized`, `T: MetaSized`, `T: PointeeSized` and `T: WF` obligations come last. + // Ensure `T: Sized`, `T: MetaSized`, `T: PointeeSized` and `T: WF` obligations come last, + // and `Subtype` obligations from `FormatLiteral` desugarings come first. // This lets us display diagnostics with more relevant type information and hide redundant // E0282 errors. + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] + enum ErrorSortKey { + SubtypeFormat(usize, usize), + OtherKind, + SizedTrait, + MetaSizedTrait, + PointeeSizedTrait, + Coerce, + WellFormed, + } errors.sort_by_key(|e| { let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()), @@ -165,12 +176,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; match e.obligation.predicate.kind().skip_binder() { - _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => 1, - _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => 2, - _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => 3, - ty::PredicateKind::Coerce(_) => 4, - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 5, - _ => 0, + ty::PredicateKind::Subtype(_) + if matches!( + e.obligation.cause.span.desugaring_kind(), + Some(DesugaringKind::FormatLiteral { .. }) + ) => + { + let (_, row, col, ..) = + self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span); + ErrorSortKey::SubtypeFormat(row, col) + } + _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => { + ErrorSortKey::SizedTrait + } + _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => { + ErrorSortKey::MetaSizedTrait + } + _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => { + ErrorSortKey::PointeeSizedTrait + } + ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { + ErrorSortKey::WellFormed + } + _ => ErrorSortKey::OtherKind, } }); diff --git a/tests/ui/errors/span-format_args-issue-140578.rs b/tests/ui/errors/span-format_args-issue-140578.rs index d086fde09f7b..8c91ded83375 100644 --- a/tests/ui/errors/span-format_args-issue-140578.rs +++ b/tests/ui/errors/span-format_args-issue-140578.rs @@ -19,11 +19,12 @@ fn check_multi2() { } fn check_unformatted() { - println!(" //~ ERROR type annotations needed + println!(" {:?} {:?} {a} {a:?}", [], + //~^ ERROR type annotations needed [], a = 1 + 1); } diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr index 4c19b4919594..6a273e5cd515 100644 --- a/tests/ui/errors/span-format_args-issue-140578.stderr +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -1,48 +1,42 @@ error[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:2:3 + --> $DIR/span-format_args-issue-140578.rs:2:28 | LL | print!("{:?} {a} {a:?}", [], a = 1 + 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type | - = note: this error originates in the macro `print` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the macro `print` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:7:3 + --> $DIR/span-format_args-issue-140578.rs:7:30 | LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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) error[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:12:3 + --> $DIR/span-format_args-issue-140578.rs:12:35 | LL | println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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) error[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:17:3 + --> $DIR/span-format_args-issue-140578.rs:17:41 | LL | println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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) error[E0282]: type annotations needed - --> $DIR/span-format_args-issue-140578.rs:22:3 + --> $DIR/span-format_args-issue-140578.rs:26:9 | -LL | / println!(" -LL | | {:?} {:?} -LL | | {a} -LL | | {a:?}", -LL | | [], -LL | | [], -LL | | a = 1 + 1); - | |__________^ cannot infer type +LL | [], + | ^^ cannot infer type | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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) error: aborting due to 5 previous errors diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr index a78941f9e11b..3de317d2af6d 100644 --- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr +++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr @@ -1,10 +1,10 @@ error[E0282]: type annotations needed - --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:5 + --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:22 | LL | println!("{:?}", []); - | ^^^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type | - = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = 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) error: aborting due to 1 previous error From d615d2ff34566c399862cfe0feb96d05767ce5ce Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 30 Sep 2025 11:59:08 +0200 Subject: [PATCH 415/537] std: call WinSock cleanup function directly instead of through its reexport --- library/std/src/sys/net/connection/socket/windows.rs | 2 +- library/std/src/sys/pal/windows/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 5b6f4cedf1b7..2221023a2125 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -111,7 +111,7 @@ pub(super) mod netc { } } -pub use crate::sys::pal::winsock::{cleanup, cvt, cvt_gai, cvt_r, startup as init}; +pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init}; #[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 18ab34982676..a5f060080130 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -58,7 +58,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { - crate::sys::net::cleanup(); + winsock::cleanup(); } #[inline] From 5139facb365c40e5b0ddedf221cd62347a2a4504 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 30 Sep 2025 12:02:43 +0200 Subject: [PATCH 416/537] add tests --- .../src/solve/assembly/mod.rs | 5 +- .../ui/indexing/ambiguity-after-deref-step.rs | 9 +++ .../ambiguity-after-deref-step.stderr | 17 ++++++ .../forced-ambiguity-typenum-ice.rs | 60 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tests/ui/indexing/ambiguity-after-deref-step.rs create mode 100644 tests/ui/indexing/ambiguity-after-deref-step.stderr create mode 100644 tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index a2e6ef6f0fe8..d58c264841c8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -473,7 +473,10 @@ where // fails to reach a fixpoint but ends up getting an error after // running for some additional step. // - // cc trait-system-refactor-initiative#105 + // FIXME(@lcnr): While I believe an error here to be possible, we + // currently don't have any test which actually triggers it. @lqd + // created a minimization for an ICE in typenum, but that one no + // longer fails here. cc trait-system-refactor-initiative#105. let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood }; self.probe_trait_candidate(source) diff --git a/tests/ui/indexing/ambiguity-after-deref-step.rs b/tests/ui/indexing/ambiguity-after-deref-step.rs new file mode 100644 index 000000000000..2dd95eed097c --- /dev/null +++ b/tests/ui/indexing/ambiguity-after-deref-step.rs @@ -0,0 +1,9 @@ +// Regression test making sure that indexing fails with an ambiguity +// error if one of the deref-steps encounters an inference variable. + +fn main() { + let x = &Default::default(); + //~^ ERROR type annotations needed for `&_` + x[1]; + let _: &Vec<()> = x; +} diff --git a/tests/ui/indexing/ambiguity-after-deref-step.stderr b/tests/ui/indexing/ambiguity-after-deref-step.stderr new file mode 100644 index 000000000000..c7ddd4731c7c --- /dev/null +++ b/tests/ui/indexing/ambiguity-after-deref-step.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&_` + --> $DIR/ambiguity-after-deref-step.rs:5:9 + | +LL | let x = &Default::default(); + | ^ +LL | +LL | x[1]; + | - type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &Default::default(); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs new file mode 100644 index 000000000000..679d6b1fb165 --- /dev/null +++ b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#105. We previously encountered +// an ICE in typenum as `forced_ambiguity` failed. While this test no longer causes +// `forced_ambiguity` to error, we still want to use it as a regression test. + +pub struct UInt { + _msb: U, + _lsb: B, +} +pub struct B1; +pub trait Sub { + type Output; +} +impl Sub for UInt, B1> { + type Output = (); +} +impl Sub for UInt +where + U: Sub, + U::Output: Send, +{ + type Output = (); +} + +pub trait Op { + fn op(&self) { + unimplemented!() + } +} +trait OpIf {} + +impl Op, I> for () +where + N: Sub, + (): OpIf, N::Output>, I>, +{ +} +impl OpIf> for () +where + UInt: Sub, + (): Op as Sub>::Output>, +{ +} +impl OpIf for () where R: Sub {} + +pub trait Compute { + type Output; +} + +pub fn repro() +where + UInt: Compute, + as Compute>::Output: Sub, + (): Op, (), ()>, +{ + ().op(); +} +fn main() {} From cd40bbfe2965a42ae8336ebd70fc7fb9c81d22e0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 20:53:06 +1000 Subject: [PATCH 417/537] Move `MetadataKindId` into its own submodule --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 11 +---------- .../rustc_codegen_llvm/src/llvm/metadata_kind.rs | 13 +++++++++++++ compiler/rustc_codegen_llvm/src/llvm/mod.rs | 2 ++ 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index afd2991a09c3..83867cc2dce6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -29,6 +29,7 @@ use super::debuginfo::{ DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind, }; use crate::llvm; +use crate::llvm::MetadataKindId; /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`. @@ -1035,16 +1036,6 @@ pub(crate) type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; -#[derive(Copy, Clone)] -#[repr(transparent)] -pub(crate) struct MetadataKindId(c_uint); - -impl From for MetadataKindId { - fn from(value: MetadataType) -> Self { - Self(value as c_uint) - } -} - unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMContextDispose(C: &'static mut Context); diff --git a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs new file mode 100644 index 000000000000..926eb7893520 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs @@ -0,0 +1,13 @@ +use libc::c_uint; + +use crate::llvm::MetadataType; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub(crate) struct MetadataKindId(c_uint); + +impl From for MetadataKindId { + fn from(value: MetadataType) -> Self { + Self(value as c_uint) + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 1115d82fa85d..2333fbe7a765 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -13,11 +13,13 @@ pub(crate) use self::CallConv::*; pub(crate) use self::CodeGenOptSize::*; pub(crate) use self::MetadataType::*; pub(crate) use self::ffi::*; +pub(crate) use self::metadata_kind::MetadataKindId; use crate::common::AsCCharPtr; pub(crate) mod diagnostic; pub(crate) mod enzyme_ffi; mod ffi; +mod metadata_kind; pub(crate) use self::enzyme_ffi::*; From 906bf49ade52d7485a6c8a0756f020ade3a342b6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 20:21:33 +1000 Subject: [PATCH 418/537] Declare all "fixed" metadata kinds as `MetadataKindId` --- .../src/llvm/metadata_kind.rs | 64 +++++++++++++++++++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 52 +++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs index 926eb7893520..4d00356c6162 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs @@ -11,3 +11,67 @@ impl From for MetadataKindId { Self(value as c_uint) } } + +macro_rules! declare_fixed_metadata_kinds { + ( + $( + FIXED_MD_KIND($variant:ident, $value:literal) + )* + ) => { + // Use a submodule to group all declarations into one `#[expect(..)]`. + #[expect(dead_code)] + mod fixed_kinds { + use super::MetadataKindId; + $( + #[expect(non_upper_case_globals)] + pub(crate) const $variant: MetadataKindId = MetadataKindId($value); + )* + } + }; +} + +// Must be kept in sync with the corresponding static assertions in `RustWrapper.cpp`. +declare_fixed_metadata_kinds! { + FIXED_MD_KIND(MD_dbg, 0) + FIXED_MD_KIND(MD_tbaa, 1) + FIXED_MD_KIND(MD_prof, 2) + FIXED_MD_KIND(MD_fpmath, 3) + FIXED_MD_KIND(MD_range, 4) + FIXED_MD_KIND(MD_tbaa_struct, 5) + FIXED_MD_KIND(MD_invariant_load, 6) + FIXED_MD_KIND(MD_alias_scope, 7) + FIXED_MD_KIND(MD_noalias, 8) + FIXED_MD_KIND(MD_nontemporal, 9) + FIXED_MD_KIND(MD_mem_parallel_loop_access, 10) + FIXED_MD_KIND(MD_nonnull, 11) + FIXED_MD_KIND(MD_dereferenceable, 12) + FIXED_MD_KIND(MD_dereferenceable_or_null, 13) + FIXED_MD_KIND(MD_make_implicit, 14) + FIXED_MD_KIND(MD_unpredictable, 15) + FIXED_MD_KIND(MD_invariant_group, 16) + FIXED_MD_KIND(MD_align, 17) + FIXED_MD_KIND(MD_loop, 18) + FIXED_MD_KIND(MD_type, 19) + FIXED_MD_KIND(MD_section_prefix, 20) + FIXED_MD_KIND(MD_absolute_symbol, 21) + FIXED_MD_KIND(MD_associated, 22) + FIXED_MD_KIND(MD_callees, 23) + FIXED_MD_KIND(MD_irr_loop, 24) + FIXED_MD_KIND(MD_access_group, 25) + FIXED_MD_KIND(MD_callback, 26) + FIXED_MD_KIND(MD_preserve_access_index, 27) + FIXED_MD_KIND(MD_vcall_visibility, 28) + FIXED_MD_KIND(MD_noundef, 29) + FIXED_MD_KIND(MD_annotation, 30) + FIXED_MD_KIND(MD_nosanitize, 31) + FIXED_MD_KIND(MD_func_sanitize, 32) + FIXED_MD_KIND(MD_exclude, 33) + FIXED_MD_KIND(MD_memprof, 34) + FIXED_MD_KIND(MD_callsite, 35) + FIXED_MD_KIND(MD_kcfi_type, 36) + FIXED_MD_KIND(MD_pcsections, 37) + FIXED_MD_KIND(MD_DIAssignID, 38) + FIXED_MD_KIND(MD_coro_outside_frame, 39) + FIXED_MD_KIND(MD_mmra, 40) + FIXED_MD_KIND(MD_noalias_addrspace, 41) +} diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 4a7781259189..2b83ea24ac61 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1824,3 +1824,55 @@ extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return 6; // Default fallback depth } #endif + +// Statically assert that the fixed metadata kind IDs declared in +// `metadata_kind.rs` match the ones actually used by LLVM. +#define FIXED_MD_KIND(VARIANT, VALUE) \ + static_assert(::llvm::LLVMContext::VARIANT == VALUE); +// Must be kept in sync with the corresponding list in `metadata_kind.rs`. +FIXED_MD_KIND(MD_dbg, 0) +FIXED_MD_KIND(MD_tbaa, 1) +FIXED_MD_KIND(MD_prof, 2) +FIXED_MD_KIND(MD_fpmath, 3) +FIXED_MD_KIND(MD_range, 4) +FIXED_MD_KIND(MD_tbaa_struct, 5) +FIXED_MD_KIND(MD_invariant_load, 6) +FIXED_MD_KIND(MD_alias_scope, 7) +FIXED_MD_KIND(MD_noalias, 8) +FIXED_MD_KIND(MD_nontemporal, 9) +FIXED_MD_KIND(MD_mem_parallel_loop_access, 10) +FIXED_MD_KIND(MD_nonnull, 11) +FIXED_MD_KIND(MD_dereferenceable, 12) +FIXED_MD_KIND(MD_dereferenceable_or_null, 13) +FIXED_MD_KIND(MD_make_implicit, 14) +FIXED_MD_KIND(MD_unpredictable, 15) +FIXED_MD_KIND(MD_invariant_group, 16) +FIXED_MD_KIND(MD_align, 17) +FIXED_MD_KIND(MD_loop, 18) +FIXED_MD_KIND(MD_type, 19) +FIXED_MD_KIND(MD_section_prefix, 20) +FIXED_MD_KIND(MD_absolute_symbol, 21) +FIXED_MD_KIND(MD_associated, 22) +FIXED_MD_KIND(MD_callees, 23) +FIXED_MD_KIND(MD_irr_loop, 24) +FIXED_MD_KIND(MD_access_group, 25) +FIXED_MD_KIND(MD_callback, 26) +FIXED_MD_KIND(MD_preserve_access_index, 27) +FIXED_MD_KIND(MD_vcall_visibility, 28) +FIXED_MD_KIND(MD_noundef, 29) +FIXED_MD_KIND(MD_annotation, 30) +FIXED_MD_KIND(MD_nosanitize, 31) +FIXED_MD_KIND(MD_func_sanitize, 32) +FIXED_MD_KIND(MD_exclude, 33) +FIXED_MD_KIND(MD_memprof, 34) +FIXED_MD_KIND(MD_callsite, 35) +FIXED_MD_KIND(MD_kcfi_type, 36) +FIXED_MD_KIND(MD_pcsections, 37) +FIXED_MD_KIND(MD_DIAssignID, 38) +FIXED_MD_KIND(MD_coro_outside_frame, 39) +FIXED_MD_KIND(MD_mmra, 40) +FIXED_MD_KIND(MD_noalias_addrspace, 41) +// If some fixed metadata kinds are not present and consistent in all supported +// LLVM versions, it's fine to omit them from this list; in that case Rust-side +// code cannot declare them as fixed IDs and must look them up by name instead. +#undef FIXED_MD_KIND From cc6329a9bcd78c4531e9713775e2936fe223e601 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 30 Sep 2025 20:05:23 +1000 Subject: [PATCH 419/537] Replace `MetadataType` with the `MetadataKindId` constants --- compiler/rustc_codegen_llvm/src/context.rs | 6 ++-- .../src/debuginfo/metadata.rs | 8 ++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 33 ++++--------------- .../src/llvm/metadata_kind.rs | 8 +---- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 3 +- compiler/rustc_codegen_llvm/src/type_.rs | 8 ++--- 6 files changed, 17 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index aa5c17269fb8..b1da6f7c7406 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::Metadata; +use crate::llvm::{Metadata, MetadataKindId}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util}; @@ -1006,11 +1006,11 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn set_metadata<'a>( &self, val: &'a Value, - kind_id: impl Into, + kind_id: MetadataKindId, md: &'ll Metadata, ) { let node = self.get_metadata_value(md); - llvm::LLVMSetMetadata(val, kind_id.into(), node); + llvm::LLVMSetMetadata(val, kind_id, node); } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1e4ace4ca922..bc20c7594134 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1611,16 +1611,12 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, - llvm::MD_type as c_uint, + llvm::MD_type, llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()), ); let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); - llvm::LLVMGlobalSetMetadata( - vtable, - llvm::MetadataType::MD_vcall_visibility as c_uint, - vcall_visibility_metadata, - ); + llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 83867cc2dce6..f17de168ca43 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -514,31 +514,6 @@ pub(crate) enum FileType { ObjectFile, } -/// LLVMMetadataType -#[derive(Copy, Clone)] -#[repr(C)] -#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] -pub(crate) enum MetadataType { - MD_dbg = 0, - MD_tbaa = 1, - MD_prof = 2, - MD_fpmath = 3, - MD_range = 4, - MD_tbaa_struct = 5, - MD_invariant_load = 6, - MD_alias_scope = 7, - MD_noalias = 8, - MD_nontemporal = 9, - MD_mem_parallel_loop_access = 10, - MD_nonnull = 11, - MD_unpredictable = 15, - MD_align = 17, - MD_type = 19, - MD_vcall_visibility = 28, - MD_noundef = 29, - MD_kcfi_type = 36, -} - /// Must match the layout of `LLVMInlineAsmDialect`. #[derive(Copy, Clone, PartialEq)] #[repr(C)] @@ -1130,7 +1105,11 @@ unsafe extern "C" { pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value); - pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); + pub(crate) fn LLVMGlobalSetMetadata<'a>( + Val: &'a Value, + KindID: MetadataKindId, + Metadata: &'a Metadata, + ); pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; // Operations on constants of any type @@ -2050,7 +2029,7 @@ unsafe extern "C" { // Operations on all values pub(crate) fn LLVMRustGlobalAddMetadata<'a>( Val: &'a Value, - KindID: c_uint, + KindID: MetadataKindId, Metadata: &'a Metadata, ); pub(crate) fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool; diff --git a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs index 4d00356c6162..a8a671b5c85f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs @@ -1,17 +1,11 @@ use libc::c_uint; -use crate::llvm::MetadataType; +pub(crate) use self::fixed_kinds::*; #[derive(Copy, Clone)] #[repr(transparent)] pub(crate) struct MetadataKindId(c_uint); -impl From for MetadataKindId { - fn from(value: MetadataType) -> Self { - Self(value as c_uint) - } -} - macro_rules! declare_fixed_metadata_kinds { ( $( diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 2333fbe7a765..9a53dacb1dfd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -11,9 +11,8 @@ use rustc_llvm::RustString; pub(crate) use self::CallConv::*; pub(crate) use self::CodeGenOptSize::*; -pub(crate) use self::MetadataType::*; pub(crate) use self::ffi::*; -pub(crate) use self::metadata_kind::MetadataKindId; +pub(crate) use self::metadata_kind::*; use crate::common::AsCCharPtr; pub(crate) mod diagnostic; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 9ecaf5f24fe1..5b97898a4b88 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -306,7 +306,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( function, - llvm::MD_type as c_uint, + llvm::MD_type, llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), ) } @@ -318,7 +318,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( function, - llvm::MD_type as c_uint, + llvm::MD_type, llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), ) } @@ -333,7 +333,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMRustGlobalAddMetadata( function, - llvm::MD_kcfi_type as c_uint, + llvm::MD_kcfi_type, llvm::LLVMMDNodeInContext2( self.llcx, &llvm::LLVMValueAsMetadata(kcfi_type_metadata), @@ -348,7 +348,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGlobalSetMetadata( function, - llvm::MD_kcfi_type as c_uint, + llvm::MD_kcfi_type, llvm::LLVMMDNodeInContext2( self.llcx, &llvm::LLVMValueAsMetadata(kcfi_type_metadata), From eba1416c015803aab6d3ac0b7efebb28165b50ab Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 30 Sep 2025 12:43:36 +0200 Subject: [PATCH 420/537] std: improve internal socket functions --- .../std/src/sys/net/connection/socket/mod.rs | 92 ++++++++++++++----- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 1dd06e97bbab..8a758947cc2d 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -3,6 +3,7 @@ mod tests; use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; +use crate::mem::MaybeUninit; use crate::net::{ Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, }; @@ -177,6 +178,11 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { } } +/// Converts the C socket address stored in `storage` to a Rust `SocketAddr`. +/// +/// # Safety +/// * `storage` must contain a valid C socket address whose length is no larger +/// than `len`. unsafe fn socket_addr_from_c( storage: *const c::sockaddr_storage, len: usize, @@ -202,49 +208,85 @@ unsafe fn socket_addr_from_c( // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// -pub fn setsockopt( +/// Sets the value of a socket option. +/// +/// # Safety +/// `T` must be the type associated with the given socket option. +pub unsafe fn setsockopt( sock: &Socket, level: c_int, option_name: c_int, option_value: T, ) -> io::Result<()> { - unsafe { - cvt(c::setsockopt( + let option_len = size_of::() as c::socklen_t; + // SAFETY: + // * `sock` is opened for the duration of this call, as `sock` owns the socket. + // * the pointer to `option_value` is readable at a size of `size_of::` + // bytes + // * the value of `option_value` has a valid type for the given socket option + // (guaranteed by caller). + cvt(unsafe { + c::setsockopt( sock.as_raw(), level, option_name, (&raw const option_value) as *const _, - size_of::() as c::socklen_t, - ))?; - Ok(()) - } + option_len, + ) + })?; + Ok(()) } -pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> io::Result { - unsafe { - let mut option_value: T = mem::zeroed(); - let mut option_len = size_of::() as c::socklen_t; - cvt(c::getsockopt( +/// Gets the value of a socket option. +/// +/// # Safety +/// `T` must be the type associated with the given socket option. +pub unsafe fn getsockopt( + sock: &Socket, + level: c_int, + option_name: c_int, +) -> io::Result { + let mut option_value = MaybeUninit::::zeroed(); + let mut option_len = size_of::() as c::socklen_t; + + // SAFETY: + // * `sock` is opened for the duration of this call, as `sock` owns the socket. + // * the pointer to `option_value` is writable and the stack allocation has + // space for `size_of::` bytes. + cvt(unsafe { + c::getsockopt( sock.as_raw(), level, option_name, - (&raw mut option_value) as *mut _, + option_value.as_mut_ptr().cast(), &mut option_len, - ))?; - Ok(option_value) - } + ) + })?; + + // SAFETY: the `getsockopt` call succeeded and the caller guarantees that + // `T` is the type of this option, thus `option_value` must have + // been initialized by the system. + Ok(unsafe { option_value.assume_init() }) } -fn sockname(f: F) -> io::Result +/// Wraps a call to a platform function that returns a socket address. +/// +/// # Safety +/// * if `f` returns a success (i.e. `cvt` returns `Ok` when called on the +/// return value), the buffer provided to `f` must have been initialized +/// with a valid C socket address, the length of which must be written +/// to the second argument. +unsafe fn sockname(f: F) -> io::Result where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int, { - unsafe { - let mut storage: c::sockaddr_storage = mem::zeroed(); - let mut len = size_of_val(&storage) as c::socklen_t; - cvt(f((&raw mut storage) as *mut _, &mut len))?; - socket_addr_from_c(&storage, len as usize) - } + let mut storage = MaybeUninit::::zeroed(); + let mut len = size_of::() as c::socklen_t; + cvt(f(storage.as_mut_ptr().cast(), &mut len))?; + // SAFETY: + // The caller guarantees that the storage has been successfully initialized + // and its size written to `len` if `f` returns a success. + unsafe { socket_addr_from_c(storage.as_ptr(), len as usize) } } #[cfg(target_os = "android")] @@ -546,8 +588,8 @@ impl TcpListener { // The `accept` function will fill in the storage with the address, // so we don't need to zero it here. // reference: https://linux.die.net/man/2/accept4 - let mut storage: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let mut len = size_of_val(&storage) as c::socklen_t; + let mut storage = MaybeUninit::::uninit(); + let mut len = size_of::() as c::socklen_t; let sock = self.inner.accept(storage.as_mut_ptr() as *mut _, &mut len)?; let addr = unsafe { socket_addr_from_c(storage.as_ptr(), len as usize)? }; Ok((TcpStream { inner: sock }, addr)) From 817e181ee80256d93156bbb8ba0a1daafb3cf4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 29 Sep 2025 15:00:10 +0200 Subject: [PATCH 421/537] test bevy compute_implied_bounds hack with new trait solver --- tests/ui/implied-bounds/bevy_world_query.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ui/implied-bounds/bevy_world_query.rs b/tests/ui/implied-bounds/bevy_world_query.rs index 6548c03d1b00..e2750bcf957e 100644 --- a/tests/ui/implied-bounds/bevy_world_query.rs +++ b/tests/ui/implied-bounds/bevy_world_query.rs @@ -1,6 +1,8 @@ -#![crate_name = "bevy_ecs"] - //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +#![crate_name = "bevy_ecs"] // We currently special case bevy from erroring on incorrect implied bounds // from normalization (issue #109628). From fef865731cdf89995f8e8667641701843b4a3168 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 30 Sep 2025 15:40:54 +0300 Subject: [PATCH 422/537] Impl `std::error::Error` for `SyntaxError` --- src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs index dc6130bd6415..1c902893abc6 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs @@ -42,3 +42,5 @@ impl fmt::Display for SyntaxError { self.0.fmt(f) } } + +impl std::error::Error for SyntaxError {} From 198777a08e74e2b7a59ed9b7a8b2561eaddc160e Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 30 Sep 2025 15:03:40 +0200 Subject: [PATCH 423/537] remove unnecessary test directives --- .../trait-upcasting/illegal-upcast-to-impl-opaque.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs index 2760c1696b56..f603ff1ec80e 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-to-impl-opaque.rs @@ -1,12 +1,5 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[next] failure-status: 101 -//@[next] known-bug: unknown -//@[next] normalize-stderr: "note: .*\n\n" -> "" -//@[next] normalize-stderr: "thread 'rustc' panicked.*\n.*\n" -> "" -//@[next] normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[next] normalize-stderr: "delayed at .*" -> "" -//@[next] rustc-env:RUST_BACKTRACE=0 //@ check-pass trait Super { From 9e79fac0354b2a87515c30e94754413ef99b3675 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 30 Sep 2025 22:39:10 +0900 Subject: [PATCH 424/537] Add repr(align(2)) to RcInner and ArcInner --- library/alloc/src/rc.rs | 4 +++- library/alloc/src/sync.rs | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fcb466778a3f..e8527b18f070 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -277,7 +277,9 @@ use crate::vec::Vec; // This is repr(C) to future-proof against possible field-reordering, which // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. -#[repr(C)] +// repr(align(2)) (forcing alignment to at least 2) is required because usize +// has 1-byte alignment on AVR. +#[repr(C, align(2))] struct RcInner { strong: Cell, weak: Cell, diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 32396cccb8fc..6bab3b7056f6 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -341,7 +341,7 @@ pub struct Weak< // but it is not necessarily a valid pointer. // `Weak::new` sets this to `usize::MAX` so that it doesn’t need // to allocate space on the heap. That's not a value a real pointer - // will ever have because RcInner has alignment at least 2. + // will ever have because ArcInner has alignment at least 2. ptr: NonNull>, alloc: A, } @@ -366,7 +366,9 @@ impl fmt::Debug for Weak { // This is repr(C) to future-proof against possible field-reordering, which // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. -#[repr(C)] +// Unlike RcInner, repr(align(2)) is not strictly required because atomic types +// have the alignment same as its size, but we use it for consistency and clarity. +#[repr(C, align(2))] struct ArcInner { strong: Atomic, @@ -1622,9 +1624,9 @@ impl Arc { pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); - // SAFETY: This cannot go through Deref::deref or RcInnerPtr::inner because + // SAFETY: This cannot go through Deref::deref or ArcInnerPtr::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can - // write through the pointer after the Rc is recovered through `from_raw`. + // write through the pointer after the Arc is recovered through `from_raw`. unsafe { &raw mut (*ptr).data } } @@ -2459,7 +2461,7 @@ impl Arc { /// If any other `Arc` or [`Weak`] pointers to the same allocation exist, then /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the - /// inner type of this Rc (including lifetimes). This is trivially the case if no + /// inner type of this Arc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Arc::new`. /// /// # Examples @@ -3031,7 +3033,7 @@ impl Weak { // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; - // Thus, we reverse the offset to get the whole RcInner. + // Thus, we reverse the offset to get the whole ArcInner. // SAFETY: the pointer originated from a Weak, so this offset is safe. unsafe { ptr.byte_sub(offset) as *mut ArcInner } }; @@ -4024,7 +4026,7 @@ impl Unpin for Arc {} /// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> usize { // Align the unsized value to the end of the ArcInner. - // Because RcInner is repr(C), it will always be the last field in memory. + // Because ArcInner is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation From 5f54d8bfd8e5921dc5eb5bbe0799907ed4ca1916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 30 Sep 2025 16:08:48 +0200 Subject: [PATCH 425/537] Remove usage of `compiletest-use-stage0-libtest` from CI --- src/bootstrap/defaults/bootstrap.dist.toml | 2 -- src/ci/citool/tests/test-jobs.yml | 2 +- src/ci/docker/host-x86_64/pr-check-1/Dockerfile | 1 - src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index b111a20f8d86..bb0592ce947a 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -7,8 +7,6 @@ test-stage = 2 doc-stage = 2 # When compiling from source, you usually want all tools. extended = true -# Use libtest built from the source tree instead of the precompiled one from stage 0. -compiletest-use-stage0-libtest = false # Most users installing from source want to build all parts of the project from source. [llvm] diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index d82b3e7648e1..512c80628574 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile index 04ac0f33daf0..776bbb12e445 100644 --- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -43,7 +43,6 @@ ENV SCRIPT \ python3 ../x.py check bootstrap && \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py build src/tools/build-manifest && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 95357d229374..278e40eb71fa 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -90,5 +90,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" From aa1263e7684341a73b600eaf0bbc70067e196243 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 30 Sep 2025 16:55:21 +0200 Subject: [PATCH 426/537] std: add missing unsafe blocks --- .../src/sys/net/connection/socket/hermit.rs | 14 +- .../std/src/sys/net/connection/socket/mod.rs | 88 ++++++----- .../src/sys/net/connection/socket/solid.rs | 14 +- .../std/src/sys/net/connection/socket/unix.rs | 148 +++++++++--------- .../src/sys/net/connection/socket/wasip2.rs | 10 +- .../src/sys/net/connection/socket/windows.rs | 14 +- 6 files changed, 154 insertions(+), 134 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 5200eaa5786a..0c105ed20fa7 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -242,11 +242,11 @@ impl Socket { None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: i32) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -272,22 +272,22 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, }; - setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + let val: netc::linger = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { let value: i32 = if nodelay { 1 } else { 0 }; - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value) } } pub fn nodelay(&self) -> io::Result { - let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: i32 = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -304,7 +304,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 8a758947cc2d..d01a52b86109 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -442,11 +442,11 @@ impl TcpStream { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) } } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -474,11 +474,11 @@ impl TcpStream { } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } @@ -545,7 +545,9 @@ impl TcpListener { // which allows “socket hijacking”, so we explicitly don't set it here. // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse #[cfg(not(windows))] - setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; + unsafe { + setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)? + }; // Bind our new socket let (addr, len) = socket_addr_to_c(addr); @@ -581,7 +583,7 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { @@ -600,20 +602,20 @@ impl TcpListener { } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) } } pub fn only_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)? }; Ok(raw != 0) } @@ -676,11 +678,11 @@ impl UdpSocket { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) } } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { @@ -728,48 +730,62 @@ impl UdpSocket { } pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { - setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) + unsafe { setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) } } pub fn broadcast(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)? }; Ok(raw != 0) } pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt( - &self.inner, - c::IPPROTO_IP, - c::IP_MULTICAST_LOOP, - multicast_loop_v4 as IpV4MultiCastType, - ) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_LOOP, + multicast_loop_v4 as IpV4MultiCastType, + ) + } } pub fn multicast_loop_v4(&self) -> io::Result { - let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + let raw: IpV4MultiCastType = + unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)? }; Ok(raw != 0) } pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt( - &self.inner, - c::IPPROTO_IP, - c::IP_MULTICAST_TTL, - multicast_ttl_v4 as IpV4MultiCastType, - ) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_TTL, + multicast_ttl_v4 as IpV4MultiCastType, + ) + } } pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + let raw: IpV4MultiCastType = + unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)? }; Ok(raw as u32) } pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IPV6, + c::IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int, + ) + } } pub fn multicast_loop_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?; + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)? }; Ok(raw != 0) } @@ -778,7 +794,7 @@ impl UdpSocket { imr_multiaddr: ip_v4_addr_to_c(multiaddr), imr_interface: ip_v4_addr_to_c(interface), }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) } } pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { @@ -786,7 +802,7 @@ impl UdpSocket { ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } } pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { @@ -794,7 +810,7 @@ impl UdpSocket { imr_multiaddr: ip_v4_addr_to_c(multiaddr), imr_interface: ip_v4_addr_to_c(interface), }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) } } pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { @@ -802,15 +818,15 @@ impl UdpSocket { ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 94bb605c1007..dfde5513f909 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -303,11 +303,11 @@ impl Socket { } None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -333,21 +333,21 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, }; - setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + let val: netc::linger = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -360,7 +360,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index a191576d93b9..3f05449903fd 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -72,47 +72,45 @@ impl Socket { } pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - cfg_select! { - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "nto", - target_os = "solaris", - ) => { - // On platforms that support it we pass the SOCK_CLOEXEC - // flag to atomically create the socket and set it as - // CLOEXEC. On Linux this was added in 2.6.27. - let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - let socket = Socket(FileDesc::from_raw_fd(fd)); + cfg_select! { + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "nto", + target_os = "solaris", + ) => { + // On platforms that support it we pass the SOCK_CLOEXEC + // flag to atomically create the socket and set it as + // CLOEXEC. On Linux this was added in 2.6.27. + let fd = cvt(unsafe { libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0) })?; + let socket = Socket(unsafe { FileDesc::from_raw_fd(fd) }); - // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` - // flag to disable `SIGPIPE` emission on socket. - #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] + unsafe { setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)? }; - Ok(socket) - } - _ => { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::from_raw_fd(fd); - fd.set_cloexec()?; - let socket = Socket(fd); + Ok(socket) + } + _ => { + let fd = cvt(unsafe { libc::socket(fam, ty, 0) })?; + let fd = unsafe { FileDesc::from_raw_fd(fd) }; + fd.set_cloexec()?; + let socket = Socket(fd); - // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` - // flag to disable `SIGPIPE` emission on socket. - #[cfg(target_vendor = "apple")] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(target_vendor = "apple")] + unsafe { setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)? }; - Ok(socket) - } + Ok(socket) } } } @@ -413,11 +411,11 @@ impl Socket { } None => libc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, libc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; + let raw: libc::timeval = unsafe { getsockopt(self, libc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -444,7 +442,7 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, }; - setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } } #[cfg(target_os = "cygwin")] @@ -454,32 +452,32 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_ushort, }; - setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?; + let val: libc::linger = unsafe { getsockopt(self, libc::SOL_SOCKET, SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)? }; Ok(raw != 0) } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn set_quickack(&self, quickack: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int) } } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn quickack(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)? }; Ok(raw != 0) } @@ -487,12 +485,12 @@ impl Socket { #[cfg(target_os = "linux")] pub fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { let val = cmp::min(accept.as_secs(), c_int::MAX as u64) as c_int; - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) } } #[cfg(target_os = "linux")] pub fn deferaccept(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)? }; Ok(Duration::from_secs(raw as _)) } @@ -506,21 +504,23 @@ impl Socket { } let mut arg: libc::accept_filter_arg = unsafe { mem::zeroed() }; arg.af_name = buf; - setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg) } } else { - setsockopt( - self, - libc::SOL_SOCKET, - libc::SO_ACCEPTFILTER, - core::ptr::null_mut() as *mut c_void, - ) + unsafe { + setsockopt( + self, + libc::SOL_SOCKET, + libc::SO_ACCEPTFILTER, + core::ptr::null_mut() as *mut c_void, + ) + } } } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] pub fn acceptfilter(&self) -> io::Result<&CStr> { let arg: libc::accept_filter_arg = - getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)?; + unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)? }; let s: &[u8] = unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) }; let name = CStr::from_bytes_with_nul(s).unwrap(); @@ -531,53 +531,57 @@ impl Socket { pub fn set_exclbind(&self, excl: bool) -> io::Result<()> { // not yet on libc crate const SO_EXCLBIND: i32 = 0x1015; - setsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND, excl) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND, excl) } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn exclbind(&self) -> io::Result { // not yet on libc crate const SO_EXCLBIND: i32 = 0x1015; - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND)?; + let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND)? }; Ok(raw != 0) } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { - setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn passcred(&self) -> io::Result { - let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + let passcred: libc::c_int = + unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)? }; Ok(passcred != 0) } #[cfg(target_os = "netbsd")] pub fn set_local_creds(&self, local_creds: bool) -> io::Result<()> { - setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, local_creds as libc::c_int) + unsafe { setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, local_creds as libc::c_int) } } #[cfg(target_os = "netbsd")] pub fn local_creds(&self) -> io::Result { - let local_creds: libc::c_int = getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)?; + let local_creds: libc::c_int = + unsafe { getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)? }; Ok(local_creds != 0) } #[cfg(target_os = "freebsd")] pub fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> { - setsockopt( - self, - libc::AF_LOCAL, - libc::LOCAL_CREDS_PERSISTENT, - local_creds_persistent as libc::c_int, - ) + unsafe { + setsockopt( + self, + libc::AF_LOCAL, + libc::LOCAL_CREDS_PERSISTENT, + local_creds_persistent as libc::c_int, + ) + } } #[cfg(target_os = "freebsd")] pub fn local_creds_persistent(&self) -> io::Result { let local_creds_persistent: libc::c_int = - getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?; + unsafe { getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)? }; Ok(local_creds_persistent != 0) } @@ -590,7 +594,7 @@ impl Socket { #[cfg(target_os = "vita")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let option = nonblocking as libc::c_int; - setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] @@ -608,11 +612,11 @@ impl Socket { let option = libc::SO_USER_COOKIE; #[cfg(target_os = "openbsd")] let option = libc::SO_RTABLE; - setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int) + unsafe { setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int) } } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index c77c50fece1a..fbd89f3c8b05 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -270,11 +270,11 @@ impl Socket { } None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -303,11 +303,11 @@ impl Socket { } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -317,7 +317,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 2221023a2125..2fdebe6c90d8 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -384,11 +384,11 @@ impl Socket { } None => 0, }; - setsockopt(self, c::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, c::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: u32 = getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = unsafe { getsockopt(self, c::SOL_SOCKET, kind)? }; if raw == 0 { Ok(None) } else { @@ -421,26 +421,26 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; - setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) + unsafe { setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: c::LINGER = getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = unsafe { getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) + unsafe { setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } } pub fn nodelay(&self) -> io::Result { - let raw: c::BOOL = getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = unsafe { getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)? }; Ok(raw != 0) } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } From bf6f75f98ebb5304800d45e58d08ed8a5cc7c584 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 30 Sep 2025 18:07:27 +0300 Subject: [PATCH 427/537] Add regression test for another (long-standing) bug fixed by the new solver --- .../hir-ty/src/tests/regression/new_solver.rs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index c7711f31bf26..adc35cc9bc1c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use crate::tests::{check_infer, check_no_mismatches}; +use crate::tests::{check_infer, check_no_mismatches, check_types}; #[test] fn regression_20365() { @@ -450,3 +450,25 @@ fn main() { "#, ); } + +#[test] +fn double_into_iter() { + check_types( + r#" +//- minicore: iterator + +fn intoiter_issue(foo: A) +where + A: IntoIterator, + B: IntoIterator, +{ + for x in foo { + // ^ B + for m in x { + // ^ usize + } + } +} +"#, + ); +} From 3534594029ed1495290e013647a1f53da561f7f1 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 30 Sep 2025 17:10:22 +0200 Subject: [PATCH 428/537] std: merge address family computation --- library/std/src/os/unix/net/datagram.rs | 2 +- library/std/src/os/unix/net/listener.rs | 4 ++-- library/std/src/os/unix/net/stream.rs | 4 ++-- .../std/src/sys/net/connection/socket/hermit.rs | 10 +--------- library/std/src/sys/net/connection/socket/mod.rs | 15 +++++++++++---- .../std/src/sys/net/connection/socket/solid.rs | 16 +++------------- .../std/src/sys/net/connection/socket/unix.rs | 14 +++----------- .../std/src/sys/net/connection/socket/wasip2.rs | 12 ++---------- .../std/src/sys/net/connection/socket/windows.rs | 6 +----- 9 files changed, 26 insertions(+), 57 deletions(-) diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 469bfbb0d837..163267be1e5c 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -159,7 +159,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_DGRAM)?; Ok(UnixDatagram(inner)) } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 27428c9eb285..5b4659e26188 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -71,7 +71,7 @@ impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; #[cfg(any( target_os = "windows", @@ -136,7 +136,7 @@ impl UnixListener { #[stable(feature = "unix_socket_abstract", since = "1.70.0")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; #[cfg(target_os = "linux")] const backlog: core::ffi::c_int = -1; #[cfg(not(target_os = "linux"))] diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index ea4171a7d287..851ff7f08795 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -105,7 +105,7 @@ impl UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(path: P) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?; @@ -139,7 +139,7 @@ impl UnixStream { #[stable(feature = "unix_socket_abstract", since = "1.70.0")] pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), (&raw const socket_addr.addr) as *const _, diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 0c105ed20fa7..2f5c6fa31d40 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -37,15 +37,7 @@ pub fn init() {} pub struct Socket(FileDesc); impl Socket { - pub fn new(addr: &SocketAddr, ty: i32) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: i32, ty: i32) -> io::Result { + pub fn new(fam: i32, ty: i32) -> io::Result { let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) })) } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index d01a52b86109..d0a4a2fab497 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -178,6 +178,13 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { } } +fn addr_family(addr: &SocketAddr) -> c_int { + match addr { + SocketAddr::V4(..) => c::AF_INET, + SocketAddr::V6(..) => c::AF_INET6, + } +} + /// Converts the C socket address stored in `storage` to a Rust `SocketAddr`. /// /// # Safety @@ -364,7 +371,7 @@ impl TcpStream { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; sock.connect(addr)?; Ok(TcpStream { inner: sock }) } @@ -373,7 +380,7 @@ impl TcpStream { pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { init(); - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; sock.connect_timeout(addr, timeout)?; Ok(TcpStream { inner: sock }) } @@ -535,7 +542,7 @@ impl TcpListener { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; // On platforms with Berkeley-derived sockets, this allows to quickly // rebind a socket, without needing to wait for the OS to clean up the @@ -661,7 +668,7 @@ impl UdpSocket { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_DGRAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_DGRAM)?; let (addr, len) = socket_addr_to_c(addr); cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; Ok(UdpSocket { inner: sock }) diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index dfde5513f909..14cf75adcc06 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -115,19 +115,9 @@ pub fn init() {} pub struct Socket(OwnedFd); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - let fd = cvt(netc::socket(fam, ty, 0))?; - Ok(Self::from_raw_fd(fd)) - } + pub fn new(fam: c_int, ty: c_int) -> io::Result { + let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 3f05449903fd..559e27604a9d 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -63,15 +63,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { } impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { + pub fn new(family: c_int, ty: c_int) -> io::Result { cfg_select! { any( target_os = "android", @@ -89,7 +81,7 @@ impl Socket { // On platforms that support it we pass the SOCK_CLOEXEC // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. - let fd = cvt(unsafe { libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0) })?; + let fd = cvt(unsafe { libc::socket(family, ty | libc::SOCK_CLOEXEC, 0) })?; let socket = Socket(unsafe { FileDesc::from_raw_fd(fd) }); // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` @@ -100,7 +92,7 @@ impl Socket { Ok(socket) } _ => { - let fd = cvt(unsafe { libc::socket(fam, ty, 0) })?; + let fd = cvt(unsafe { libc::socket(family, ty, 0) })?; let fd = unsafe { FileDesc::from_raw_fd(fd) }; fd.set_cloexec()?; let socket = Socket(fd); diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index fbd89f3c8b05..a1b08609eb02 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -74,16 +74,8 @@ pub struct WasiSocket(OwnedFd); pub struct Socket(WasiSocket); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; + pub fn new(family: c_int, ty: c_int) -> io::Result { + let fd = cvt(unsafe { netc::socket(family, ty, 0) })?; Ok(unsafe { Self::from_raw_fd(fd) }) } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 2fdebe6c90d8..6dbebc5e276e 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -117,11 +117,7 @@ pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init}; pub struct Socket(OwnedSocket); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let family = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; + pub fn new(family: c_int, ty: c_int) -> io::Result { let socket = unsafe { c::WSASocketW( family, From ba13b6ec6f919430412d99a3d50ff87042a787a7 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 29 Sep 2025 21:02:52 -0700 Subject: [PATCH 429/537] bootstrap: build bootstrap docs with in-tree rustdoc All of the docs need to be built with the same rustdoc. Otherwise, any change to the search index breaks everything, because the two rustdocs don't agree on the format. --- src/bootstrap/src/core/build_steps/doc.rs | 21 +++++++++++---------- src/bootstrap/src/core/builder/tests.rs | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 7865b6856593..37462c63f1b0 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1024,12 +1024,9 @@ macro_rules! tool_doc { run.builder.ensure(Rustc::from_build_compiler(run.builder, compilers.build_compiler(), target)); compilers.build_compiler() } - Mode::ToolBootstrap => { - // bootstrap/host tools should be documented with the stage 0 compiler - prepare_doc_compiler(run.builder, run.builder.host_target, 1) - } Mode::ToolTarget => { - // target tools should be documented with the in-tree compiler + // when shipping multiple docs together in one folder, + // they all need to use the same rustdoc version prepare_doc_compiler(run.builder, run.builder.host_target, run.builder.top_stage) } _ => { @@ -1132,7 +1129,11 @@ macro_rules! tool_doc { tool_doc!( BuildHelper, "src/build_helper", - mode = Mode::ToolBootstrap, + // ideally, this would use ToolBootstrap, + // but we distribute these docs together in the same folder + // as a bunch of stage1 tools, and you can't mix rustdoc versions + // because that breaks cross-crate data (particularly search) + mode = Mode::ToolTarget, is_library = true, crates = ["build_helper"] ); @@ -1175,25 +1176,25 @@ tool_doc!( // "specialization" feature in its build script when it detects a nightly toolchain. allow_features: "specialization" ); -tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolBootstrap, crates = ["tidy"]); +tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolTarget, crates = ["tidy"]); tool_doc!( Bootstrap, "src/bootstrap", - mode = Mode::ToolBootstrap, + mode = Mode::ToolTarget, is_library = true, crates = ["bootstrap"] ); tool_doc!( RunMakeSupport, "src/tools/run-make-support", - mode = Mode::ToolBootstrap, + mode = Mode::ToolTarget, is_library = true, crates = ["run_make_support"] ); tool_doc!( Compiletest, "src/tools/compiletest", - mode = Mode::ToolBootstrap, + mode = Mode::ToolTarget, is_library = true, crates = ["compiletest"] ); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 88df469e9a09..3306435758b4 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1158,13 +1158,12 @@ mod snapshot { [doc] embedded-book (book) [doc] edition-guide (book) [doc] style-guide (book) - [build] rustdoc 0 - [doc] rustc 0 -> Tidy 1 - [doc] rustc 0 -> Bootstrap 1 + [doc] rustc 1 -> Tidy 2 + [doc] rustc 1 -> Bootstrap 2 [doc] rustc 1 -> releases 2 - [doc] rustc 0 -> RunMakeSupport 1 - [doc] rustc 0 -> BuildHelper 1 - [doc] rustc 0 -> Compiletest 1 + [doc] rustc 1 -> RunMakeSupport 2 + [doc] rustc 1 -> BuildHelper 2 + [doc] rustc 1 -> Compiletest 2 [build] rustc 0 -> RustInstaller 1 " ); @@ -2686,8 +2685,11 @@ mod snapshot { .path("src/tools/compiletest") .stage(2) .render_steps(), @r" - [build] rustdoc 0 - [doc] rustc 0 -> Compiletest 1 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + [doc] rustc 1 -> Compiletest 2 "); } From d1bbd39c59523d7a5499816a9da200a5910f8b7f Mon Sep 17 00:00:00 2001 From: jackh726 Date: Sun, 28 Sep 2025 23:04:55 +0000 Subject: [PATCH 430/537] Split Bound into Canonical and Bound --- compiler/rustc_borrowck/src/lib.rs | 2 +- .../src/collect/item_bounds.rs | 16 ++-- .../src/hir_ty_lowering/bounds.rs | 6 +- .../src/infer/canonical/canonicalizer.rs | 53 ++++--------- .../src/infer/canonical/instantiate.rs | 74 +++++-------------- .../src/infer/canonical/query_response.rs | 18 ++--- .../src/infer/outlives/test_type_match.rs | 6 +- compiler/rustc_middle/src/ty/consts.rs | 14 +++- compiler/rustc_middle/src/ty/context.rs | 47 +++++++++++- compiler/rustc_middle/src/ty/fold.rs | 14 +++- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- compiler/rustc_middle/src/ty/region.rs | 36 +++++++-- compiler/rustc_middle/src/ty/sty.rs | 22 +++++- .../rustc_middle/src/ty/typeck_results.rs | 12 +-- compiler/rustc_middle/src/ty/visit.rs | 6 +- .../src/canonical/canonicalizer.rs | 34 ++------- .../src/canonical/mod.rs | 12 +-- .../src/placeholder.rs | 18 +++-- .../src/unstable/convert/stable/ty.rs | 7 +- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 5 +- compiler/rustc_symbol_mangling/src/v0.rs | 5 +- .../src/traits/dyn_compatibility.rs | 2 +- .../src/traits/query/normalize.rs | 4 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- compiler/rustc_type_ir/src/binder.rs | 43 ++++++++++- compiler/rustc_type_ir/src/canonical.rs | 23 +++--- compiler/rustc_type_ir/src/const_kind.rs | 4 +- compiler/rustc_type_ir/src/flags.rs | 18 ++++- compiler/rustc_type_ir/src/fold.rs | 24 ++++-- compiler/rustc_type_ir/src/inherent.rs | 6 ++ compiler/rustc_type_ir/src/lib.rs | 17 +++-- compiler/rustc_type_ir/src/region_kind.rs | 4 +- compiler/rustc_type_ir/src/ty_kind.rs | 4 +- compiler/rustc_type_ir/src/ty_kind/closure.rs | 5 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 4 +- src/tools/clippy/clippy_utils/src/ty/mod.rs | 4 +- ..._of_reborrow.SimplifyCfg-initial.after.mir | 18 ++--- ...st-mono-higher-ranked-hang.current.stderr} | 6 +- .../post-mono-higher-ranked-hang.next.stderr | 21 ++++++ .../post-mono-higher-ranked-hang.rs | 4 + .../trait-bounds/issue-59311.stderr | 2 +- .../trait-bounds/trivial-does-not-hold.stderr | 2 +- tests/ui/lifetimes/re-empty-in-error.stderr | 2 +- .../ui/nll/user-annotations/dump-fn-method.rs | 4 +- .../user-annotations/dump-fn-method.stderr | 4 +- 45 files changed, 391 insertions(+), 247 deletions(-) rename tests/ui/async-await/async-closures/{post-mono-higher-ranked-hang.stderr => post-mono-higher-ranked-hang.current.stderr} (85%) create mode 100644 tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4c380ddcf708..8b23bc2822bf 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -278,7 +278,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>, ) -> Ty<'tcx> { fold_regions(tcx, self.inner, |r, depth| match r.kind() { - ty::ReBound(debruijn, br) => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) => { debug_assert_eq!(debruijn, depth); map(ty::RegionVid::from_usize(br.var.index())) } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index ba54fa8cc0db..664ca35ddfbc 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -174,21 +174,25 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { let existing = match var.kind() { ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { + if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + re.kind() + { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } } ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { + if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } } ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + ct.kind() + { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; @@ -253,7 +257,7 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { return ty; } - if let ty::Bound(binder, old_bound) = *ty.kind() + if let ty::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = *ty.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { @@ -279,7 +283,7 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { } fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReBound(binder, old_bound) = re.kind() + if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), old_bound) = re.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { @@ -307,7 +311,7 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { return ct; } - if let ty::ConstKind::Bound(binder, old_bound) = ct.kind() + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = ct.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 99dc8e6e5221..4b2e20a78b9c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -915,7 +915,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't ty::Param(param) => { self.params.insert(param.index); } - ty::Bound(db, bt) if *db >= self.depth => { + ty::Bound(ty::BoundVarIndexKind::Bound(db), bt) if *db >= self.depth => { self.vars.insert(match bt.kind { ty::BoundTyKind::Param(def_id) => def_id, ty::BoundTyKind::Anon => { @@ -938,7 +938,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't ty::ReEarlyParam(param) => { self.params.insert(param.index); } - ty::ReBound(db, br) if db >= self.depth => { + ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.depth => { self.vars.insert(match br.kind { ty::BoundRegionKind::Named(def_id) => def_id, ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => { @@ -961,7 +961,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't ty::ConstKind::Param(param) => { self.params.insert(param.index); } - ty::ConstKind::Bound(db, _) if db >= self.depth => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(db), _) if db >= self.depth => { let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 3c5e4a91c98c..e445def4faa7 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -303,8 +303,6 @@ struct Canonicalizer<'cx, 'tcx> { sub_root_lookup_table: SsoHashMap, canonicalize_mode: &'cx dyn CanonicalizeMode, needs_canonical_flags: TypeFlags, - - binder_index: ty::DebruijnIndex, } impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { @@ -312,24 +310,12 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { self.tcx } - fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> - where - T: TypeFoldable>, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(index, ..) => { - if index >= self.binder_index { - bug!("escaping late-bound region during canonicalization"); - } else { - r - } + ty::ReBound(ty::BoundVarIndexKind::Bound(_), ..) => r, + + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::ReStatic @@ -403,12 +389,10 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t) } - ty::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") - } else { - t - } + ty::Bound(ty::BoundVarIndexKind::Bound(_), _) => t, + + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::Closure(..) @@ -479,12 +463,11 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("encountered a fresh const during canonicalization") } - ty::ConstKind::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound const during canonicalization") - } else { - return ct; - } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(_), _) => { + return ct; + } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::ConstKind::Placeholder(placeholder) => { return self @@ -569,7 +552,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { query_state, indices: FxHashMap::default(), sub_root_lookup_table: Default::default(), - binder_index: ty::INNERMOST, }; if canonicalizer.query_state.var_values.spilled() { canonicalizer.indices = canonicalizer @@ -751,8 +733,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(var_kind, r.into()); - let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }; - ty::Region::new_bound(self.cx(), self.binder_index, br) + ty::Region::new_canonical_bound(self.cx(), var) } /// Given a type variable `ty_var` of the given kind, first check @@ -766,8 +747,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); let var = self.canonical_var(var_kind, ty_var.into()); - let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon }; - Ty::new_bound(self.tcx, self.binder_index, bt) + Ty::new_canonical_bound(self.tcx, var) } /// Given a type variable `const_var` of the given kind, first check @@ -783,7 +763,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var)) ); let var = self.canonical_var(var_kind, ct_var.into()); - let bc = ty::BoundConst { var }; - ty::Const::new_bound(self.tcx, self.binder_index, bc) + ty::Const::new_canonical_bound(self.tcx, var) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index cc052fbd85c1..c215a9db2a0a 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{ self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_type_ir::TypeVisitable; +use rustc_type_ir::{TypeFlags, TypeVisitable}; use crate::infer::canonical::{Canonical, CanonicalVarValues}; @@ -66,7 +66,6 @@ where value.fold_with(&mut CanonicalInstantiator { tcx, - current_index: ty::INNERMOST, var_values: var_values.var_values, cache: Default::default(), }) @@ -79,12 +78,9 @@ struct CanonicalInstantiator<'tcx> { // The values that the bound vars are are being instantiated with. var_values: ty::GenericArgsRef<'tcx>, - /// As with `BoundVarReplacer`, represents the index of a binder *just outside* - /// the ones we have visited. - current_index: ty::DebruijnIndex, - - // Instantiation is a pure function of `DebruijnIndex` and `Ty`. - cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>, + // Because we use `ty::BoundVarIndexKind::Canonical`, we can cache + // based only on the entire ty, not worrying about a `DebruijnIndex` + cache: DelayedMap, Ty<'tcx>>, } impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { @@ -92,29 +88,19 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { self.tcx } - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) => { self.var_values[bound_ty.var.as_usize()].expect_ty() } _ => { - if !t.has_vars_bound_at_or_above(self.current_index) { + if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { t - } else if let Some(&t) = self.cache.get(&(self.current_index, t)) { + } else if let Some(&t) = self.cache.get(&t) { t } else { let res = t.super_fold_with(self); - assert!(self.cache.insert((self.current_index, t), res)); + assert!(self.cache.insert(t, res)); res } } @@ -123,7 +109,7 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(debruijn, br) if debruijn == self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Canonical, br) => { self.var_values[br.var.as_usize()].expect_region() } _ => r, @@ -132,7 +118,7 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) => { self.var_values[bound_const.var.as_usize()].expect_const() } _ => ct.super_fold_with(self), @@ -140,22 +126,14 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { } fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } } fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { - if !c.has_vars_bound_at_or_above(self.current_index) { + if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { return c; } - // Since instantiation is a function of `DebruijnIndex`, we don't want - // to have to cache more copies of clauses when we're inside of binders. - // Since we currently expect to only have clauses in the outermost - // debruijn index, we just fold if we're inside of a binder. - if self.current_index > ty::INNERMOST { - return c.super_fold_with(self); - } - // Our cache key is `(clauses, var_values)`, but we also don't care about // var values that aren't named in the clauses, since they can change without // affecting the output. Since `ParamEnv`s are cached first, we compute the @@ -185,45 +163,29 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize { struct HighestVarInClauses { max_var: usize, - current_index: ty::DebruijnIndex, } impl<'tcx> TypeVisitor> for HighestVarInClauses { - fn visit_binder>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> Self::Result { - self.current_index.shift_in(1); - let t = t.super_visit_with(self); - self.current_index.shift_out(1); - t - } fn visit_ty(&mut self, t: Ty<'tcx>) { - if let ty::Bound(debruijn, bound_ty) = *t.kind() - && debruijn == self.current_index - { + if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) = *t.kind() { self.max_var = self.max_var.max(bound_ty.var.as_usize()); - } else if t.has_vars_bound_at_or_above(self.current_index) { + } else if t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { t.super_visit_with(self); } } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReBound(debruijn, bound_region) = r.kind() - && debruijn == self.current_index - { + if let ty::ReBound(ty::BoundVarIndexKind::Canonical, bound_region) = r.kind() { self.max_var = self.max_var.max(bound_region.var.as_usize()); } } fn visit_const(&mut self, ct: ty::Const<'tcx>) { - if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind() - && debruijn == self.current_index - { + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) = ct.kind() { self.max_var = self.max_var.max(bound_const.var.as_usize()); - } else if ct.has_vars_bound_at_or_above(self.current_index) { + } else if ct.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { ct.super_visit_with(self); } } } - let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST }; + let mut visitor = HighestVarInClauses { max_var: 0 }; c.visit_with(&mut visitor); visitor.max_var } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5d1b4be9e57b..3c20bdd9391a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -422,28 +422,28 @@ impl<'tcx> InferCtxt<'tcx> { // and only use it for placeholders. We need to handle the // `sub_root` of type inference variables which would make this // more involved. They are also a lot rarer than region variables. - if let ty::Bound(debruijn, b) = *result_value.kind() + if let ty::Bound(index_kind, b) = *result_value.kind() && !matches!( query_response.variables[b.var.as_usize()], CanonicalVarKind::Ty { .. } ) { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Lifetime(result_value) => { - if let ty::ReBound(debruijn, b) = result_value.kind() { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ReBound(index_kind, b) = result_value.kind() { + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { - if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ConstKind::Bound(index_kind, b) = result_value.kind() { + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index f06eb58a371c..6592360cf0a5 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -44,8 +44,8 @@ pub fn extract_verify_if_eq<'tcx>( let verify_if_eq = verify_if_eq_b.skip_binder(); m.relate(verify_if_eq.ty, test_ty).ok()?; - if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() { - assert!(depth == ty::INNERMOST); + if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST))); match m.map.get(&br) { Some(&r) => Some(r), None => { @@ -156,7 +156,7 @@ impl<'tcx> TypeRelation> for MatchAgainstHigherRankedOutlives<'tcx> pattern: ty::Region<'tcx>, value: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - if let ty::RegionKind::ReBound(depth, br) = pattern.kind() + if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(depth), br) = pattern.kind() && depth == self.pattern_depth { self.bind(br, value) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 614b6471f188..95adb561c704 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -95,7 +95,15 @@ impl<'tcx> Const<'tcx> { debruijn: ty::DebruijnIndex, bound_const: ty::BoundConst, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const)) + Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)) + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> { + Const::new( + tcx, + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }), + ) } #[inline] @@ -180,6 +188,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_bound(tcx, debruijn, ty::BoundConst { var }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self { + Const::new_canonical_bound(tcx, var) + } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { Const::new_placeholder(tcx, placeholder) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7d3e2c9965da..161fec9245a8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1110,6 +1110,15 @@ const NUM_PREINTERNED_FRESH_TYS: u32 = 20; const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3; const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3; const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3; + +// From general profiling of the *max vars during canonicalization* of a value: +// - about 90% of the time, there are no canonical vars +// - about 9% of the time, there is only one canonical var +// - there are rarely more than 3-5 canonical vars (with exceptions in particularly pathological cases) +// This may not match the number of bound vars found in `for`s. +// Given that this is all heap interned, it seems likely that interning fewer +// vars here won't make an appreciable difference. Though, if we were to inline the data (in an array), +// we may want to consider reducing the number for canonicalized vars down to 4 or so. const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20; // This number may seem high, but it is reached in all but the smallest crates. @@ -1160,9 +1169,14 @@ pub struct CommonTypes<'tcx> { pub fresh_float_tys: Vec>, /// Pre-interned values of the form: - /// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})` + /// `Bound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundTy { var: v, kind: BoundTyKind::Anon})` /// for small values of `i` and `v`. pub anon_bound_tys: Vec>>, + + // Pre-interned values of the form: + // `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })` + // for small values of `v`. + pub anon_canonical_bound_tys: Vec>, } pub struct CommonLifetimes<'tcx> { @@ -1176,9 +1190,14 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec>, /// Pre-interned values of the form: - /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })` + /// `ReBound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundRegion { var: v, kind: BoundRegionKind::Anon })` /// for small values of `i` and `v`. pub anon_re_bounds: Vec>>, + + // Pre-interned values of the form: + // `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })` + // for small values of `v`. + pub anon_re_canonical_bounds: Vec>, } pub struct CommonConsts<'tcx> { @@ -1211,7 +1230,7 @@ impl<'tcx> CommonTypes<'tcx> { (0..NUM_PREINTERNED_ANON_BOUND_TYS_V) .map(|v| { mk(ty::Bound( - ty::DebruijnIndex::from(i), + ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)), ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, )) }) @@ -1219,6 +1238,15 @@ impl<'tcx> CommonTypes<'tcx> { }) .collect(); + let anon_canonical_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_V) + .map(|v| { + mk(ty::Bound( + ty::BoundVarIndexKind::Canonical, + ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, + )) + }) + .collect(); + CommonTypes { unit: mk(Tuple(List::empty())), bool: mk(Bool), @@ -1250,6 +1278,7 @@ impl<'tcx> CommonTypes<'tcx> { fresh_int_tys, fresh_float_tys, anon_bound_tys, + anon_canonical_bound_tys, } } } @@ -1270,7 +1299,7 @@ impl<'tcx> CommonLifetimes<'tcx> { (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V) .map(|v| { mk(ty::ReBound( - ty::DebruijnIndex::from(i), + ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)), ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon, @@ -1281,11 +1310,21 @@ impl<'tcx> CommonLifetimes<'tcx> { }) .collect(); + let anon_re_canonical_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V) + .map(|v| { + mk(ty::ReBound( + ty::BoundVarIndexKind::Canonical, + ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon }, + )) + }) + .collect(); + CommonLifetimes { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased), re_vars, anon_re_bounds, + anon_re_canonical_bounds, } } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 7d56ec1635f8..ee29afcff638 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -125,7 +125,9 @@ where fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn == self.current_index => + { let ty = self.delegate.replace_ty(bound_ty); debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); ty::shift_vars(self.tcx, ty, self.current_index.as_u32()) @@ -146,9 +148,11 @@ where fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(debruijn, br) if debruijn == self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn == self.current_index => + { let region = self.delegate.replace_region(br); - if let ty::ReBound(debruijn1, br) = region.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() { // If the callback returns a bound region, // that region should always use the INNERMOST // debruijn index. Then we adjust it to the @@ -165,7 +169,9 @@ where fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const) + if debruijn == self.current_index => + { let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST)); ty::shift_vars(self.tcx, ct, self.current_index.as_u32()) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8f7c8170f7ad..4d1fcaeda5e2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2664,7 +2664,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; let region = match r.kind() { - ty::ReBound(db, br) if db >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.current_index => { *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) } ty::RePlaceholder(ty::PlaceholderRegion { @@ -2687,7 +2687,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { } _ => return r, }; - if let ty::ReBound(debruijn1, br) = region.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() { assert_eq!(debruijn1, ty::INNERMOST); ty::Region::new_bound(self.tcx, self.current_index, br) } else { diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 3a7852dea068..f0687f2bc726 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -31,7 +31,7 @@ impl<'tcx> rustc_type_ir::Flags for Region<'tcx> { fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { match self.kind() { - ty::ReBound(debruijn, _) => debruijn.shifted_in(1), + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1), _ => ty::INNERMOST, } } @@ -59,7 +59,20 @@ impl<'tcx> Region<'tcx> { { re } else { - tcx.intern_region(ty::ReBound(debruijn, bound_region)) + tcx.intern_region(ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), bound_region)) + } + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let Some(re) = tcx.lifetimes.anon_re_canonical_bounds.get(var.as_usize()).copied() { + re + } else { + tcx.intern_region(ty::ReBound( + ty::BoundVarIndexKind::Canonical, + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + )) } } @@ -122,7 +135,12 @@ impl<'tcx> Region<'tcx> { pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { match kind { ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), - ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), region) => { + Region::new_bound(tcx, debruijn, region) + } + ty::ReBound(ty::BoundVarIndexKind::Canonical, region) => { + Region::new_canonical_bound(tcx, region.var) + } ty::ReLateParam(ty::LateParamRegion { scope, kind }) => { Region::new_late_param(tcx, scope, kind) } @@ -148,6 +166,10 @@ impl<'tcx> rustc_type_ir::inherent::Region> for Region<'tcx> { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self { + Region::new_canonical_bound(tcx, var) + } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self { Region::new_placeholder(tcx, placeholder) } @@ -223,7 +245,7 @@ impl<'tcx> Region<'tcx> { #[inline] pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match self.kind() { - ty::ReBound(debruijn, _) => debruijn >= index, + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index, _ => false, } } @@ -254,7 +276,11 @@ impl<'tcx> Region<'tcx> { ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - ty::ReBound(..) => { + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { + flags = flags | TypeFlags::HAS_RE_BOUND; + flags = flags | TypeFlags::HAS_CANONICAL_BOUND; + } + ty::ReBound(ty::BoundVarIndexKind::Bound(..), _) => { flags = flags | TypeFlags::HAS_RE_BOUND; } ty::ReErased => { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index de35e5e847c8..a3fdd4e35b6a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -487,7 +487,23 @@ impl<'tcx> Ty<'tcx> { { ty } else { - Ty::new(tcx, Bound(index, bound_ty)) + Ty::new(tcx, Bound(ty::BoundVarIndexKind::Bound(index), bound_ty)) + } + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> { + // Use a pre-interned one when possible. + if let Some(ty) = tcx.types.anon_canonical_bound_tys.get(var.as_usize()).copied() { + ty + } else { + Ty::new( + tcx, + Bound( + ty::BoundVarIndexKind::Canonical, + ty::BoundTy { var, kind: ty::BoundTyKind::Anon }, + ), + ) } } @@ -952,6 +968,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Self { + Ty::new_canonical_bound(tcx, var) + } + fn new_alias( interner: TyCtxt<'tcx>, kind: ty::AliasTyKind, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 8dd80aab946d..370ef364bf5c 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -798,8 +798,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { match arg.kind() { GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(*debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(*debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, @@ -807,8 +807,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Lifetime(r) => match r.kind() { ty::ReBound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, @@ -816,8 +816,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Const(ct) => match ct.kind() { ty::ConstKind::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f0c47f257cc4..e84ac56b31df 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -78,7 +78,9 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { match r.kind() { - ty::ReBound(debruijn, _) if debruijn < self.outer_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn < self.outer_index => + { ControlFlow::Continue(()) } _ => { @@ -205,7 +207,7 @@ impl<'tcx> TypeVisitor> for LateBoundRegionsCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReBound(debruijn, br) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) = r.kind() { if debruijn == self.current_index { self.regions.insert(br.kind); } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index b25671d676b9..9162284422d0 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -74,12 +74,10 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner /// we set the `sub_root` of the second variable to the position of the first. /// Otherwise the `sub_root` of each type variable is just its own position. sub_root_lookup_table: HashMap, - binder_index: ty::DebruijnIndex, - /// We only use the debruijn index during lookup. We don't need to - /// track the `variables` as each generic arg only results in a single - /// bound variable regardless of how many times it is encountered. - cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, + /// We can simply cache based on the ty itself, because we use + /// `ty::BoundVarIndexKind::Canonical`. + cache: HashMap, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { @@ -97,7 +95,6 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; @@ -141,12 +138,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); CanonicalParamEnvCacheEntry { param_env, @@ -175,12 +170,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) } @@ -212,7 +205,6 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table, sub_root_lookup_table: Default::default(), var_kinds, - binder_index: ty::INNERMOST, // We do not reuse the cache as it may contain entries whose canonicalized // value contains `'static`. While we could alternatively handle this by @@ -409,7 +401,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let var = self.get_or_insert_bound_var(t, kind); - Ty::new_anon_bound(self.cx(), self.binder_index, var) + Ty::new_canonical_bound(self.cx(), var) } } @@ -418,16 +410,6 @@ impl, I: Interner> TypeFolder for Canonicaliz self.delegate.cx() } - fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder - where - T: TypeFoldable, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - fn fold_region(&mut self, r: I::Region) -> I::Region { let kind = match r.kind() { ty::ReBound(..) => return r, @@ -491,15 +473,15 @@ impl, I: Interner> TypeFolder for Canonicaliz let var = self.get_or_insert_bound_var(r, kind); - Region::new_anon_bound(self.cx(), self.binder_index, var) + Region::new_canonical_bound(self.cx(), var) } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { + if let Some(&ty) = self.cache.get(&t) { ty } else { let res = self.inner_fold_ty(t); - let old = self.cache.insert((self.binder_index, t), res); + let old = self.cache.insert(t, res); assert_eq!(old, None); res } @@ -552,7 +534,7 @@ impl, I: Interner> TypeFolder for Canonicaliz let var = self.get_or_insert_bound_var(c, kind); - Const::new_anon_bound(self.cx(), self.binder_index, var) + Const::new_canonical_bound(self.cx(), var) } fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index e3520e238ed3..4c1569e478f8 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -167,25 +167,25 @@ where // and only use it for placeholders. We need to handle the // `sub_root` of type inference variables which would make this // more involved. They are also a lot rarer than region variables. - if let ty::Bound(debruijn, b) = t.kind() + if let ty::Bound(index_kind, b) = t.kind() && !matches!( response.variables.get(b.var().as_usize()).unwrap(), CanonicalVarKind::Ty { .. } ) { - assert_eq!(debruijn, ty::INNERMOST); + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var()] = Some(*original_value); } } ty::GenericArgKind::Lifetime(r) => { - if let ty::ReBound(debruijn, br) = r.kind() { - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ReBound(index_kind, br) = r.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[br.var()] = Some(*original_value); } } ty::GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ConstKind::Bound(index_kind, bv) = c.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[bv.var()] = Some(*original_value); } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index c88fb8defae7..c8016759f239 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -90,7 +90,7 @@ where fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, _) + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() >= self.current_index.as_usize() + self.universe_indices.len() => { @@ -99,7 +99,9 @@ where self.universe_indices ); } - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, br); self.mapped_regions.insert(p, br); @@ -111,7 +113,7 @@ where fn fold_ty(&mut self, t: I::Ty) -> I::Ty { match t.kind() { - ty::Bound(debruijn, _) + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { @@ -120,7 +122,9 @@ where self.universe_indices ); } - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, bound_ty); self.mapped_types.insert(p, bound_ty); @@ -133,7 +137,7 @@ where fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Bound(debruijn, _) + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { @@ -142,7 +146,9 @@ where self.universe_indices ); } - ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, bound_const); self.mapped_consts.insert(p, bound_const); diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 7f14f878d373..59440e5407f4 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -453,7 +453,10 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx)) } ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)), - ty::Bound(debruijn_idx, bound_ty) => { + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + unreachable!() + } + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn_idx), bound_ty) => { TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables, cx)) } ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness( @@ -907,7 +910,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> { index: early_reg.index, name: early_reg.name.to_string(), }), - ty::ReBound(db_index, bound_reg) => RegionKind::ReBound( + ty::ReBound(ty::BoundVarIndexKind::Bound(db_index), bound_reg) => RegionKind::ReBound( db_index.as_u32(), BoundRegion { var: bound_reg.var.as_u32(), diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index ec7a4a81a71a..621cc0fb3ef1 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -287,7 +287,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap, // u6region[I[][]E] as vendor extended type let mut s = String::new(); match region.kind() { - RegionKind::ReBound(debruijn, r) => { + RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => { s.push_str("u6regionI"); // Debruijn index, which identifies the binder, as region disambiguator let num = debruijn.index() as u64; @@ -303,7 +303,8 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap, s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReEarlyParam(..) + RegionKind::ReBound(ty::BoundVarIndexKind::Canonical, _) + | RegionKind::ReEarlyParam(..) | RegionKind::ReLateParam(..) | RegionKind::ReStatic | RegionKind::ReError(_) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 9fa7e2f10039..d808ade58e69 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -412,7 +412,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { // Bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReBound(debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) => { + ty::ReBound( + ty::BoundVarIndexKind::Bound(debruijn), + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + ) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + var.as_u32(); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 3260dd712b9e..6ab92531e4ef 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -830,7 +830,7 @@ impl<'tcx> TypeFolder> for EraseEscapingBoundRegions<'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReBound(debruijn, _) = r.kind() + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() && debruijn < self.binder { r diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a54eb80fedc2..c6eb0caee1a6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -145,7 +145,9 @@ impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { #[inline] fn visit_region(&mut self, r: ty::Region<'tcx>) { match r.kind() { - ty::ReBound(debruijn, _) if debruijn > self.outer_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn > self.outer_index => + { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index e91e5055e905..bb25a14ef744 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -235,7 +235,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { // bounds of the RPITIT. Shift these binders back out when // constructing the top-level projection predicate. let shifted_alias_ty = fold_regions(self.tcx, unshifted_alias_ty, |re, depth| { - if let ty::ReBound(index, bv) = re.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(index), bv) = re.kind() { if depth != ty::INNERMOST { return ty::Region::new_error_with_message( self.tcx, diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 6591d3148cb1..94b950357e1e 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -4,6 +4,7 @@ use std::ops::{ControlFlow, Deref}; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; use crate::data_structures::SsoHashSet; @@ -11,7 +12,7 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldabl use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, Interner}; +use crate::{self as ty, DebruijnIndex, Interner}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -299,7 +300,9 @@ impl TypeVisitor for ValidateBoundVars { return ControlFlow::Break(()); } match t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn == self.binder_index => + { let idx = bound_ty.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); @@ -317,7 +320,9 @@ impl TypeVisitor for ValidateBoundVars { return ControlFlow::Break(()); } match c.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.binder_index => { + ty::ConstKind::Bound(debruijn, bound_const) + if debruijn == ty::BoundVarIndexKind::Bound(self.binder_index) => + { let idx = bound_const.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", c, self.bound_vars); @@ -332,7 +337,7 @@ impl TypeVisitor for ValidateBoundVars { fn visit_region(&mut self, r: I::Region) -> Self::Result { match r.kind() { - ty::ReBound(index, br) if index == self.binder_index => { + ty::ReBound(index, br) if index == ty::BoundVarIndexKind::Bound(self.binder_index) => { let idx = br.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars); @@ -913,3 +918,33 @@ impl<'a, I: Interner> ArgFolder<'a, I> { } } } + +/// Okay, we do something fun for `Bound` types/regions/consts: +/// Specifically, we distinguish between *canonically* bound things and +/// `for<>` bound things. And, really, it comes down to caching during +/// canonicalization and instantiation. +/// +/// To understand why we do this, imagine we have a type `(T, for<> fn(T))`. +/// If we just tracked canonically bound types with a `DebruijnIndex` (as we +/// used to), then the canonicalized type would be something like +/// `for<0> (^0.0, for<> fn(^1.0))` and so we can't cache `T -> ^0.0`, +/// we have to also factor in binder level. (Of course, we don't cache that +/// exactly, but rather the entire enclosing type, but the point stands.) +/// +/// Of course, this is okay because we don't ever nest canonicalization, so +/// `BoundVarIndexKind::Canonical` is unambiguous. We, alternatively, could +/// have some sentinel `DebruijinIndex`, but that just seems too scary. +/// +/// This doesn't seem to have a huge perf swing either way, but in the next +/// solver, canonicalization is hot and there are some pathological cases where +/// this is needed (`post-mono-higher-ranked-hang`). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub enum BoundVarIndexKind { + Bound(DebruijnIndex), + Canonical, +} diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ecf3ae4f8b2c..7b4b953b2cf6 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -230,13 +230,13 @@ impl CanonicalVarValues { pub fn is_identity(&self) -> bool { self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() { ty::GenericArgKind::Lifetime(r) => { - matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv) + matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if br.var().as_usize() == bv) } ty::GenericArgKind::Type(ty) => { - matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv) + matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if bt.var().as_usize() == bv) } ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv) + matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if bc.var().as_usize() == bv) } }) } @@ -246,21 +246,23 @@ impl CanonicalVarValues { for arg in self.var_values.iter() { match arg.kind() { ty::GenericArgKind::Lifetime(r) => { - if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) { + if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if var == br.var()) + { var = var + 1; } else { // It's ok if this region var isn't an identity variable } } ty::GenericArgKind::Type(ty) => { - if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) { + if matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if var == bt.var()) + { var = var + 1; } else { return false; } } ty::GenericArgKind::Const(ct) => { - if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var()) + if matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if var == bc.var()) { var = var + 1; } else { @@ -284,16 +286,13 @@ impl CanonicalVarValues { | CanonicalVarKind::Int | CanonicalVarKind::Float | CanonicalVarKind::PlaceholderTy(_) => { - Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Ty::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Region::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { - Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Const::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } } }, diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 6de41b47bde0..273b60960087 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{self as ty, DebruijnIndex, Interner}; +use crate::{self as ty, BoundVarIndexKind, Interner}; /// Represents a constant in Rust. #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] @@ -23,7 +23,7 @@ pub enum ConstKind { Infer(InferConst), /// Bound const variable, used only when preparing a trait query. - Bound(DebruijnIndex, I::BoundConst), + Bound(BoundVarIndexKind, I::BoundConst), /// A placeholder const - universally quantified higher-ranked const. Placeholder(I::PlaceholderConst), diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 24704c5bb535..03099b331984 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -133,6 +133,9 @@ bitflags::bitflags! { /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 24; + + /// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`? + const HAS_CANONICAL_BOUND = 1 << 25; } } @@ -254,7 +257,12 @@ impl FlagComputation { self.add_args(args.as_slice()); } - ty::Bound(debruijn, _) => { + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + self.add_flags(TypeFlags::HAS_TY_BOUND); + self.add_flags(TypeFlags::HAS_CANONICAL_BOUND); + } + + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_TY_BOUND); } @@ -434,7 +442,7 @@ impl FlagComputation { fn add_region(&mut self, r: I::Region) { self.add_flags(r.flags()); - if let ty::ReBound(debruijn, _) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() { self.add_bound_var(debruijn); } } @@ -454,10 +462,14 @@ impl FlagComputation { ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), }, - ty::ConstKind::Bound(debruijn, _) => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_CT_BOUND); } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => { + self.add_flags(TypeFlags::HAS_CT_BOUND); + self.add_flags(TypeFlags::HAS_CANONICAL_BOUND); + } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index a5eb8699e5fc..d1a50599e8b9 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -55,7 +55,7 @@ use tracing::{debug, instrument}; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, Interner, TypeFlags}; +use crate::{self as ty, BoundVarIndexKind, Interner, TypeFlags}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -398,7 +398,9 @@ impl TypeFolder for Shifter { fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Region::new_bound(self.cx, debruijn, br) } @@ -408,7 +410,9 @@ impl TypeFolder for Shifter { fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { match ty.kind() { - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Ty::new_bound(self.cx, debruijn, bound_ty) } @@ -420,7 +424,9 @@ impl TypeFolder for Shifter { fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ct) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Const::new_bound(self.cx, debruijn, bound_ct) } @@ -435,7 +441,7 @@ impl TypeFolder for Shifter { pub fn shift_region(cx: I, region: I::Region, amount: u32) -> I::Region { match region.kind() { - ty::ReBound(debruijn, br) if amount > 0 => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) if amount > 0 => { Region::new_bound(cx, debruijn.shifted_in(amount), br) } _ => region, @@ -515,7 +521,13 @@ where #[instrument(skip(self), level = "debug", ret)] fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, _) if debruijn < self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn < self.current_index => + { + debug!(?self.current_index, "skipped bound region"); + r + } + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { debug!(?self.current_index, "skipped bound region"); r } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b5b552dbaec0..75ba0231d98c 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -48,6 +48,8 @@ pub trait Ty>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self { @@ -230,6 +232,8 @@ pub trait Region>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_static(interner: I) -> Self; fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self; @@ -260,6 +264,8 @@ pub trait Const>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self; fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 61e0b67b1639..c1e301961267 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -196,13 +196,20 @@ impl DebruijnIndex { pub fn debug_bound_var( fmt: &mut T, - debruijn: DebruijnIndex, + bound_index: BoundVarIndexKind, var: impl std::fmt::Debug, ) -> Result<(), std::fmt::Error> { - if debruijn == INNERMOST { - write!(fmt, "^{var:?}") - } else { - write!(fmt, "^{}_{:?}", debruijn.index(), var) + match bound_index { + BoundVarIndexKind::Bound(debruijn) => { + if debruijn == INNERMOST { + write!(fmt, "^{var:?}") + } else { + write!(fmt, "^{}_{:?}", debruijn.index(), var) + } + } + BoundVarIndexKind::Canonical => { + write!(fmt, "^c_{:?}", var) + } } } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 06048af04362..1e8585cf52ce 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use self::RegionKind::*; -use crate::{DebruijnIndex, Interner}; +use crate::{BoundVarIndexKind, Interner}; rustc_index::newtype_index! { /// A **region** **v**ariable **ID**. @@ -147,7 +147,7 @@ pub enum RegionKind { /// Bound regions inside of types **must not** be erased, as they impact trait /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and /// `fn(&'static ())` are different types and have to be treated as such. - ReBound(DebruijnIndex, I::BoundRegion), + ReBound(BoundVarIndexKind, I::BoundRegion), /// Late-bound function parameters are represented using a `ReBound`. When /// inside of a function, we convert these bound variables to placeholder diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index dda59283677c..bb80e2cf46d4 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -15,7 +15,7 @@ pub use self::closure::*; use crate::inherent::*; #[cfg(feature = "nightly")] use crate::visit::TypeVisitable; -use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy}; +use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy}; mod closure; @@ -229,7 +229,7 @@ pub enum TyKind { /// /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html - Bound(DebruijnIndex, I::BoundTy), + Bound(BoundVarIndexKind, I::BoundTy), /// A placeholder type, used during higher ranked subtyping to instantiate /// bound variables. diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 3a6d1acfa8d9..4d9fd6040d8b 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -344,7 +344,8 @@ impl TypeVisitor for HasRegionsBoundAt { } fn visit_region(&mut self, r: I::Region) -> Self::Result { - if matches!(r.kind(), ty::ReBound(binder, _) if self.binder == binder) { + if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Bound(binder), _) if self.binder == binder) + { ControlFlow::Break(()) } else { ControlFlow::Continue(()) @@ -531,7 +532,7 @@ impl TypeFolder for FoldEscapingRegions { } fn fold_region(&mut self, r: ::Region) -> ::Region { - if let ty::ReBound(debruijn, _) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() { assert!( debruijn <= self.debruijn, "cannot instantiate binder with escaping bound vars" diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 1b1e77bbea8f..6e9142b22e0e 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -14,7 +14,7 @@ use rustc_hir::{BindingMode, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, No use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, RegionKind, TyCtxt}; +use rustc_middle::ty::{self, BoundVarIndexKind, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -151,7 +151,7 @@ impl PassByRefOrValue { match *ty.skip_binder().kind() { ty::Ref(lt, ty, Mutability::Not) => { match lt.kind() { - RegionKind::ReBound(index, region) + RegionKind::ReBound(BoundVarIndexKind::Bound(index), region) if index.as_u32() == 0 && output_regions.contains(®ion) => { continue; diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index e4bc3b768294..c03469c2b885 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, + self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; @@ -826,7 +826,7 @@ pub fn for_each_top_level_late_bound_region( impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow> TypeVisitor> for V { type Result = ControlFlow; fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result { - if let RegionKind::ReBound(idx, bound) = r.kind() + if let RegionKind::ReBound(BoundVarIndexKind::Bound(idx), bound) = r.kind() && idx.as_u32() == self.index { (self.f)(bound) diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index a18d7e7478fc..a1fe278c6520 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,30 +1,30 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] +| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] | 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] | 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send | 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] +| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] | 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] | 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send | 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] +| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] | 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] | 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr similarity index 85% rename from tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr rename to tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr index 486e5f941655..f3938ff606f4 100644 --- a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr +++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr @@ -1,5 +1,5 @@ -error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:43:45: 43:67}>` - --> $DIR/post-mono-higher-ranked-hang.rs:43:21 +error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:47:45: 47:67}>` + --> $DIR/post-mono-higher-ranked-hang.rs:47:21 | LL | / self.perm_pairs(l, &mut async move |left_pair| { LL | | @@ -8,7 +8,7 @@ LL | | }) | |______________________^ | note: `ToChain::<'env, 'db>::perm_pairs` defined here - --> $DIR/post-mono-higher-ranked-hang.rs:34:5 + --> $DIR/post-mono-higher-ranked-hang.rs:38:5 | LL | / fn perm_pairs<'l>( LL | | &'l self, diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr new file mode 100644 index 000000000000..f3938ff606f4 --- /dev/null +++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr @@ -0,0 +1,21 @@ +error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:47:45: 47:67}>` + --> $DIR/post-mono-higher-ranked-hang.rs:47:21 + | +LL | / self.perm_pairs(l, &mut async move |left_pair| { +LL | | +LL | | self.perm_pairs(r, yield_chain).await +LL | | }) + | |______________________^ + | +note: `ToChain::<'env, 'db>::perm_pairs` defined here + --> $DIR/post-mono-higher-ranked-hang.rs:38:5 + | +LL | / fn perm_pairs<'l>( +LL | | &'l self, +LL | | perm: &'l SymPerm<'db>, +LL | | yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>), +LL | | ) -> Pin + 'l>> { + | |____________________________________________________________^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs index f6ebf787f81b..55d7cc30ec96 100644 --- a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs +++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs @@ -2,6 +2,10 @@ //@ aux-build:block-on.rs //@ edition:2021 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + // Regression test for . extern crate block_on; diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index a26c617dc931..f8f64dcc545b 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr @@ -37,7 +37,7 @@ error: higher-ranked lifetime error LL | v.t(|| {}); | ^^^^^ | - = note: could not prove `for<'a> &'a V: 'b` + = note: could not prove `for<'a> &'a V: '_` error: aborting due to 3 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr index 9e0d7e4b7be0..a04c6d770d73 100644 --- a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr +++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr @@ -4,7 +4,7 @@ error: higher-ranked lifetime error LL | || {}; | ^^^^^ | - = note: could not prove `for<'a> &'a (): 'b` + = note: could not prove `for<'a> &'a (): '_` error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/re-empty-in-error.stderr b/tests/ui/lifetimes/re-empty-in-error.stderr index 554bcb5451fc..b3b6d3d269c9 100644 --- a/tests/ui/lifetimes/re-empty-in-error.stderr +++ b/tests/ui/lifetimes/re-empty-in-error.stderr @@ -4,7 +4,7 @@ error: higher-ranked lifetime error LL | foo(&10); | ^^^^^^^^ | - = note: could not prove `for<'b> &'b (): 'a` + = note: could not prove `for<'b> &'b (): '_` error: aborting due to 1 previous error diff --git a/tests/ui/nll/user-annotations/dump-fn-method.rs b/tests/ui/nll/user-annotations/dump-fn-method.rs index 26714b6ffe3a..ec349e36839a 100644 --- a/tests/ui/nll/user-annotations/dump-fn-method.rs +++ b/tests/ui/nll/user-annotations/dump-fn-method.rs @@ -31,7 +31,7 @@ fn main() { // Here: we only want the `T` to be given, the rest should be variables. // // (`T` refers to the declaration of `Bazoom`) - let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] + let x = <_ as Bazoom>::method::<_>; //~ ERROR [^c_0, u32, ^c_1] x(&22, 44, 66); // Here: all are given and definitely contain no lifetimes, so we @@ -48,7 +48,7 @@ fn main() { // // (`U` refers to the declaration of `Bazoom`) let y = 22_u32; - y.method::(44, 66); //~ ERROR [^0, ^1, u32] + y.method::(44, 66); //~ ERROR [^c_0, ^c_1, u32] // Here: nothing is given, so we don't have any annotation. let y = 22_u32; diff --git a/tests/ui/nll/user-annotations/dump-fn-method.stderr b/tests/ui/nll/user-annotations/dump-fn-method.stderr index 8e847b464e18..f00fb0013dfd 100644 --- a/tests/ui/nll/user-annotations/dump-fn-method.stderr +++ b/tests/ui/nll/user-annotations/dump-fn-method.stderr @@ -4,7 +4,7 @@ error: user args: UserArgs { args: [&'static u32], user_self_ty: None } LL | let x = foo::<&'static u32>; | ^^^^^^^^^^^^^^^^^^^ -error: user args: UserArgs { args: [^0, u32, ^1], user_self_ty: None } +error: user args: UserArgs { args: [^c_0, u32, ^c_1], user_self_ty: None } --> $DIR/dump-fn-method.rs:34:13 | LL | let x = <_ as Bazoom>::method::<_>; @@ -16,7 +16,7 @@ error: user args: UserArgs { args: [u8, &'static u16, u32], user_self_ty: None } LL | let x = >::method::; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user args: UserArgs { args: [^0, ^1, u32], user_self_ty: None } +error: user args: UserArgs { args: [^c_0, ^c_1, u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:51:5 | LL | y.method::(44, 66); From 50398e2e7505779323e5371b1905c4ad56a29097 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Tue, 30 Sep 2025 17:56:18 +0000 Subject: [PATCH 431/537] iter repeat: add tests for new count and last behavior --- library/coretests/tests/iter/sources.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/coretests/tests/iter/sources.rs b/library/coretests/tests/iter/sources.rs index 506febaa056a..5a391cb67751 100644 --- a/library/coretests/tests/iter/sources.rs +++ b/library/coretests/tests/iter/sources.rs @@ -30,6 +30,17 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +#[should_panic = "iterator is infinite"] +fn test_repeat_count() { + repeat(42).count(); +} + +#[test] +fn test_repeat_last() { + assert_eq!(repeat(42).last(), Some(42)); +} + #[test] fn test_repeat_with() { #[derive(PartialEq, Debug)] From 6edf05b740070429e57ec18e5c027167dbb17ab4 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 30 Sep 2025 00:14:03 +0300 Subject: [PATCH 432/537] Add `#[bench]` for librustdoc's syntax highlighter --- src/bootstrap/src/core/builder/mod.rs | 2 +- src/librustdoc/html/highlight/tests.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 006dea4b98d1..fc06db8f80b9 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1145,7 +1145,7 @@ impl<'a> Builder<'a> { test::RunMakeCargo, ), Kind::Miri => describe!(test::Crate), - Kind::Bench => describe!(test::Crate, test::CrateLibrustc), + Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc), Kind::Doc => describe!( doc::UnstableBook, doc::UnstableBookGen, diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 2603e887bead..4d1bee9b3a1b 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,6 +1,7 @@ use expect_test::expect_file; use rustc_data_structures::fx::FxIndexMap; use rustc_span::create_default_session_globals_then; +use test::Bencher; use super::{DecorationInfo, write_code}; @@ -81,3 +82,16 @@ let a = 4;"; expect_file!["fixtures/decorations.html"].assert_eq(&html); }); } + +#[bench] +fn bench_html_highlighting(b: &mut Bencher) { + let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs"); + + create_default_session_globals_then(|| { + b.iter(|| { + let mut out = String::new(); + write_code(&mut out, src, None, None, None); + out + }); + }); +} From cbaec31c10c5eff7342e5273360521911fbf7631 Mon Sep 17 00:00:00 2001 From: Josh Simmons Date: Thu, 26 Jun 2025 21:31:05 +0200 Subject: [PATCH 433/537] Add fast-path for accessing the current thread id Accessing the thread id is often used in profiling and debugging, as well as some approaches for sound single-threaded access to data. Currently the only way to access the thread id is by first obtaining a handle to the current thread. While this is not exactly slow, it does require an atomic inc-ref and dec-ref operation, as well as the injection of `Thread`'s drop code into the caller. This publicly exposes the existing fast-path for accessing the current thread id. --- library/std/src/thread/current.rs | 24 ++++++++++++++++++++++-- library/std/src/thread/mod.rs | 4 +++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs index 7da1621da45c..f00212bfcb61 100644 --- a/library/std/src/thread/current.rs +++ b/library/std/src/thread/current.rs @@ -133,12 +133,32 @@ pub(super) fn set_current(thread: Thread) -> Result<(), Thread> { Ok(()) } -/// Gets the id of the thread that invokes it. +/// Gets the unique identifier of the thread which invokes it. +/// +/// Calling this function may be more efficient than accessing the current +/// thread id through the current thread handle. i.e. `thread::current().id()`. /// /// This function will always succeed, will always return the same value for /// one thread and is guaranteed not to call the global allocator. +/// +/// # Examples +/// +/// ``` +/// #![feature(current_thread_id)] +/// +/// use std::thread; +/// +/// let other_thread = thread::spawn(|| { +/// thread::current_id() +/// }); +/// +/// let other_thread_id = other_thread.join().unwrap(); +/// assert_ne!(thread::current_id(), other_thread_id); +/// ``` #[inline] -pub(crate) fn current_id() -> ThreadId { +#[must_use] +#[unstable(feature = "current_thread_id", issue = "147194")] +pub fn current_id() -> ThreadId { // If accessing the persistent thread ID takes multiple TLS accesses, try // to retrieve it from the current thread handle, which will only take one // TLS access. diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 4d09b2b4e9d2..1768369792ae 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -183,7 +183,9 @@ mod current; #[stable(feature = "rust1", since = "1.0.0")] pub use current::current; -pub(crate) use current::{current_id, current_or_unnamed, current_os_id, drop_current}; +#[unstable(feature = "current_thread_id", issue = "147194")] +pub use current::current_id; +pub(crate) use current::{current_or_unnamed, current_os_id, drop_current}; use current::{set_current, try_with_current}; mod spawnhook; From 2d03ab1486c11f2c5f8a19ae040b94edc090b279 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 30 Sep 2025 17:12:31 +0300 Subject: [PATCH 434/537] Replace `rustc_span::Span` with a stripped down version for librustdoc's highlighter --- src/librustdoc/html/highlight.rs | 3 +- src/librustdoc/html/render/context.rs | 3 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/span_map.rs | 68 ++++++++++++++++++++------ src/librustdoc/html/sources.rs | 7 ++- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index fad15573cde0..1dcb4dcc3ff8 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,15 +12,16 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; +use rustc_span::BytePos; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, DUMMY_SP, Span}; use super::format; use crate::clean::PrimitiveType; use crate::display::Joined as _; use crate::html::escape::EscapeBodyText; use crate::html::macro_expansion::ExpandedCode; +use crate::html::render::span_map::{DUMMY_SP, Span}; use crate::html::render::{Context, LinkFromSrc}; /// This type is needed in case we want to render links on items to allow to go to their definition. diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5f92ab2fada9..4c06d0da4701 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -30,6 +30,7 @@ use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::macro_expansion::ExpandedCode; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; +use crate::html::render::span_map::Span; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; use crate::html::{layout, sources, static_files}; @@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> { /// Correspondence map used to link types used in the source code pages to allow to click on /// links to jump to the type's definition. - pub(crate) span_correspondence_map: FxHashMap, + pub(crate) span_correspondence_map: FxHashMap, pub(crate) expanded_codes: FxHashMap>, /// The [`Cache`] used during rendering. pub(crate) cache: Cache, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 97dcaf57cdfa..d6371e4dbab3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -36,7 +36,7 @@ mod ordered_json; mod print_item; pub(crate) mod sidebar; mod sorted_template; -mod span_map; +pub(crate) mod span_map; mod type_layout; mod write_shared; diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index ef7ce33298d9..bc9417b1bb1d 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -8,11 +8,48 @@ use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; -use rustc_span::{BytePos, ExpnKind, Span}; +use rustc_span::{BytePos, ExpnKind}; use crate::clean::{self, PrimitiveType, rustc_span}; use crate::html::sources; +/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span. +/// +/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we +/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this +/// one, which is much cheaper to construct. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Span { + lo: BytePos, + hi: BytePos, +} + +impl From for Span { + fn from(value: rustc_span::Span) -> Self { + Self { lo: value.lo(), hi: value.hi() } + } +} + +impl Span { + pub(crate) fn lo(self) -> BytePos { + self.lo + } + + pub(crate) fn hi(self) -> BytePos { + self.hi + } + + pub(crate) fn with_lo(self, lo: BytePos) -> Self { + Self { lo, hi: self.hi() } + } + + pub(crate) fn with_hi(self, hi: BytePos) -> Self { + Self { lo: self.lo(), hi } + } +} + +pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) }; + /// This enum allows us to store two different kinds of information: /// /// In case the `span` definition comes from the same crate, we can simply get the `span` and use @@ -96,7 +133,7 @@ impl SpanMapVisitor<'_> { }) .unwrap_or(path.span) }; - self.matches.insert(span, link); + self.matches.insert(span.into(), link); } Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => { let path_span = if only_use_last_segment @@ -106,11 +143,12 @@ impl SpanMapVisitor<'_> { } else { path.span }; - self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span))); + self.matches.insert(path_span.into(), LinkFromSrc::Local(clean::Span::new(span))); } Res::PrimTy(p) => { // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. - self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p))); + self.matches + .insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p))); } Res::Err => {} _ => {} @@ -127,7 +165,7 @@ impl SpanMapVisitor<'_> { if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE { return; } - self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id())); + self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id())); } } @@ -138,7 +176,7 @@ impl SpanMapVisitor<'_> { /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop. /// Finally, we get the information about the macro itself (`span` if "local", `DefId` /// otherwise) and store it inside the span map. - fn handle_macro(&mut self, span: Span) -> bool { + fn handle_macro(&mut self, span: rustc_span::Span) -> bool { if !span.from_expansion() { return false; } @@ -176,7 +214,7 @@ impl SpanMapVisitor<'_> { // The "call_site" includes the whole macro with its "arguments". We only want // the macro name. let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32)); - self.matches.insert(new_span, link_from_src); + self.matches.insert(new_span.into(), link_from_src); true } @@ -233,7 +271,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } - fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) { + fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: rustc_span::Span) { match *qpath { QPath::TypeRelative(qself, path) => { if matches!(path.res, Res::Err) { @@ -249,7 +287,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { self.handle_path(&path, false); } } else { - self.infer_id(path.hir_id, Some(id), path.ident.span); + self.infer_id(path.hir_id, Some(id), path.ident.span.into()); } rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself)); @@ -267,7 +305,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } } - fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. if !span.overlaps(m.spans.inner_span) { @@ -275,8 +313,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { // name only and not all the "mod foo;". if let Node::Item(item) = self.tcx.hir_node(id) { let (ident, _) = item.expect_mod(); - self.matches - .insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span))); + self.matches.insert( + ident.span.into(), + LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)), + ); } } else { // If it's a "mod foo {}", we want to look to its documentation page. @@ -288,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { match expr.kind { ExprKind::MethodCall(segment, ..) => { - self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span) + self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into()) } - ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span), + ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()), _ => { if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9c5518a780e4..c79f63fbc203 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -348,7 +348,12 @@ pub(crate) fn print_src( highlight::write_code( fmt, s, - Some(highlight::HrefContext { context, file_span, root_path, current_href }), + Some(highlight::HrefContext { + context, + file_span: file_span.into(), + root_path, + current_href, + }), Some(decoration_info), Some(line_info), ); From 80e598bb12297c5df04e5b380a4f51aa4dfc5d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 30 Sep 2025 13:29:39 +0200 Subject: [PATCH 435/537] clone region obligations instead of taking in implied bounds hack --- compiler/rustc_infer/src/infer/outlives/obligations.rs | 4 ++++ .../src/traits/query/type_op/implied_outlives_bounds.rs | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index b989d419057b..a640dcb1b4e1 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -170,6 +170,10 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } + pub fn clone_registered_region_obligations(&self) -> Vec> { + self.inner.borrow().region_obligations.clone() + } + pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionAssumption); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 7540cbe3fd1a..e55ffb4d5fdb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -55,6 +55,12 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( span: Span, disable_implied_bounds_hack: bool, ) -> Result>, NoSolution> { + // Inside mir borrowck, each computation starts with an empty list. + assert!( + ocx.infcx.inner.borrow().region_obligations().is_empty(), + "compute_implied_outlives_bounds assumes region obligations are empty before starting" + ); + let normalize_ty = |ty| -> Result<_, NoSolution> { // We must normalize the type so we can compute the right outlives components. // for example, if we have some constrained param type like `T: Trait`, @@ -143,7 +149,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() { for TypeOutlivesConstraint { sup_type, sub_region, .. } in - ocx.infcx.take_registered_region_obligations() + ocx.infcx.clone_registered_region_obligations() { let mut components = smallvec![]; push_outlives_components(ocx.infcx.tcx, sup_type, &mut components); From bdebd479acb692319ace3f88bf874ea365503199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 30 Sep 2025 14:01:05 +0200 Subject: [PATCH 436/537] remove outdated context (inner) infctx --- compiler/rustc_infer/src/infer/mod.rs | 17 ----------------- compiler/rustc_trait_selection/src/regions.rs | 2 ++ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9fc124d3bf8..f3ebfde06ab6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> { /// `$0: 'static`. This will get checked later by regionck. (We /// can't generally check these things right away because we have /// to wait until types are resolved.) - /// - /// These are stored in a map keyed to the id of the innermost - /// enclosing fn body / static initializer expression. This is - /// because the location where the obligation was incurred can be - /// relevant with respect to which sublifetime assumptions are in - /// place. The reason that we store under the fn-id, and not - /// something more fine-grained, is so that it is easier for - /// regionck to be sure that it has found *all* the region - /// obligations (otherwise, it's easy to fail to walk to a - /// particular node-id). - /// - /// Before running `resolve_regions_and_report_errors`, the creator - /// of the inference context is expected to invoke - /// [`InferCtxt::process_registered_region_obligations`] - /// for each body-id in this map, which will process the - /// obligations within. This is expected to be done 'late enough' - /// that all type inference variables have been bound and so forth. region_obligations: Vec>, /// The outlives bounds that we assume must hold about placeholders that diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 2b33b8ac9f86..debc4fda15a5 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -77,6 +77,8 @@ impl<'tcx> InferCtxt<'tcx> { /// /// Prefer this method over `resolve_regions_with_normalize`, unless you are /// doing something specific for normalization. + /// + /// This function assumes that all infer variables are already constrained. fn resolve_regions( &self, body_id: LocalDefId, From c1318053e3ab0578420ba93720dc479e3b526f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 1 Oct 2025 00:10:49 +0200 Subject: [PATCH 437/537] add test for trait-system-refactor-initiative/239 --- .../coroutine/handle_opaques_before_coroutines.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/ui/coroutine/handle_opaques_before_coroutines.rs diff --git a/tests/ui/coroutine/handle_opaques_before_coroutines.rs b/tests/ui/coroutine/handle_opaques_before_coroutines.rs new file mode 100644 index 000000000000..2771c77429ca --- /dev/null +++ b/tests/ui/coroutine/handle_opaques_before_coroutines.rs @@ -0,0 +1,15 @@ +// test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/239 +//@edition: 2024 +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +fn foo<'a>() -> impl Send { + if false { + foo(); + } + async {} +} + +fn main() {} From 422f6bb7420e1f1fe1cd920ed0c6b22f5042ae35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 1 Oct 2025 01:10:24 +0200 Subject: [PATCH 438/537] enable tests on next-solver for rust-lang/trait-system-refactor-initiative/237 --- tests/ui/type/pattern_types/const_generics.rs | 3 +++ .../{transmute.stderr => transmute.current.stderr} | 4 ++-- tests/ui/type/pattern_types/transmute.rs | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) rename tests/ui/type/pattern_types/{transmute.stderr => transmute.current.stderr} (92%) diff --git a/tests/ui/type/pattern_types/const_generics.rs b/tests/ui/type/pattern_types/const_generics.rs index 79d46c010d73..f5eb90e94d4f 100644 --- a/tests/ui/type/pattern_types/const_generics.rs +++ b/tests/ui/type/pattern_types/const_generics.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver #![feature(pattern_types, generic_pattern_types, pattern_type_macro)] #![expect(incomplete_features)] diff --git a/tests/ui/type/pattern_types/transmute.stderr b/tests/ui/type/pattern_types/transmute.current.stderr similarity index 92% rename from tests/ui/type/pattern_types/transmute.stderr rename to tests/ui/type/pattern_types/transmute.current.stderr index 578549b515c1..edec542e5e15 100644 --- a/tests/ui/type/pattern_types/transmute.stderr +++ b/tests/ui/type/pattern_types/transmute.current.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute.rs:20:14 + --> $DIR/transmute.rs:23:14 | LL | unsafe { std::mem::transmute(x) } | ^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | unsafe { std::mem::transmute(x) } = note: target type: `u32` (32 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute.rs:28:14 + --> $DIR/transmute.rs:31:14 | LL | unsafe { std::mem::transmute(x) } | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/type/pattern_types/transmute.rs b/tests/ui/type/pattern_types/transmute.rs index 43dd62a19e70..4e686245f937 100644 --- a/tests/ui/type/pattern_types/transmute.rs +++ b/tests/ui/type/pattern_types/transmute.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver #![feature(pattern_types, pattern_type_macro, generic_pattern_types)] #![expect(incomplete_features)] From ddbaca521edf274b1462fced5b50ee6983fb8d01 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 30 Sep 2025 17:56:12 -0400 Subject: [PATCH 439/537] fix void and empty struct ret --- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index c3485f563916..4a749642265d 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); - builder.store_to_place(call, dest.val); + let fn_ret_ty = builder.cx.val_ty(call); + if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) { + // If we return void or an empty struct, then our caller (due to how we generated it) + // does not expect a return value. As such, we have no pointer (or place) into which + // we could store our value, and would store into an undef, which would cause UB. + // As such, we just ignore the return value in those cases. + builder.store_to_place(call, dest.val); + } } From 28ffbab35382164167a5f101bb0181d7f77bffc2 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 30 Sep 2025 17:56:26 -0400 Subject: [PATCH 440/537] add empty struct ret testcase --- tests/codegen-llvm/autodiff/void_ret.rs | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/codegen-llvm/autodiff/void_ret.rs diff --git a/tests/codegen-llvm/autodiff/void_ret.rs b/tests/codegen-llvm/autodiff/void_ret.rs new file mode 100644 index 000000000000..98c6b98eef4e --- /dev/null +++ b/tests/codegen-llvm/autodiff/void_ret.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C no-prepopulate-passes -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +#![feature(autodiff)] +use std::autodiff::*; + +// Usually we would store the return value of the differentiated function. +// However, if the return type is void or an empty struct, +// we don't need to store anything. Verify this, since it caused a bug. + +// CHECK:; void_ret::main +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal +// CHECK-NOT: store {} undef, ptr undef +// CHECK: ret void + +#[autodiff_reverse(bar, Duplicated, Duplicated)] +pub fn foo(r: &[f64; 10], res: &mut f64) { + let mut output = [0.0; 10]; + output[0] = r[0]; + output[1] = r[1] * r[2]; + output[2] = r[4] * r[5]; + output[3] = r[2] * r[6]; + output[4] = r[1] * r[7]; + output[5] = r[2] * r[8]; + output[6] = r[1] * r[9]; + output[7] = r[5] * r[6]; + output[8] = r[5] * r[7]; + output[9] = r[4] * r[8]; + *res = output.iter().sum(); +} +fn main() { + let inputs = Box::new([3.1; 10]); + let mut d_inputs = Box::new([0.0; 10]); + let mut res = Box::new(0.0); + let mut d_res = Box::new(1.0); + + bar(&inputs, &mut d_inputs, &mut res, &mut d_res); + dbg!(&d_inputs); +} From de189fa982ad8830c326fac443ab830728567aff Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 28 Sep 2025 19:45:12 -0400 Subject: [PATCH 441/537] updating tests to not break from new typetree metadata --- tests/codegen-llvm/autodiff/abi_handling.rs | 4 ++-- tests/codegen-llvm/autodiff/batched.rs | 2 +- tests/codegen-llvm/autodiff/scalar.rs | 2 +- tests/codegen-llvm/autodiff/sret.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/codegen-llvm/autodiff/abi_handling.rs b/tests/codegen-llvm/autodiff/abi_handling.rs index 454ec698b917..5c8126898a8d 100644 --- a/tests/codegen-llvm/autodiff/abi_handling.rs +++ b/tests/codegen-llvm/autodiff/abi_handling.rs @@ -1,7 +1,7 @@ //@ revisions: debug release -//@[debug] compile-flags: -Zautodiff=Enable -C opt-level=0 -Clto=fat -//@[release] compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@[debug] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat +//@[release] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs index 306a6ed9d1f4..dc82403212fb 100644 --- a/tests/codegen-llvm/autodiff/batched.rs +++ b/tests/codegen-llvm/autodiff/batched.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme // diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs index 55b989f920da..53672a89230a 100644 --- a/tests/codegen-llvm/autodiff/scalar.rs +++ b/tests/codegen-llvm/autodiff/scalar.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme #![feature(autodiff)] diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs index dbc253ce8943..498cd3fea012 100644 --- a/tests/codegen-llvm/autodiff/sret.rs +++ b/tests/codegen-llvm/autodiff/sret.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme From ec893d1a646bc0a1e09511ca80d71141da3b6997 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 1 Oct 2025 13:31:42 +0800 Subject: [PATCH 442/537] tests: remove `no-remap-src-base` Previously in the `//`-compiletest-directive times, this was implemented as a special `no-*` directive parsing. In the migration from `//` -> `//@`, the `// no-remap-src-base` directive was lost, most likely because it had no effect -- the default is not remapping `src-base`. So remove occurrences of `no-remap-src-base`, as these are not valid directives. --- tests/ui-fulldeps/mod_dir_path_canonicalized.rs | 1 - tests/ui/errors/auxiliary/remapped_dep.rs | 2 +- tests/ui/errors/remap-path-prefix-reverse.local-self.stderr | 2 +- tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr | 2 +- tests/ui/errors/remap-path-prefix-reverse.rs | 1 - tests/ui/errors/remap-path-prefix.rs | 2 +- tests/ui/proc-macro/expand-expr.rs | 2 +- tests/ui/proc-macro/pretty-print-hack-show.rs | 1 - 8 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index df5f29e35fe6..86f2d5f5954a 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -2,7 +2,6 @@ // Testing that a librustc_ast can parse modules with canonicalized base path //@ ignore-cross-compile //@ ignore-remote -// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled. #![feature(rustc_private)] diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs index 36d4699a3060..997118f822c3 100644 --- a/tests/ui/errors/auxiliary/remapped_dep.rs +++ b/tests/ui/errors/auxiliary/remapped_dep.rs @@ -1,4 +1,4 @@ //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux -// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. +// Manually remap, so the remapped path remains in .stderr file. pub struct SomeStruct {} // This line should be show as part of the error. diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr index b4f83f6bfc0a..b2651f3e03a6 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> $DIR/remap-path-prefix-reverse.rs:16:13 + --> $DIR/remap-path-prefix-reverse.rs:15:13 | LL | let _ = remapped_dep::SomeStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr index b4f83f6bfc0a..b2651f3e03a6 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> $DIR/remap-path-prefix-reverse.rs:16:13 + --> $DIR/remap-path-prefix-reverse.rs:15:13 | LL | let _ = remapped_dep::SomeStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs index 28fdabb8f4df..562e44690f76 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.rs +++ b/tests/ui/errors/remap-path-prefix-reverse.rs @@ -2,7 +2,6 @@ //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux //@ revisions: local-self remapped-self -// [local-self] no-remap-src-base: The hack should work regardless of remapping. //@ [remapped-self] remap-src-base // Verify that the expected source code is shown. diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs index 7e38e16280f5..de18aa8cc204 100644 --- a/tests/ui/errors/remap-path-prefix.rs +++ b/tests/ui/errors/remap-path-prefix.rs @@ -2,7 +2,7 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped //@ [with-diagnostic-scope]compile-flags: -Zremap-path-scope=diagnostics //@ [without-diagnostic-scope]compile-flags: -Zremap-path-scope=object -// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. +// Manually remap, so the remapped path remains in .stderr file. // The remapped paths are not normalized by compiletest. //@ normalize-stderr: "\\(errors)" -> "/$1" diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 1e058abe3bc1..c3dddd8e4594 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -1,6 +1,6 @@ //@ proc-macro: expand-expr.rs //@ ignore-backends: gcc -// no-remap-src-base: check_expand_expr_file!() fails when enabled. +// No `remap-src-base`, since `check_expand_expr_file!()` fails when enabled. #![feature(concat_bytes)] extern crate expand_expr; diff --git a/tests/ui/proc-macro/pretty-print-hack-show.rs b/tests/ui/proc-macro/pretty-print-hack-show.rs index 70f0d5f6ea97..08e26c811427 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.rs +++ b/tests/ui/proc-macro/pretty-print-hack-show.rs @@ -1,7 +1,6 @@ //@ proc-macro: test-macros.rs //@ compile-flags: -Z span-debug //@ revisions: local remapped -// [local] no-remap-src-base: The hack should work regardless of remapping. //@ [remapped] remap-src-base #![no_std] // Don't load unnecessary hygiene information from std From 3186902bfca12d492ebbac70e2a41b15f0fb2b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 1 Oct 2025 09:05:30 +0200 Subject: [PATCH 443/537] Remove mention of `compiletest-use-stage0-libtest` from the bootstrap example config --- bootstrap.example.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 0a39c6d8f247..f623a3db0029 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -476,9 +476,6 @@ # when the stage 0 compiler is actually built from in-tree sources. #build.compiletest-allow-stage0 = false -# Whether to use the precompiled stage0 libtest with compiletest. -#build.compiletest-use-stage0-libtest = true - # Default value for the `--extra-checks` flag of tidy. # # See `./x test tidy --help` for details. From 86f2d424c8cda473aa1bf91365f499cfe520c54a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 15 Sep 2025 11:35:08 +0000 Subject: [PATCH 444/537] indexing: reword help Co-authored-by: beef --- .../src/error_codes/E0608.md | 15 ++++++++--- compiler/rustc_hir_typeck/src/expr.rs | 27 +++++-------------- tests/ui/indexing/index_message.stderr | 4 ++- tests/ui/issues/issue-27842.stderr | 12 ++++----- tests/ui/span/suggestion-non-ascii.stderr | 4 ++- ...for-indexing-expression-issue-40861.stderr | 2 +- 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md index d0ebc3a26f08..3c29484f575c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0608.md +++ b/compiler/rustc_error_codes/src/error_codes/E0608.md @@ -1,5 +1,5 @@ -An attempt to use index on a type which doesn't implement the `std::ops::Index` -trait was performed. +Attempted to index a value whose type doesn't implement the +`std::ops::Index` trait. Erroneous code example: @@ -7,8 +7,8 @@ Erroneous code example: 0u8[2]; // error: cannot index into a value of type `u8` ``` -To be able to index into a type it needs to implement the `std::ops::Index` -trait. Example: +Only values with types that implement the `std::ops::Index` trait +can be indexed with square brackets. Example: ``` let v: Vec = vec![0, 1, 2, 3]; @@ -16,3 +16,10 @@ let v: Vec = vec![0, 1, 2, 3]; // The `Vec` type implements the `Index` trait so you can do: println!("{}", v[2]); ``` + +Tuples and structs are indexed with dot (`.`), not with brackets (`[]`), +and tuple element names are their positions: +```ignore(pseudo code) +// this (pseudo code) expression is true for any tuple: +tuple == (tuple.0, tuple.1, ...) +``` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d1ce0afddf91..f9cdc923670f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3551,35 +3551,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Try to give some advice about indexing tuples. if let ty::Tuple(types) = base_t.kind() { - let mut needs_note = true; - // If the index is an integer, we can show the actual - // fixed expression: + err.help( + "tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.", + ); + // If index is an unsuffixed integer, show the fixed expression: if let ExprKind::Lit(lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node - && i.get() - < types - .len() - .try_into() - .expect("expected tuple index to be < usize length") + && i.get() < types.len().try_into().expect("tuple length fits in u128") { err.span_suggestion( brackets_span, - "to access tuple elements, use", + format!("to access tuple element `{i}`, use"), format!(".{i}"), Applicability::MachineApplicable, ); - needs_note = false; - } else if let ExprKind::Path(..) = idx.peel_borrows().kind { - err.span_label( - idx.span, - "cannot access tuple elements at a variable index", - ); - } - if needs_note { - err.help( - "to access tuple elements, use tuple indexing \ - syntax (e.g., `tuple.0`)", - ); } } diff --git a/tests/ui/indexing/index_message.stderr b/tests/ui/indexing/index_message.stderr index 6affb1ed9625..b6f61379f2af 100644 --- a/tests/ui/indexing/index_message.stderr +++ b/tests/ui/indexing/index_message.stderr @@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/index_message.rs:3:14 | LL | let _ = z[0]; - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr index b18fe1512b50..f388fdf85cde 100644 --- a/tests/ui/issues/issue-27842.stderr +++ b/tests/ui/issues/issue-27842.stderr @@ -2,17 +2,17 @@ error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer --> $DIR/issue-27842.rs:4:16 | LL | let _ = tup[0]; - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})` --> $DIR/issue-27842.rs:9:16 | LL | let _ = tup[i]; - | ^-^ - | | - | cannot access tuple elements at a variable index + | ^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/issue-27842.rs:14:16 @@ -20,7 +20,7 @@ error[E0608]: cannot index into a value of type `({integer},)` LL | let _ = tup[3]; | ^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 3 previous errors diff --git a/tests/ui/span/suggestion-non-ascii.stderr b/tests/ui/span/suggestion-non-ascii.stderr index 6e6e31a5698b..361f744ee8eb 100644 --- a/tests/ui/span/suggestion-non-ascii.stderr +++ b/tests/ui/span/suggestion-non-ascii.stderr @@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:3:24 | LL | println!("☃{}", tup[0]); - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error diff --git a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr index 13bc0cd94f37..ef5f1786801a 100644 --- a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr +++ b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr @@ -4,7 +4,7 @@ error[E0608]: cannot index into a value of type `()` LL | ()[f(&[1.0])]; | ^^^^^^^^^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error From b1c212f8502e8e7fcb66da0e8da98db770cb7c02 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Wed, 1 Oct 2025 08:12:44 +0000 Subject: [PATCH 445/537] Fix broken STD build for ESP-IDF --- library/std/src/sys/net/hostname/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs index a4b5b76059d3..8ffe4894d718 100644 --- a/library/std/src/sys/net/hostname/mod.rs +++ b/library/std/src/sys/net/hostname/mod.rs @@ -1,5 +1,5 @@ cfg_select! { - target_family = "unix" => { + all(target_family = "unix", not(target_os = "espidf")) => { mod unix; pub use unix::hostname; } From e6429c74548aa2a5e20b78dca51c5f74ad59dea8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 Oct 2025 21:05:28 +1000 Subject: [PATCH 446/537] Don't create a top-level `true` directory when running UI tests --- .../cmse-nonsecure-call/undeclared-lifetime.rs | 5 +++-- .../cmse-nonsecure-call/undeclared-lifetime.stderr | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs index 5fa5b74c0c0b..0a0dca804ef3 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs @@ -1,5 +1,6 @@ //@ add-core-stubs -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Cincremental=true +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ incremental (required to trigger the bug) //@ needs-llvm-components: arm #![feature(abi_cmse_nonsecure_call, no_core)] #![no_core] @@ -8,7 +9,7 @@ extern crate minicore; use minicore::*; // A regression test for https://github.com/rust-lang/rust/issues/131639. -// NOTE: -Cincremental=true was required for triggering the bug. +// NOTE: `-Cincremental` was required for triggering the bug. fn foo() { id::(PhantomData); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr index 4aca17e73544..7300bdb72cdd 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/undeclared-lifetime.rs:14:43 + --> $DIR/undeclared-lifetime.rs:15:43 | LL | id::(PhantomData); | ^^ undeclared lifetime From b810a68197515bfbe5afd8557b566d6817035389 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Wed, 1 Oct 2025 11:53:47 +0000 Subject: [PATCH 447/537] added error for closures case in impl --- .../src/coherence/inherent_impls.rs | 9 ++++----- .../rustc_hir_analysis/src/coherence/orphan.rs | 10 ++++++---- tests/ui/closures/impl-closure-147146.rs | 7 +++++++ tests/ui/closures/impl-closure-147146.stderr | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 tests/ui/closures/impl-closure-147146.rs create mode 100644 tests/ui/closures/impl-closure-147146.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 38ae7852ca99..b069a74bf5ad 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -195,11 +195,10 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Alias(ty::Free, _) - | ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(_) => { + | ty::CoroutineWitness(..) => { + Err(self.tcx.dcx().delayed_bug("cannot define inherent `impl` for closure types")) + } + ty::Alias(ty::Free, _) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); } // We could bail out here, but that will silence other useful errors. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 621431ae2343..5a61248cab8f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -230,10 +230,12 @@ pub(crate) fn orphan_check_impl( ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) => { + | ty::CoroutineWitness(..) => { + return Err(tcx + .dcx() + .delayed_bug("cannot define inherent `impl` for closure types")); + } + ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { let sp = tcx.def_span(impl_def_id); span_bug!(sp, "weird self type for autotrait impl") } diff --git a/tests/ui/closures/impl-closure-147146.rs b/tests/ui/closures/impl-closure-147146.rs new file mode 100644 index 000000000000..b709e577354e --- /dev/null +++ b/tests/ui/closures/impl-closure-147146.rs @@ -0,0 +1,7 @@ +impl typeof(|| {}) {} +//~^ ERROR `typeof` is a reserved keyword but unimplemented + +unsafe impl Send for typeof(|| {}) {} +//~^ ERROR `typeof` is a reserved keyword but unimplemented + +fn main() {} diff --git a/tests/ui/closures/impl-closure-147146.stderr b/tests/ui/closures/impl-closure-147146.stderr new file mode 100644 index 000000000000..6da16b5d450f --- /dev/null +++ b/tests/ui/closures/impl-closure-147146.stderr @@ -0,0 +1,15 @@ +error[E0516]: `typeof` is a reserved keyword but unimplemented + --> $DIR/impl-closure-147146.rs:1:6 + | +LL | impl typeof(|| {}) {} + | ^^^^^^^^^^^^^ reserved keyword + +error[E0516]: `typeof` is a reserved keyword but unimplemented + --> $DIR/impl-closure-147146.rs:4:22 + | +LL | unsafe impl Send for typeof(|| {}) {} + | ^^^^^^^^^^^^^ reserved keyword + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0516`. From 5ade7647b7ec9080aa91e174f4b12a1eac8e9bd5 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Sep 2025 17:47:40 -0500 Subject: [PATCH 448/537] Change ArrayWindows to use a slice --- library/core/src/slice/iter.rs | 69 +++++++++++----------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index ae910e052520..7053ae86e732 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2203,16 +2203,13 @@ unsafe impl Sync for ChunksExactMut<'_, T> where T: Sync {} #[unstable(feature = "array_windows", issue = "75027")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ArrayWindows<'a, T: 'a, const N: usize> { - slice_head: *const T, - num: usize, - marker: PhantomData<&'a [T; N]>, + v: &'a [T], } impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { #[inline] pub(super) const fn new(slice: &'a [T]) -> Self { - let num_windows = slice.len().saturating_sub(N - 1); - Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData } + Self { v: slice } } } @@ -2222,49 +2219,34 @@ impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { #[inline] fn next(&mut self) -> Option { - if self.num == 0 { - return None; + let ret = self.v.first_chunk(); + if ret.is_some() { + self.v = &self.v[1..]; } - // SAFETY: - // This is safe because it's indexing into a slice guaranteed to be length > N. - let ret = unsafe { &*self.slice_head.cast::<[T; N]>() }; - // SAFETY: Guaranteed that there are at least 1 item remaining otherwise - // earlier branch would've been hit - self.slice_head = unsafe { self.slice_head.add(1) }; - - self.num -= 1; - Some(ret) + ret } #[inline] fn size_hint(&self) -> (usize, Option) { - (self.num, Some(self.num)) + let size = self.v.len().saturating_sub(N - 1); + (size, Some(size)) } #[inline] fn count(self) -> usize { - self.num + self.len() } #[inline] fn nth(&mut self, n: usize) -> Option { - if self.num <= n { - self.num = 0; - return None; - } - // SAFETY: - // This is safe because it's indexing into a slice guaranteed to be length > N. - let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() }; - // SAFETY: Guaranteed that there are at least n items remaining - self.slice_head = unsafe { self.slice_head.add(n + 1) }; - - self.num -= n + 1; - Some(ret) + let idx = n.min(self.v.len()); + self.v = &self.v[idx..]; + self.next() } #[inline] - fn last(mut self) -> Option { - self.nth(self.num.checked_sub(1)?) + fn last(self) -> Option { + self.v.last_chunk() } } @@ -2272,32 +2254,25 @@ impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { #[inline] fn next_back(&mut self) -> Option<&'a [T; N]> { - if self.num == 0 { - return None; + let ret = self.v.last_chunk(); + if ret.is_some() { + self.v = &self.v[..self.v.len() - 1]; } - // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. - let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() }; - self.num -= 1; - Some(ret) + ret } #[inline] fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> { - if self.num <= n { - self.num = 0; - return None; - } - // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. - let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() }; - self.num -= n + 1; - Some(ret) + let idx = self.v.len().saturating_sub(n); + self.v = &self.v[..idx]; + self.next_back() } } #[unstable(feature = "array_windows", issue = "75027")] impl ExactSizeIterator for ArrayWindows<'_, T, N> { fn is_empty(&self) -> bool { - self.num == 0 + self.v.len() < N } } From 5b809b355c5c134e6848f800a2f8e692a3c10d44 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 1 Oct 2025 14:47:42 +0200 Subject: [PATCH 449/537] Don't enable shared memory with Wasm atomics --- compiler/rustc_codegen_ssa/src/back/linker.rs | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e644a43f8834..ac1231437382 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -17,7 +17,6 @@ use rustc_middle::middle::exported_symbols::{ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_span::sym; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; @@ -1324,37 +1323,7 @@ struct WasmLd<'a> { impl<'a> WasmLd<'a> { fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { - // If the atomics feature is enabled for wasm then we need a whole bunch - // of flags: - // - // * `--shared-memory` - the link won't even succeed without this, flags - // the one linear memory as `shared` - // - // * `--max-memory=1G` - when specifying a shared memory this must also - // be specified. We conservatively choose 1GB but users should be able - // to override this with `-C link-arg`. - // - // * `--import-memory` - it doesn't make much sense for memory to be - // exported in a threaded module because typically you're - // sharing memory and instantiating the module multiple times. As a - // result if it were exported then we'd just have no sharing. - // - // On wasm32-unknown-unknown, we also export symbols for glue code to use: - // * `--export=*tls*` - when `#[thread_local]` symbols are used these - // symbols are how the TLS segments are initialized and configured. - let mut wasm_ld = WasmLd { cmd, sess }; - if sess.target_features.contains(&sym::atomics) { - wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" || sess.target.os == "none" { - wasm_ld.link_args(&[ - "--export=__wasm_init_tls", - "--export=__tls_size", - "--export=__tls_align", - "--export=__tls_base", - ]); - } - } - wasm_ld + WasmLd { cmd, sess } } } From 96fb1b3b559ccc8ed051c95fa5385f9ba4030a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 1 Oct 2025 16:11:21 +0200 Subject: [PATCH 450/537] include outer_inclusive_binder of pattern types --- compiler/rustc_type_ir/src/flags.rs | 1 + .../type/pattern_types/transmute.next.stderr | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/ui/type/pattern_types/transmute.next.stderr diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 24704c5bb535..ea3903d401e3 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -347,6 +347,7 @@ impl FlagComputation { fn add_ty_pat(&mut self, pat: ::Pat) { self.add_flags(pat.flags()); + self.add_exclusive_binder(pat.outer_exclusive_binder()); } fn add_predicate(&mut self, binder: ty::Binder>) { diff --git a/tests/ui/type/pattern_types/transmute.next.stderr b/tests/ui/type/pattern_types/transmute.next.stderr new file mode 100644 index 000000000000..edec542e5e15 --- /dev/null +++ b/tests/ui/type/pattern_types/transmute.next.stderr @@ -0,0 +1,21 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute.rs:23:14 + | +LL | unsafe { std::mem::transmute(x) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32) + = note: target type: `u32` (32 bits) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute.rs:31:14 + | +LL | unsafe { std::mem::transmute(x) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32) + = note: target type: `Option` (64 bits) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0512`. From 0435b16f3b8d4b6139993a60528658416aa36d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 1 Oct 2025 00:20:47 +0200 Subject: [PATCH 451/537] swap order of resolve_coroutine_interiors and handle_opaque_type_uses --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 18 ++++++------------ compiler/rustc_hir_typeck/src/lib.rs | 9 +++------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 833ce433d56f..35253e4c2919 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -611,19 +611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { typeck_results.rvalue_scopes = rvalue_scopes; } - /// Unify the inference variables corresponding to coroutine witnesses, and save all the - /// predicates that were stalled on those inference variables. - /// - /// This process allows to conservatively save all predicates that do depend on the coroutine - /// interior types, for later processing by `check_coroutine_obligations`. - /// - /// We must not attempt to select obligations after this method has run, or risk query cycle - /// ICE. + /// Drain all obligations that are stalled on coroutines defined in this body. #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_coroutine_interiors(&self) { - // Try selecting all obligations that are not blocked on inference variables. - // Once we start unifying coroutine witnesses, trying to select obligations on them will - // trigger query cycle ICEs, as doing so requires MIR. + pub(crate) fn drain_stalled_coroutine_obligations(&self) { + // Make as much inference progress as possible before + // draining the stalled coroutine obligations as this may + // change obligations from being stalled on infer vars to + // being stalled on a coroutine. self.select_obligations_where_possible(|_| {}); let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index acc0481e457f..9f5a85b69264 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -243,18 +243,15 @@ fn typeck_with_inspect<'tcx>( debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); - // This must be the last thing before `report_ambiguity_errors`. - fcx.resolve_coroutine_interiors(); - - debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); - // We need to handle opaque types before emitting ambiguity errors as applying // defining uses may guide type inference. if fcx.next_trait_solver() { fcx.handle_opaque_type_uses_next(); } - fcx.select_obligations_where_possible(|_| {}); + // This must be the last thing before `report_ambiguity_errors` below except `select_obligations_where_possible`. + // So don't put anything after this. + fcx.drain_stalled_coroutine_obligations(); if fcx.infcx.tainted_by_errors().is_none() { fcx.report_ambiguity_errors(); } From 84864bcf89592a1c85b6646d600ca111291fbc66 Mon Sep 17 00:00:00 2001 From: Brian Caswell Date: Wed, 1 Oct 2025 11:07:42 -0400 Subject: [PATCH 452/537] Fix typo in 'unfulfilled_lint_expectation' to plural --- src/doc/rustc/src/lints/levels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 5b002b435a51..09b55da741d6 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -38,7 +38,7 @@ talk about later in this section. Sometimes, it can be helpful to suppress lints, but at the same time ensure that the code in question still emits them. The 'expect' level does exactly this. If -the lint in question is not emitted, the `unfulfilled_lint_expectation` lint +the lint in question is not emitted, the `unfulfilled_lint_expectations` lint triggers on the `expect` attribute, notifying you that the expectation is no longer fulfilled. From 8dfea22c974fe18aca8322f1c73f8455dc42c66f Mon Sep 17 00:00:00 2001 From: edwloef Date: Wed, 1 Oct 2025 16:03:46 +0200 Subject: [PATCH 453/537] implement `Box::take` --- library/alloc/src/boxed.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5a63d90b95fa..49ff768bed1b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -619,6 +619,37 @@ impl Box { pub fn into_inner(boxed: Self) -> T { *boxed } + + /// Consumes the `Box` without consuming its allocation, returning the wrapped value and a `Box` + /// to the uninitialized memory where the wrapped value used to live. + /// + /// This can be used together with [`write`](Box::write) to reuse the allocation for multiple + /// boxed values. + /// + /// # Examples + /// + /// ``` + /// #![feature(box_take)] + /// + /// let c = Box::new(5); + /// + /// // take the value out of the box + /// let (value, uninit) = Box::take(c); + /// assert_eq!(value, 5); + /// + /// // reuse the box for a second value + /// let c = Box::write(uninit, 6); + /// assert_eq!(*c, 6); + /// ``` + #[unstable(feature = "box_take", issue = "147212")] + pub fn take(boxed: Self) -> (T, Box, A>) { + unsafe { + let (raw, alloc) = Box::into_raw_with_allocator(boxed); + let value = raw.read(); + let uninit = Box::from_raw_in(raw.cast::>(), alloc); + (value, uninit) + } + } } impl Box<[T]> { From 69619535d9dbad6a7f5e622bfd3e3c3fb190e0aa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 1 Oct 2025 17:36:53 +0200 Subject: [PATCH 454/537] Switch `citool` to 2024 edition --- src/ci/citool/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index f61243a4d712..078b877e44b1 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "citool" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] anyhow = "1" From 4baf9208a129e5ea8b3973ce2eeb55fdd7404aea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 1 Oct 2025 17:38:36 +0200 Subject: [PATCH 455/537] Initialize llvm submodule if not already the case to run citool --- src/ci/citool/src/main.rs | 4 +++- src/ci/citool/src/utils.rs | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index fe1b36673a1b..255d39846da1 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -24,7 +24,7 @@ use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::test_dashboard::generate_test_dashboard; -use crate::utils::{load_env_var, output_details}; +use crate::utils::{init_submodule_if_needed, load_env_var, output_details}; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); pub const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); @@ -121,6 +121,8 @@ fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> any (key.clone(), value) })); + init_submodule_if_needed("src/llvm-project/")?; + let mut cmd = Command::new(Path::new(DOCKER_DIRECTORY).join("run.sh")); cmd.arg(job.image()); cmd.envs(custom_env); diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index 3176cb62f606..43b220255dc7 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use std::convert::AsRef; use std::path::Path; +use std::process::Command; use anyhow::Context; @@ -34,3 +36,19 @@ where pub fn normalize_path_delimiters(name: &str) -> Cow<'_, str> { if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() } } + +pub fn init_submodule_if_needed>(path_to_submodule: P) -> anyhow::Result<()> { + let path_to_submodule = path_to_submodule.as_ref(); + + if let Ok(mut iter) = path_to_submodule.read_dir() + && iter.any(|entry| entry.is_ok()) + { + // Seems like the submodule is already initialized, nothing to be done here. + return Ok(()); + } + let mut child = Command::new("git") + .args(&["submodule", "update", "--init"]) + .arg(path_to_submodule) + .spawn()?; + if !child.wait()?.success() { Err(anyhow::anyhow!("git command failed")) } else { Ok(()) } +} From 3e8ce2bda9e9563c546287b4715fcde61d008d3e Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 1 Oct 2025 17:43:53 +0200 Subject: [PATCH 456/537] Adjust WASI and WALI targets --- .../src/spec/targets/wasm32_wali_linux_musl.rs | 13 ++++++++++--- .../src/spec/targets/wasm32_wasip1_threads.rs | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs index a0eb4a254fc0..06e5cfaed92d 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs @@ -6,11 +6,18 @@ use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut options = base::linux_wasm::opts(); - options - .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]); + options.add_pre_link_args( + LinkerFlavor::WasmLld(Cc::No), + &["--export-memory", "--shared-memory", "--max-memory=1073741824"], + ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), - &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"], + &[ + "--target=wasm32-wasi-threads", + "-Wl,--export-memory,", + "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", + ], ); Target { diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 44d906a507de..c735c72cb1cb 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::No), - &["--import-memory", "--export-memory", "--shared-memory"], + &["--import-memory", "--export-memory", "--shared-memory", "--max-memory=1073741824"], ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), @@ -28,6 +28,7 @@ pub(crate) fn target() -> Target { "-Wl,--import-memory", "-Wl,--export-memory,", "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", ], ); From a7eed086b913d708c9f38ce9c833e403f00fc15d Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 30 Sep 2025 19:45:26 +0200 Subject: [PATCH 457/537] Add the check-pass and check-fail tests. --- .../same-res-ambigious-extern-fail.rs | 16 +++++++++++++++ .../same-res-ambigious-extern-macro.rs | 8 ++++++++ .../auxiliary/same-res-ambigious-extern.rs | 11 ++++++++++ .../ui/imports/same-res-ambigious.fail.stderr | 20 +++++++++++++++++++ .../same-res-ambigious.nightly-fail.stderr | 20 +++++++++++++++++++ tests/ui/imports/same-res-ambigious.rs | 11 ++++++++++ 6 files changed, 86 insertions(+) create mode 100644 tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs create mode 100644 tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs create mode 100644 tests/ui/imports/auxiliary/same-res-ambigious-extern.rs create mode 100644 tests/ui/imports/same-res-ambigious.fail.stderr create mode 100644 tests/ui/imports/same-res-ambigious.nightly-fail.stderr create mode 100644 tests/ui/imports/same-res-ambigious.rs diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs new file mode 100644 index 000000000000..61a8d8f0054a --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs @@ -0,0 +1,16 @@ +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +macro_rules! globbing{ + () => { + pub use same_res_ambigious_extern_macro::*; + } +} + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +globbing! {} // this imports the same `RustEmbed` macro with `pub` visibility + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs new file mode 100644 index 000000000000..4e9b8427092f --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs @@ -0,0 +1,8 @@ +//@ edition: 2018 +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(RustEmbed)] +pub fn rust_embed_derive(_input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs new file mode 100644 index 000000000000..5269dcd0b17a --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs @@ -0,0 +1,11 @@ +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +// this imports the same `RustEmbed` macro with `pub` visibility +pub use same_res_ambigious_extern_macro::*; + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; diff --git a/tests/ui/imports/same-res-ambigious.fail.stderr b/tests/ui/imports/same-res-ambigious.fail.stderr new file mode 100644 index 000000000000..dfd7c5a5f94e --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.fail.stderr @@ -0,0 +1,20 @@ +error[E0603]: derive macro `Embed` is private + --> $DIR/same-res-ambigious.rs:8:28 + | +LL | #[derive(ambigious_extern::Embed)] + | ^^^^^ private derive macro + | +note: the derive macro `Embed` is defined here + --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ +help: import `Embed` directly + | +LL - #[derive(ambigious_extern::Embed)] +LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/same-res-ambigious.nightly-fail.stderr b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr new file mode 100644 index 000000000000..dfd7c5a5f94e --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr @@ -0,0 +1,20 @@ +error[E0603]: derive macro `Embed` is private + --> $DIR/same-res-ambigious.rs:8:28 + | +LL | #[derive(ambigious_extern::Embed)] + | ^^^^^ private derive macro + | +note: the derive macro `Embed` is defined here + --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ +help: import `Embed` directly + | +LL - #[derive(ambigious_extern::Embed)] +LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/same-res-ambigious.rs b/tests/ui/imports/same-res-ambigious.rs new file mode 100644 index 000000000000..b5c13a15b7c9 --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.rs @@ -0,0 +1,11 @@ +//@ edition: 2018 +//@ revisions: fail pass +//@[pass] check-pass +//@[pass] aux-crate: ambigious_extern=same-res-ambigious-extern.rs +//@[fail] aux-crate: ambigious_extern=same-res-ambigious-extern-fail.rs +// see https://github.com/rust-lang/rust/pull/147196 + +#[derive(ambigious_extern::Embed)] //[fail]~ ERROR: derive macro `Embed` is private +struct Foo{} + +fn main(){} From 94f00f4e4a0240bc7b8284c78482e37af252309a Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 1 Oct 2025 11:32:54 -0400 Subject: [PATCH 458/537] Fix memory leak in `os` impl --- library/std/src/sys/thread_local/os.rs | 103 ++++++++++++------ .../miri/tests/pass/thread_local-panic.rs | 8 ++ .../miri/tests/pass/thread_local-panic.stderr | 5 + 3 files changed, 85 insertions(+), 31 deletions(-) create mode 100644 src/tools/miri/tests/pass/thread_local-panic.rs create mode 100644 src/tools/miri/tests/pass/thread_local-panic.stderr diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index b488f12fe841..88bb5ae7c650 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -1,9 +1,12 @@ use super::key::{Key, LazyKey, get, set}; use super::{abort_on_dtor_unwind, guard}; -use crate::alloc::Layout; +use crate::alloc::{self, Layout}; use crate::cell::Cell; use crate::marker::PhantomData; -use crate::ptr; +use crate::mem::ManuallyDrop; +use crate::ops::Deref; +use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; +use crate::ptr::{self, NonNull}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] @@ -110,6 +113,60 @@ pub const fn value_align() -> usize { crate::mem::align_of::>() } +/// Equivalent to `Box>`, but potentially over-aligned. +struct AlignedBox { + ptr: NonNull>, +} + +impl AlignedBox { + #[inline] + fn new(v: Value) -> Self { + let layout = Layout::new::>().align_to(ALIGN).unwrap(); + + let ptr: *mut Value = (unsafe { alloc::alloc(layout) }).cast(); + let Some(ptr) = NonNull::new(ptr) else { + alloc::handle_alloc_error(layout); + }; + unsafe { ptr.write(v) }; + Self { ptr } + } + + #[inline] + fn into_raw(b: Self) -> *mut Value { + let md = ManuallyDrop::new(b); + md.ptr.as_ptr() + } + + #[inline] + unsafe fn from_raw(ptr: *mut Value) -> Self { + Self { ptr: unsafe { NonNull::new_unchecked(ptr) } } + } +} + +impl Deref for AlignedBox { + type Target = Value; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self.ptr.as_ptr()) } + } +} + +impl Drop for AlignedBox { + #[inline] + fn drop(&mut self) { + let layout = Layout::new::>().align_to(ALIGN).unwrap(); + + unsafe { + let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place())); + alloc::dealloc(self.ptr.as_ptr().cast(), layout); + if let Err(payload) = unwind_result { + resume_unwind(payload); + } + } + } +} + impl Storage { pub const fn new() -> Storage { Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } @@ -148,15 +205,11 @@ impl Storage { return ptr::null(); } - // Manually allocate with the requested alignment - let layout = Layout::new::>().align_to(ALIGN).unwrap(); - let ptr: *mut Value = (unsafe { crate::alloc::alloc(layout) }).cast(); - if ptr.is_null() { - crate::alloc::handle_alloc_error(layout); - } - unsafe { - ptr.write(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }); - } + let value = AlignedBox::::new(Value { + value: i.and_then(Option::take).unwrap_or_else(f), + key, + }); + let ptr = AlignedBox::into_raw(value); // SAFETY: // * key came from a `LazyKey` and is thus correct. @@ -174,10 +227,7 @@ impl Storage { // initializer has already returned and the next scope only starts // after we return the pointer. Therefore, there can be no references // to the old value. - unsafe { - old.drop_in_place(); - crate::alloc::dealloc(old.cast(), layout); - } + drop(unsafe { AlignedBox::::from_raw(old) }); } // SAFETY: We just created this value above. @@ -196,22 +246,13 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. abort_on_dtor_unwind(|| { - let value_ptr: *mut Value = ptr.cast(); - unsafe { - let key = (*value_ptr).key; - - // SAFETY: `key` is the TLS key `ptr` was stored under. - set(key, ptr::without_provenance_mut(1)); - - // drop and deallocate the value - let layout = - Layout::from_size_align_unchecked(crate::mem::size_of::>(), ALIGN); - value_ptr.drop_in_place(); - crate::alloc::dealloc(ptr, layout); - - // SAFETY: `key` is the TLS key `ptr` was stored under. - set(key, ptr::null_mut()); - }; + let ptr = unsafe { AlignedBox::::from_raw(ptr as *mut Value) }; + let key = ptr.key; + // SAFETY: `key` is the TLS key `ptr` was stored under. + unsafe { set(key, ptr::without_provenance_mut(1)) }; + drop(ptr); + // SAFETY: `key` is the TLS key `ptr` was stored under. + unsafe { set(key, ptr::null_mut()) }; // Make sure that the runtime cleanup will be performed // after the next round of TLS destruction. guard::enable(); diff --git a/src/tools/miri/tests/pass/thread_local-panic.rs b/src/tools/miri/tests/pass/thread_local-panic.rs new file mode 100644 index 000000000000..549acd23987e --- /dev/null +++ b/src/tools/miri/tests/pass/thread_local-panic.rs @@ -0,0 +1,8 @@ +thread_local! { + static LOCAL: u64 = panic!(); + +} + +fn main() { + let _ = std::panic::catch_unwind(|| LOCAL.with(|_| {})); +} diff --git a/src/tools/miri/tests/pass/thread_local-panic.stderr b/src/tools/miri/tests/pass/thread_local-panic.stderr new file mode 100644 index 000000000000..e69340a81026 --- /dev/null +++ b/src/tools/miri/tests/pass/thread_local-panic.stderr @@ -0,0 +1,5 @@ + +thread 'main' ($TID) panicked at tests/pass/thread_local-panic.rs:LL:CC: +explicit panic +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect From 5991c8703d01cc73c31c51fef5d92b93ac1391b4 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:14:45 +0200 Subject: [PATCH 459/537] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index 33f1af40cc44..1d7c3e6abec2 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 33f1af40cc44dde7e3e892f7a508e6f427d2cbc6 +Subproject commit 1d7c3e6abec2d5a9bfac798b29b7855b95025426 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index aa6ce337c0ad..e2ed891f0036 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit aa6ce337c0adf7a63e33960d184270f2a45ab9ef +Subproject commit e2ed891f00361efc26616d82590b1c85d7a8920e diff --git a/src/doc/nomicon b/src/doc/nomicon index f17a018b9989..23fc2682f8fc 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit f17a018b9989430967d1c58e9a12c51169abc744 +Subproject commit 23fc2682f8fcb887f77d0eaabba708809f834c11 diff --git a/src/doc/reference b/src/doc/reference index cc7247d8dfae..e11adf6016a3 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit cc7247d8dfaef4c39000bb12c55c32ba5b5ba976 +Subproject commit e11adf6016a362766eea5a3f9832e193994dd0c8 From 4735c2184c72b8b3a8bad642407a74d4b19838fb Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 2 Jul 2025 17:18:57 +0800 Subject: [PATCH 460/537] Fix diagnostics str::replace comma to bar --- .../rustc_parse/src/parser/diagnostics.rs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a28af7833c38..5d6da6093120 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2947,26 +2947,24 @@ impl<'a> Parser<'a> { } let seq_span = lo.to(self.prev_token.span); let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.multipart_suggestion( - format!( - "try adding parentheses to match on a tuple{}", - if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." }, - ), - vec![ - (seq_span.shrink_to_lo(), "(".to_string()), - (seq_span.shrink_to_hi(), ")".to_string()), - ], + err.multipart_suggestion( + format!( + "try adding parentheses to match on a tuple{}", + if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." }, + ), + vec![ + (seq_span.shrink_to_lo(), "(".to_string()), + (seq_span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + if let CommaRecoveryMode::EitherTupleOrPipe = rt { + err.span_suggestion( + comma_span, + "...or a vertical bar to match on alternative", + " |", Applicability::MachineApplicable, ); - if let CommaRecoveryMode::EitherTupleOrPipe = rt { - err.span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(',', " |"), - Applicability::MachineApplicable, - ); - } } Err(err) } From a08228d284a91e5b2514035b723e82deb9179985 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Sat, 27 Sep 2025 22:57:13 +0200 Subject: [PATCH 461/537] bless tests --- ...ssue-48492-tuple-destructure-missing-parens.stderr | 4 ++-- .../feature-gates/feature-gate-never_patterns.stderr | 2 +- tests/ui/parser/match-arm-without-body.rs | 4 ++-- tests/ui/parser/match-arm-without-body.stderr | 11 ++++------- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index c74cb89f85cb..dc875ad27ea6 100644 --- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -32,10 +32,10 @@ help: try adding parentheses to match on a tuple... | LL | (Nucleotide::Adenine, Nucleotide::Cytosine, _) => true | + + -help: ...or a vertical bar to match on multiple alternatives +help: ...or a vertical bar to match on alternative | LL - Nucleotide::Adenine, Nucleotide::Cytosine, _ => true -LL + Nucleotide::Adenine | Nucleotide::Cytosine | _ => true +LL + Nucleotide::Adenine | Nucleotide::Cytosine, _ => true | error: unexpected `,` in pattern diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr index 473e263c7965..5e810249b906 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr @@ -8,7 +8,7 @@ help: try adding parentheses to match on a tuple... | LL | (Some(_),) | + + -help: ...or a vertical bar to match on multiple alternatives +help: ...or a vertical bar to match on alternative | LL - Some(_), LL + Some(_) | diff --git a/tests/ui/parser/match-arm-without-body.rs b/tests/ui/parser/match-arm-without-body.rs index 4723abff8b6a..7fe5b6d25398 100644 --- a/tests/ui/parser/match-arm-without-body.rs +++ b/tests/ui/parser/match-arm-without-body.rs @@ -17,13 +17,13 @@ fn main() { Some(_), //~^ ERROR unexpected `,` in pattern //~| HELP try adding parentheses to match on a tuple - //~| HELP or a vertical bar to match on multiple alternatives + //~| HELP or a vertical bar to match on alternative } match Some(false) { Some(_), //~^ ERROR unexpected `,` in pattern //~| HELP try adding parentheses to match on a tuple - //~| HELP or a vertical bar to match on multiple alternatives + //~| HELP or a vertical bar to match on alternative _ => {} } match Some(false) { diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index a65875b787a3..85ff7db8d4aa 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -16,7 +16,7 @@ help: try adding parentheses to match on a tuple... | LL | (Some(_),) | + + -help: ...or a vertical bar to match on multiple alternatives +help: ...or a vertical bar to match on alternative | LL - Some(_), LL + Some(_) | @@ -36,13 +36,10 @@ LL | LL | LL ~ _) => {} | -help: ...or a vertical bar to match on multiple alternatives +help: ...or a vertical bar to match on alternative | -LL ~ Some(_) | -LL + -LL + -LL + -LL ~ _ => {} +LL - Some(_), +LL + Some(_) | | error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` From 934ad740270944800d03f6290bcc131a8697e59f Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Wed, 1 Oct 2025 22:40:23 +0200 Subject: [PATCH 462/537] regression test --- ...place-intended-bar-not-all-in-pattern.fixed | 18 ++++++++++++++++++ ...-replace-intended-bar-not-all-in-pattern.rs | 18 ++++++++++++++++++ ...lace-intended-bar-not-all-in-pattern.stderr | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed create mode 100644 tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs create mode 100644 tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed new file mode 100644 index 000000000000..5abc1edd381b --- /dev/null +++ b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed @@ -0,0 +1,18 @@ +//@ run-rustfix + +// Regression test for issue #143330. +// Ensure we suggest to replace only the intended bar with a comma, not all bars in the pattern. + +fn main() { + struct Foo { x: i32, ch: char } + let pos = Foo { x: 2, ch: 'x' }; + match pos { + // All commas here were replaced with bars. + // Foo { x: 2 | ch: ' |' } | Foo { x: 3 | ch: '@' } => (), + (Foo { x: 2, ch: ',' } | Foo { x: 3, ch: '@' }) => (), + //~^ ERROR unexpected `,` in pattern + //~| HELP try adding parentheses to match on a tuple... + //~| HELP ...or a vertical bar to match on alternative + _ => todo!(), + } +} diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs new file mode 100644 index 000000000000..5bd267c3bc40 --- /dev/null +++ b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs @@ -0,0 +1,18 @@ +//@ run-rustfix + +// Regression test for issue #143330. +// Ensure we suggest to replace only the intended bar with a comma, not all bars in the pattern. + +fn main() { + struct Foo { x: i32, ch: char } + let pos = Foo { x: 2, ch: 'x' }; + match pos { + // All commas here were replaced with bars. + // Foo { x: 2 | ch: ' |' } | Foo { x: 3 | ch: '@' } => (), + Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (), + //~^ ERROR unexpected `,` in pattern + //~| HELP try adding parentheses to match on a tuple... + //~| HELP ...or a vertical bar to match on alternative + _ => todo!(), + } +} diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr new file mode 100644 index 000000000000..db0bb8c50e86 --- /dev/null +++ b/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr @@ -0,0 +1,18 @@ +error: unexpected `,` in pattern + --> $DIR/only-replace-intended-bar-not-all-in-pattern.rs:12:30 + | +LL | Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (), + | ^ + | +help: try adding parentheses to match on a tuple... + | +LL | (Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' }) => (), + | + + +help: ...or a vertical bar to match on alternative + | +LL - Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (), +LL + Foo { x: 2, ch: ',' } | Foo { x: 3, ch: '@' } => (), + | + +error: aborting due to 1 previous error + From 08b4641f50f6f8fa3aa222fa606a0c1a2482b72d Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Wed, 20 Aug 2025 18:20:53 -0400 Subject: [PATCH 463/537] add CloneFromCell and Cell::get_cloned --- library/alloc/src/lib.rs | 1 + library/alloc/src/rc.rs | 10 ++++- library/alloc/src/sync.rs | 9 ++++ library/core/src/cell.rs | 92 ++++++++++++++++++++++++++++++++++++++- library/core/src/tuple.rs | 10 +++++ 5 files changed, 119 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cba1ce40f75d..e7cfd01e654e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,6 +103,7 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cast_maybe_uninit)] +#![feature(cell_get_cloned)] #![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index aed3357afbf4..783b6147e956 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -242,7 +242,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any; -use core::cell::Cell; +use core::cell::{Cell, CloneFromCell}; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; use core::clone::UseCloned; @@ -338,6 +338,10 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> for #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Rc {} +// SAFETY: `Rc::clone` doesn't access any `Cell`s which could contain the `Rc` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Rc {} + impl Rc { #[inline] unsafe fn from_inner(ptr: NonNull>) -> Self { @@ -3011,6 +3015,10 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> f #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Weak {} +// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Weak {} + impl Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a466b74944c5..eddc9047f21b 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -9,6 +9,7 @@ //! `#[cfg(target_has_atomic = "ptr")]`. use core::any::Any; +use core::cell::CloneFromCell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; use core::clone::UseCloned; @@ -281,6 +282,10 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> fo #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Arc {} +// SAFETY: `Arc::clone` doesn't access any `Cell`s which could contain the `Arc` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Arc {} + impl Arc { unsafe fn from_inner(ptr: NonNull>) -> Self { unsafe { Self::from_inner_in(ptr, Global) } @@ -356,6 +361,10 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> f #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Weak {} +// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Weak {} + #[stable(feature = "arc_weak", since = "1.4.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7d4a66640b10..a991bbf46b1f 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -253,11 +253,12 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; -use crate::mem; -use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; +use crate::mem::{self, ManuallyDrop}; +use crate::ops::{self, CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::panic::const_panic; use crate::pin::PinCoerceUnsized; use crate::ptr::{self, NonNull}; +use crate::range; mod lazy; mod once; @@ -713,6 +714,93 @@ impl Cell<[T; N]> { } } +/// Types for which cloning `Cell` is sound. +/// +/// # Safety +/// +/// Implementing this trait for a type is sound if and only if the following code is sound for T = +/// that type. +/// +/// ``` +/// #![feature(cell_get_cloned)] +/// # use std::cell::{CloneFromCell, Cell}; +/// fn clone_from_cell(cell: &Cell) -> T { +/// unsafe { T::clone(&*cell.as_ptr()) } +/// } +/// ``` +/// +/// Importantly, you can't just implement `CloneFromCell` for any arbitrary `Copy` type, e.g. the +/// following is unsound: +/// +/// ```rust +/// #![feature(cell_get_cloned)] +/// # use std::cell::Cell; +/// +/// #[derive(Copy, Debug)] +/// pub struct Bad<'a>(Option<&'a Cell>>, u8); +/// +/// impl Clone for Bad<'_> { +/// fn clone(&self) -> Self { +/// let a: &u8 = &self.1; +/// // when self.0 points to self, we write to self.1 while we have a live `&u8` pointing to +/// // it -- this is UB +/// self.0.unwrap().set(Self(None, 1)); +/// dbg!((a, self)); +/// Self(None, 0) +/// } +/// } +/// +/// // this is not sound +/// // unsafe impl CloneFromCell for Bad<'_> {} +/// ``` +#[unstable(feature = "cell_get_cloned", issue = "145329")] +// Allow potential overlapping implementations in user code +#[marker] +pub unsafe trait CloneFromCell: Clone {} + +// `CloneFromCell` can be implemented for types that don't have indirection and which don't access +// `Cell`s in their `Clone` implementation. A commonly-used subset is covered here. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for [T; N] {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Option {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for Result {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for PhantomData {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for ManuallyDrop {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for ops::Range {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl CloneFromCell for range::Range {} + +#[unstable(feature = "cell_get_cloned", issue = "145329")] +impl Cell { + /// Get a clone of the `Cell` that contains a copy of the original value. + /// + /// This allows a cheaply `Clone`-able type like an `Rc` to be stored in a `Cell`, exposing the + /// cheaper `clone()` method. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_get_cloned)] + /// + /// use core::cell::Cell; + /// use std::rc::Rc; + /// + /// let rc = Rc::new(1usize); + /// let c1 = Cell::new(rc); + /// let c2 = c1.get_cloned(); + /// assert_eq!(*c2.into_inner(), 1); + /// ``` + pub fn get_cloned(&self) -> Self { + // SAFETY: T is CloneFromCell, which guarantees that this is sound. + Cell::new(T::clone(unsafe { &*self.as_ptr() })) + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index c57a8d81ade1..58f81372aff7 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,5 +1,6 @@ // See core/src/primitive_docs.rs for documentation. +use crate::cell::CloneFromCell; use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq}; use crate::ops::ControlFlow::{self, Break, Continue}; @@ -155,6 +156,15 @@ macro_rules! tuple_impls { } } } + + maybe_tuple_doc! { + $($T)+ @ + // SAFETY: tuples introduce no additional indirection, so they can be copied whenever T + // can. + #[unstable(feature = "cell_get_cloned", issue = "145329")] + unsafe impl<$($T: CloneFromCell),+> CloneFromCell for ($($T,)+) + {} + } } } From 30d57abccf7d55e9dd4e36be583c55f6b0090302 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Sep 2025 14:32:56 +0800 Subject: [PATCH 464/537] mbe: Rename a local variable to match corresponding field names This simplifies subsequent initialization of enum variants. --- compiler/rustc_expand/src/mbe/macro_rules.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d4504ba720e4..8ed46a9fe9f6 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -741,10 +741,10 @@ pub fn compile_declarative_macro( if let Some(guar) = check_no_eof(sess, &p, "expected right-hand side of macro rule") { return dummy_syn_ext(guar); } - let rhs_tt = p.parse_token_tree(); - let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); - check_emission(check_rhs(sess, &rhs_tt)); - check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt)); + let rhs = p.parse_token_tree(); + let rhs = parse_one_tt(rhs, RulePart::Body, sess, node_id, features, edition); + check_emission(check_rhs(sess, &rhs)); + check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs)); let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. @@ -760,11 +760,11 @@ pub fn compile_declarative_macro( }; let args = mbe::macro_parser::compute_locs(&delimited.tts); let body_span = lhs_span; - rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt }); + rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs }); } else if is_derive { - rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs }); } else { - rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Func { lhs, lhs_span, rhs }); } if p.token == token::Eof { break; From 6bff1abf9d3c171d2380aacb8b4c6f52580192b3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Sep 2025 16:17:51 +0800 Subject: [PATCH 465/537] mbe: Support `unsafe` attribute rules --- .../rustc_attr_parsing/src/validate_attr.rs | 12 ++--- compiler/rustc_expand/src/base.rs | 17 ++++++- compiler/rustc_expand/src/expand.rs | 6 ++- compiler/rustc_expand/src/mbe/macro_rules.rs | 46 +++++++++++++++++-- .../unsafe/double-unsafe-attributes.rs | 2 +- .../unsafe/double-unsafe-attributes.stderr | 6 +-- .../unsafe-safe-attribute_diagnostic.rs | 2 +- .../unsafe-safe-attribute_diagnostic.stderr | 6 +-- 8 files changed, 75 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 7a7624893bd2..927417f89f8c 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -207,10 +207,9 @@ pub fn check_attribute_safety( } } - // - Normal builtin attribute, or any non-builtin attribute - // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is - // not permitted on non-builtin attributes or normal builtin attributes - (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => { + // - Normal builtin attribute + // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes + (Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), @@ -224,9 +223,8 @@ pub fn check_attribute_safety( } // - Non-builtin attribute - // - No explicit `#[unsafe(..)]` written. - (None, Safety::Default) => { - // OK + (None, Safety::Unsafe(_) | Safety::Default) => { + // OK (not checked here) } ( diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 33b712e3aedf..810a5a21a055 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -345,6 +345,21 @@ pub trait AttrProcMacro { annotation: TokenStream, annotated: TokenStream, ) -> Result; + + // Default implementation for safe attributes; override if the attribute can be unsafe. + fn expand_with_safety<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + safety: Safety, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result { + if let Safety::Unsafe(span) = safety { + ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } + self.expand(ecx, span, annotation, annotated) + } } impl AttrProcMacro for F diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 172bc3d1d9f8..a035896d5542 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.to_tokens(), }; let attr_item = attr.get_normal_item(); + let safety = attr_item.unsafety; if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - match expander.expand(self.cx, span, inner_tokens, tokens) { + match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( tok_result, @@ -882,6 +883,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } } else if let SyntaxExtensionKind::NonMacroAttr = ext { + if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety { + self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8ed46a9fe9f6..c548cea537f4 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; -use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; @@ -131,6 +131,7 @@ pub(super) enum MacroRule { Func { lhs: Vec, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` Attr { + unsafe_rule: bool, args: Vec, args_span: Span, body: Vec, @@ -247,8 +248,19 @@ impl TTMacroExpander for MacroRulesMacroExpander { impl AttrProcMacro for MacroRulesMacroExpander { fn expand( + &self, + _cx: &mut ExtCtxt<'_>, + _sp: Span, + _args: TokenStream, + _body: TokenStream, + ) -> Result { + unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`") + } + + fn expand_with_safety( &self, cx: &mut ExtCtxt<'_>, + safety: Safety, sp: Span, args: TokenStream, body: TokenStream, @@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander { self.node_id, self.name, self.transparency, + safety, args, body, &self.rules, @@ -408,6 +421,7 @@ fn expand_macro_attr( node_id: NodeId, name: Ident, transparency: Transparency, + safety: Safety, args: TokenStream, body: TokenStream, rules: &[MacroRule], @@ -429,13 +443,26 @@ fn expand_macro_attr( // Track nothing for the best performance. match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { Ok((i, rule, named_matches)) => { - let MacroRule::Attr { rhs, .. } = rule else { + let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else { panic!("try_macro_match_attr returned non-attr rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; + match (safety, unsafe_rule) { + (Safety::Default, false) | (Safety::Unsafe(_), true) => {} + (Safety::Default, true) => { + cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`"); + } + (Safety::Unsafe(span), false) => { + cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation"); + } + (Safety::Safe(span), _) => { + cx.dcx().span_bug(span, "unexpected `safe` keyword"); + } + } + let id = cx.current_expansion.id; let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) .map_err(|e| e.emit())?; @@ -681,6 +708,11 @@ pub fn compile_declarative_macro( let mut rules = Vec::new(); while p.token != token::Eof { + let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe); + let unsafe_keyword_span = p.prev_token.span; + if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") { + return dummy_syn_ext(guar); + } let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) { kinds |= MacroKinds::ATTR; if !features.macro_attr() { @@ -705,6 +737,10 @@ pub fn compile_declarative_macro( feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable") .emit(); } + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") { return dummy_syn_ext(guar); } @@ -730,6 +766,10 @@ pub fn compile_declarative_macro( (None, true) } else { kinds |= MacroKinds::BANG; + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } (None, false) }; let lhs_tt = p.parse_token_tree(); @@ -760,7 +800,7 @@ pub fn compile_declarative_macro( }; let args = mbe::macro_parser::compute_locs(&delimited.tts); let body_span = lhs_span; - rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs }); + rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs }); } else if is_derive { rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs }); } else { diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs index 894d1327da79..c0181d960539 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs @@ -1,7 +1,7 @@ #[unsafe(unsafe(no_mangle))] //~^ ERROR expected identifier, found keyword `unsafe` //~| ERROR cannot find attribute `r#unsafe` in this scope -//~| ERROR `r#unsafe` is not an unsafe attribute +//~| ERROR unnecessary `unsafe` fn a() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index 0825cf794083..846800daa546 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -9,13 +9,11 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(r#unsafe(no_mangle))] | ++ -error: `r#unsafe` is not an unsafe attribute +error: unnecessary `unsafe` on safe attribute --> $DIR/double-unsafe-attributes.rs:1:3 | LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes + | ^^^^^^ error: cannot find attribute `r#unsafe` in this scope --> $DIR/double-unsafe-attributes.rs:1:10 diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs index 0f241cc439f3..d9054248a292 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs @@ -1,4 +1,4 @@ -#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute +#[unsafe(diagnostic::on_unimplemented( //~ ERROR: unnecessary `unsafe` message = "testing", ))] trait Foo {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr index 3bc291db5acf..a7662f5ee6c7 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr @@ -1,10 +1,8 @@ -error: `diagnostic::on_unimplemented` is not an unsafe attribute +error: unnecessary `unsafe` on safe attribute --> $DIR/unsafe-safe-attribute_diagnostic.rs:1:3 | LL | #[unsafe(diagnostic::on_unimplemented( - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes + | ^^^^^^ error: aborting due to 1 previous error From 05c5b8779704e20620e18c822a18f28e4961e86e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Sep 2025 16:23:39 +0800 Subject: [PATCH 466/537] mbe: Add parsing tests for `unsafe` macro rules --- tests/ui/parser/macro/bad-macro-definition.rs | 3 +++ .../parser/macro/bad-macro-definition.stderr | 8 +++++- tests/ui/parser/macro/macro-attr-bad.rs | 6 +++++ tests/ui/parser/macro/macro-attr-bad.stderr | 26 ++++++++++++++----- tests/ui/parser/macro/macro-derive-bad.rs | 3 +++ tests/ui/parser/macro/macro-derive-bad.stderr | 8 +++++- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/tests/ui/parser/macro/bad-macro-definition.rs b/tests/ui/parser/macro/bad-macro-definition.rs index 3c5c93ea3b3e..12df6e64bd2c 100644 --- a/tests/ui/parser/macro/bad-macro-definition.rs +++ b/tests/ui/parser/macro/bad-macro-definition.rs @@ -20,3 +20,6 @@ macro_rules! e { {} } macro_rules! f {} //~^ ERROR: macros must contain at least one rule + +macro_rules! g { unsafe {} => {} } +//~^ ERROR: `unsafe` is only supported on `attr` rules diff --git a/tests/ui/parser/macro/bad-macro-definition.stderr b/tests/ui/parser/macro/bad-macro-definition.stderr index de6d9d6a38b1..d15f33f708de 100644 --- a/tests/ui/parser/macro/bad-macro-definition.stderr +++ b/tests/ui/parser/macro/bad-macro-definition.stderr @@ -52,5 +52,11 @@ error: macros must contain at least one rule LL | macro_rules! f {} | ^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: `unsafe` is only supported on `attr` rules + --> $DIR/bad-macro-definition.rs:24:18 + | +LL | macro_rules! g { unsafe {} => {} } + | ^^^^^^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/parser/macro/macro-attr-bad.rs b/tests/ui/parser/macro/macro-attr-bad.rs index 9f50b057a7a4..0ac46c8b7681 100644 --- a/tests/ui/parser/macro/macro-attr-bad.rs +++ b/tests/ui/parser/macro/macro-attr-bad.rs @@ -13,6 +13,12 @@ macro_rules! attr_incomplete_3 { attr() {} } macro_rules! attr_incomplete_4 { attr() {} => } //~^ ERROR macro definition ended unexpectedly +macro_rules! attr_incomplete_5 { unsafe } +//~^ ERROR macro definition ended unexpectedly + +macro_rules! attr_incomplete_6 { unsafe attr } +//~^ ERROR macro definition ended unexpectedly + macro_rules! attr_noparens_1 { attr{} {} => {} } //~^ ERROR `attr` rule argument matchers require parentheses diff --git a/tests/ui/parser/macro/macro-attr-bad.stderr b/tests/ui/parser/macro/macro-attr-bad.stderr index bf0ed13cd553..481ef8118aeb 100644 --- a/tests/ui/parser/macro/macro-attr-bad.stderr +++ b/tests/ui/parser/macro/macro-attr-bad.stderr @@ -22,8 +22,20 @@ error: macro definition ended unexpectedly LL | macro_rules! attr_incomplete_4 { attr() {} => } | ^ expected right-hand side of macro rule +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:16:40 + | +LL | macro_rules! attr_incomplete_5 { unsafe } + | ^ expected `attr` + +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:19:45 + | +LL | macro_rules! attr_incomplete_6 { unsafe attr } + | ^ expected macro attr args + error: `attr` rule argument matchers require parentheses - --> $DIR/macro-attr-bad.rs:16:36 + --> $DIR/macro-attr-bad.rs:22:36 | LL | macro_rules! attr_noparens_1 { attr{} {} => {} } | ^^ @@ -35,7 +47,7 @@ LL + macro_rules! attr_noparens_1 { attr() {} => {} } | error: `attr` rule argument matchers require parentheses - --> $DIR/macro-attr-bad.rs:19:36 + --> $DIR/macro-attr-bad.rs:25:36 | LL | macro_rules! attr_noparens_2 { attr[] {} => {} } | ^^ @@ -47,13 +59,13 @@ LL + macro_rules! attr_noparens_2 { attr() {} => {} } | error: invalid macro matcher; matchers must be contained in balanced delimiters - --> $DIR/macro-attr-bad.rs:22:37 + --> $DIR/macro-attr-bad.rs:28:37 | LL | macro_rules! attr_noparens_3 { attr _ {} => {} } | ^ error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:25:52 + --> $DIR/macro-attr-bad.rs:31:52 | LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } | -------- ^^^^^^^^ duplicate binding @@ -61,7 +73,7 @@ LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } | previous binding error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:28:49 + --> $DIR/macro-attr-bad.rs:34:49 | LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } | -------- ^^^^^^^^ duplicate binding @@ -69,12 +81,12 @@ LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } | previous binding error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:31:51 + --> $DIR/macro-attr-bad.rs:37:51 | LL | macro_rules! attr_dup_matcher_3 { attr($x:ident) {$x:ident} => {} } | -------- ^^^^^^^^ duplicate binding | | | previous binding -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/parser/macro/macro-derive-bad.rs b/tests/ui/parser/macro/macro-derive-bad.rs index 79b9eb8c113c..74e7d9acdafc 100644 --- a/tests/ui/parser/macro/macro-derive-bad.rs +++ b/tests/ui/parser/macro/macro-derive-bad.rs @@ -41,3 +41,6 @@ macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} } //~^ ERROR duplicate matcher binding //~| NOTE duplicate binding //~| NOTE previous binding + +macro_rules! derive_unsafe { unsafe derive() {} => {} } +//~^ ERROR `unsafe` is only supported on `attr` rules diff --git a/tests/ui/parser/macro/macro-derive-bad.stderr b/tests/ui/parser/macro/macro-derive-bad.stderr index ec750c9ac822..c98535f4031f 100644 --- a/tests/ui/parser/macro/macro-derive-bad.stderr +++ b/tests/ui/parser/macro/macro-derive-bad.stderr @@ -86,5 +86,11 @@ LL | macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} } | | | previous binding -error: aborting due to 12 previous errors +error: `unsafe` is only supported on `attr` rules + --> $DIR/macro-derive-bad.rs:45:30 + | +LL | macro_rules! derive_unsafe { unsafe derive() {} => {} } + | ^^^^^^ + +error: aborting due to 13 previous errors From ea0e00c5738f56970ad3ed3cc3d27c19715cd9ea Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Sep 2025 16:28:50 +0800 Subject: [PATCH 467/537] mbe: Add tests for `unsafe` attr invocation --- tests/ui/macros/macro-rules-attr-error.rs | 19 +++++++++++++++++++ tests/ui/macros/macro-rules-attr-error.stderr | 14 +++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs index 81eadb6692f2..60290b883cb8 100644 --- a/tests/ui/macros/macro-rules-attr-error.rs +++ b/tests/ui/macros/macro-rules-attr-error.rs @@ -50,3 +50,22 @@ macro_rules! forward_referenced_attr { macro_rules! cyclic_attr { attr() {} => {} } + +macro_rules! attr_with_safety { + unsafe attr() { struct RequiresUnsafe; } => {}; + attr() { struct SafeInvocation; } => {}; +} + +#[attr_with_safety] +struct SafeInvocation; + +//~v ERROR: unnecessary `unsafe` on safe attribute invocation +#[unsafe(attr_with_safety)] +struct SafeInvocation; + +//~v ERROR: unsafe attribute invocation requires `unsafe` +#[attr_with_safety] +struct RequiresUnsafe; + +#[unsafe(attr_with_safety)] +struct RequiresUnsafe; diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr index 674d35091b68..27527a2da7ef 100644 --- a/tests/ui/macros/macro-rules-attr-error.stderr +++ b/tests/ui/macros/macro-rules-attr-error.stderr @@ -9,6 +9,18 @@ LL | #[local_attr] | = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info) +error: unnecessary `unsafe` on safe attribute invocation + --> $DIR/macro-rules-attr-error.rs:63:3 + | +LL | #[unsafe(attr_with_safety)] + | ^^^^^^ + +error: unsafe attribute invocation requires `unsafe` + --> $DIR/macro-rules-attr-error.rs:67:1 + | +LL | #[attr_with_safety] + | ^^^^^^^^^^^^^^^^^^^ + error: cannot find macro `local_attr` in this scope --> $DIR/macro-rules-attr-error.rs:27:5 | @@ -59,5 +71,5 @@ note: a macro with the same name exists, but it appears later LL | macro_rules! cyclic_attr { | ^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From 4fc0a0d42a66e9b248fa527f7f063ec7226803dd Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 28 Sep 2025 09:15:02 -0700 Subject: [PATCH 468/537] mbe: `expand_invoc`: Add comment about not needing to check safety of `LegacyAttr` here `LegacyAttr` is only used for builtin attributes, and builtin attributes have their safety checked by `check_attribute_safety`, so we don't need to check `unsafety` here. --- compiler/rustc_expand/src/expand.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index a035896d5542..3dfa3cdcc356 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -841,6 +841,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { + // `LegacyAttr` is only used for builtin attribute macros, which have their + // safety checked by `check_builtin_meta_item`, so we don't need to check + // `unsafety` here. match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { let item_clone = macro_stats.then(|| item.clone()); From 59c4dfe59d587f0f09746958bf9a16c271cc02a7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 Oct 2025 21:45:50 +1000 Subject: [PATCH 469/537] Forbid `//@ compile-flags: -Cincremental=` in tests Tests should not try to manually enable incremental compilation with `-Cincremental`, because that typically results in stray directories being created in the repository root. Instead, use the `//@ incremental` directive, which instructs compiletest to handle the details of passing `-Cincremental` with a fresh directory. --- src/tools/compiletest/src/directives.rs | 10 +++++++++- .../compile-flags-incremental.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/compiletest-self-test/compile-flags-incremental.rs diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e6916610190e..0d85e76c2cc0 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -415,10 +415,18 @@ impl TestProps { config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile) { let flags = split_flags(&flags); - for flag in &flags { + for (i, flag) in flags.iter().enumerate() { if flag == "--edition" || flag.starts_with("--edition=") { panic!("you must use `//@ edition` to configure the edition"); } + if (flag == "-C" + && flags.get(i + 1).is_some_and(|v| v.starts_with("incremental="))) + || flag.starts_with("-Cincremental=") + { + panic!( + "you must use `//@ incremental` to enable incremental compilation" + ); + } } self.compile_flags.extend(flags); } diff --git a/tests/ui/compiletest-self-test/compile-flags-incremental.rs b/tests/ui/compiletest-self-test/compile-flags-incremental.rs new file mode 100644 index 000000000000..62a1ad84d8f7 --- /dev/null +++ b/tests/ui/compiletest-self-test/compile-flags-incremental.rs @@ -0,0 +1,17 @@ +//@ revisions: good bad bad-space +//@ check-pass + +//@[bad] compile-flags: -Cincremental=true +//@[bad] should-fail + +//@[bad-space] compile-flags: -C incremental=dir +//@[bad-space] should-fail + +fn main() {} + +// Tests should not try to manually enable incremental compilation with +// `-Cincremental`, because that typically results in stray directories being +// created in the repository root. +// +// Instead, use the `//@ incremental` directive, which instructs compiletest +// to handle the details of passing `-Cincremental` with a fresh directory. From 571412f8190089c36758031fe09fc0ece59be6b7 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 8 Jun 2025 15:30:09 +0800 Subject: [PATCH 470/537] mir-opt: Eliminate dead ref statements --- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 4 + compiler/rustc_middle/src/mir/mod.rs | 45 ++- compiler/rustc_middle/src/mir/pretty.rs | 19 + compiler/rustc_middle/src/mir/statement.rs | 103 +++++- compiler/rustc_middle/src/mir/visit.rs | 40 ++- compiler/rustc_mir_dataflow/src/debuginfo.rs | 10 +- .../rustc_mir_dataflow/src/impls/liveness.rs | 78 ++-- .../src/cleanup_post_borrowck.rs | 4 +- compiler/rustc_mir_transform/src/copy_prop.rs | 4 +- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- .../src/dead_store_elimination.rs | 55 ++- compiler/rustc_mir_transform/src/dest_prop.rs | 4 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../rustc_mir_transform/src/large_enums.rs | 2 +- compiler/rustc_mir_transform/src/patch.rs | 2 +- .../rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/ref_prop.rs | 2 +- .../src/remove_place_mention.rs | 2 +- .../src/remove_storage_markers.rs | 2 +- .../rustc_mir_transform/src/remove_zsts.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 29 +- .../src/simplify_comparison_integral.rs | 4 +- compiler/rustc_mir_transform/src/sroa.rs | 10 +- tests/codegen-llvm/debug-fndef-size.rs | 4 +- ...ad_first.DeadStoreElimination-initial.diff | 31 ++ tests/mir-opt/dead-store-elimination/ref.rs | 33 ++ ...ef.tuple.DeadStoreElimination-initial.diff | 26 ++ ...ycfg.drop_debuginfo.SimplifyCfg-final.diff | 26 ++ ...reserve_debuginfo_1.SimplifyCfg-final.diff | 30 ++ ...reserve_debuginfo_2.SimplifyCfg-final.diff | 29 ++ .../inline_shims.drop.Inline.panic-abort.diff | 56 +-- ...y.run2-{closure#0}.Inline.panic-abort.diff | 6 +- ....run2-{closure#0}.Inline.panic-unwind.diff | 6 +- ...implifyComparisonIntegral.panic-abort.diff | 6 +- ...mplifyComparisonIntegral.panic-unwind.diff | 6 +- ...git.PreCodegen.after.32bit.panic-abort.mir | 4 + ...it.PreCodegen.after.32bit.panic-unwind.mir | 4 + ...git.PreCodegen.after.64bit.panic-abort.mir | 4 + ...it.PreCodegen.after.64bit.panic-unwind.mir | 4 + ...p_forward.PreCodegen.after.panic-abort.mir | 40 ++- ..._forward.PreCodegen.after.panic-unwind.mir | 40 ++- ...as_copy.clone_as_copy.PreCodegen.after.mir | 2 +- ...py.enum_clone_as_copy.PreCodegen.after.mir | 6 +- ...ace.PreCodegen.after.32bit.panic-abort.mir | 38 +- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 38 +- ...ace.PreCodegen.after.64bit.panic-abort.mir | 38 +- ...ce.PreCodegen.after.64bit.panic-unwind.mir | 38 +- tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 2 +- .../loops.filter_mapped.PreCodegen.after.mir | 44 +-- .../loops.int_range.PreCodegen.after.mir | 100 +++--- .../loops.mapped.PreCodegen.after.mir | 84 ++--- tests/mir-opt/pre-codegen/loops.rs | 1 + .../loops.vec_move.PreCodegen.after.mir | 340 ++++++++++++++++-- ...variant_a-{closure#0}.PreCodegen.after.mir | 199 +++++----- ...ated_loop.PreCodegen.after.panic-abort.mir | 14 + ...ward_loop.PreCodegen.after.panic-abort.mir | 14 + ...ard_loop.PreCodegen.after.panic-unwind.mir | 14 + ...erse_loop.PreCodegen.after.panic-abort.mir | 227 ++++++++++-- ...rse_loop.PreCodegen.after.panic-unwind.mir | 233 ++++++++++-- ..._is_empty.PreCodegen.after.panic-abort.mir | 8 + ...is_empty.PreCodegen.after.panic-unwind.mir | 8 + ...next_back.PreCodegen.after.panic-abort.mir | 189 +++++++++- ...ext_back.PreCodegen.after.panic-unwind.mir | 189 +++++++++- ...iter_next.PreCodegen.after.panic-abort.mir | 14 + ...ter_next.PreCodegen.after.panic-unwind.mir | 14 + ...ans.outer.PreCodegen.after.panic-abort.mir | 2 +- ...ns.outer.PreCodegen.after.panic-unwind.mir | 2 +- ..._to_slice.PreCodegen.after.panic-abort.mir | 8 + ...to_slice.PreCodegen.after.panic-unwind.mir | 8 + 69 files changed, 2142 insertions(+), 514 deletions(-) create mode 100644 tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff create mode 100644 tests/mir-opt/dead-store-elimination/ref.rs create mode 100644 tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 45bc54519468..0a37a904193f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -260,6 +260,10 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer PlaceContext::MutatingUse(MutatingUseContext::Yield) => bug!(), } } + + fn visit_statement_debuginfo(&mut self, _: &mir::StmtDebugInfo<'tcx>, _: Location) { + // Debuginfo does not generate actual code. + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 28142382b130..8eb7aa71fcde 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1298,6 +1298,10 @@ pub struct BasicBlockData<'tcx> { /// List of statements in this block. pub statements: Vec>, + /// All debuginfos happen before the statement. + /// Put debuginfos here when the last statement is eliminated. + pub after_last_stmt_debuginfos: StmtDebugInfos<'tcx>, + /// Terminator for this block. /// /// N.B., this should generally ONLY be `None` during construction. @@ -1325,7 +1329,12 @@ impl<'tcx> BasicBlockData<'tcx> { terminator: Option>, is_cleanup: bool, ) -> BasicBlockData<'tcx> { - BasicBlockData { statements, terminator, is_cleanup } + BasicBlockData { + statements, + after_last_stmt_debuginfos: StmtDebugInfos::default(), + terminator, + is_cleanup, + } } /// Accessor for terminator. @@ -1360,6 +1369,36 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator().successors() } } + + pub fn retain_statements(&mut self, mut f: F) + where + F: FnMut(&Statement<'tcx>) -> bool, + { + // Place debuginfos into the next retained statement, + // this `debuginfos` variable is used to cache debuginfos between two retained statements. + let mut debuginfos = StmtDebugInfos::default(); + self.statements.retain_mut(|stmt| { + let retain = f(stmt); + if retain { + stmt.debuginfos.prepend(&mut debuginfos); + } else { + debuginfos.append(&mut stmt.debuginfos); + } + retain + }); + self.after_last_stmt_debuginfos.prepend(&mut debuginfos); + } + + pub fn strip_nops(&mut self) { + self.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + } + + pub fn drop_debuginfo(&mut self) { + self.after_last_stmt_debuginfos.drop_debuginfo(); + for stmt in self.statements.iter_mut() { + stmt.debuginfos.drop_debuginfo(); + } + } } /////////////////////////////////////////////////////////////////////////// @@ -1664,10 +1703,10 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(BasicBlockData<'_>, 128); + static_assert_size!(BasicBlockData<'_>, 152); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 64); - static_assert_size!(Statement<'_>, 32); + static_assert_size!(Statement<'_>, 56); static_assert_size!(Terminator<'_>, 96); static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 350d75c2ee77..8cf89f778a2a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -719,6 +719,11 @@ impl<'de, 'tcx> MirWriter<'de, 'tcx> { let mut current_location = Location { block, statement_index: 0 }; for statement in &data.statements { (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; + + for debuginfo in statement.debuginfos.iter() { + writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?};")?; + } + let indented_body = format!("{INDENT}{INDENT}{statement:?};"); if self.options.include_extra_comments { writeln!( @@ -749,6 +754,10 @@ impl<'de, 'tcx> MirWriter<'de, 'tcx> { current_location.statement_index += 1; } + for debuginfo in data.after_last_stmt_debuginfos.iter() { + writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?};")?; + } + // Terminator at the bottom. (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; if data.terminator.is_some() { @@ -829,6 +838,16 @@ impl Debug for Statement<'_> { } } +impl Debug for StmtDebugInfo<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + match self { + StmtDebugInfo::AssignRef(local, place) => { + write!(fmt, "{local:?} = &{place:?}") + } + } + } +} + impl Display for NonDivergingIntrinsic<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index e009fe05b53e..9deb43eb7084 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -1,5 +1,7 @@ //! Functionality for statements, operands, places, and things that appear in them. +use std::ops; + use tracing::{debug, instrument}; use super::interpret::GlobalAlloc; @@ -15,17 +17,34 @@ use crate::ty::CoroutineArgsExt; pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, + /// Some debuginfos appearing before the primary statement. + pub debuginfos: StmtDebugInfos<'tcx>, } impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. - pub fn make_nop(&mut self) { - self.kind = StatementKind::Nop + pub fn make_nop(&mut self, drop_debuginfo: bool) { + if matches!(self.kind, StatementKind::Nop) { + return; + } + let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop); + if !drop_debuginfo { + match replaced_stmt { + StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) + if let Some(local) = place.as_local() => + { + self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place)); + } + _ => { + bug!("debuginfo is not yet supported.") + } + } + } } pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { - Statement { source_info, kind } + Statement { source_info, kind, debuginfos: StmtDebugInfos::default() } } } @@ -63,6 +82,17 @@ impl<'tcx> StatementKind<'tcx> { _ => None, } } + + pub fn as_debuginfo(&self) -> Option> { + match self { + StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) + if let Some(local) = place.as_local() => + { + Some(StmtDebugInfo::AssignRef(local, *ref_place)) + } + _ => None, + } + } } /////////////////////////////////////////////////////////////////////////// @@ -967,3 +997,70 @@ impl RawPtrKind { } } } + +#[derive(Default, Debug, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct StmtDebugInfos<'tcx>(Vec>); + +impl<'tcx> StmtDebugInfos<'tcx> { + pub fn push(&mut self, debuginfo: StmtDebugInfo<'tcx>) { + self.0.push(debuginfo); + } + + pub fn drop_debuginfo(&mut self) { + self.0.clear(); + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn prepend(&mut self, debuginfos: &mut Self) { + if debuginfos.is_empty() { + return; + }; + debuginfos.0.append(self); + std::mem::swap(debuginfos, self); + } + + pub fn append(&mut self, debuginfos: &mut Self) { + if debuginfos.is_empty() { + return; + }; + self.0.append(debuginfos); + } + + pub fn extend(&mut self, debuginfos: &Self) { + if debuginfos.is_empty() { + return; + }; + self.0.extend_from_slice(debuginfos); + } + + pub fn retain(&mut self, f: F) + where + F: FnMut(&StmtDebugInfo<'tcx>) -> bool, + { + self.0.retain(f); + } +} + +impl<'tcx> ops::Deref for StmtDebugInfos<'tcx> { + type Target = Vec>; + + #[inline] + fn deref(&self) -> &Vec> { + &self.0 + } +} + +impl<'tcx> ops::DerefMut for StmtDebugInfos<'tcx> { + #[inline] + fn deref_mut(&mut self) -> &mut Vec> { + &mut self.0 + } +} + +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub enum StmtDebugInfo<'tcx> { + AssignRef(Local, Place<'tcx>), +} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index f39234778005..47ae23afd556 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -95,6 +95,14 @@ macro_rules! make_mir_visitor { self.super_source_scope_data(scope_data); } + fn visit_statement_debuginfo( + &mut self, + stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>, + location: Location + ) { + self.super_statement_debuginfo(stmt_debuginfo, location); + } + fn visit_statement( &mut self, statement: & $($mutability)? Statement<'tcx>, @@ -301,6 +309,7 @@ macro_rules! make_mir_visitor { { let BasicBlockData { statements, + after_last_stmt_debuginfos, terminator, is_cleanup: _ } = data; @@ -312,8 +321,11 @@ macro_rules! make_mir_visitor { index += 1; } + let location = Location { block, statement_index: index }; + for debuginfo in after_last_stmt_debuginfos as & $($mutability)? [_] { + self.visit_statement_debuginfo(debuginfo, location); + } if let Some(terminator) = terminator { - let location = Location { block, statement_index: index }; self.visit_terminator(terminator, location); } } @@ -376,14 +388,38 @@ macro_rules! make_mir_visitor { } } + fn super_statement_debuginfo( + &mut self, + stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>, + location: Location + ) { + match stmt_debuginfo { + StmtDebugInfo::AssignRef(local, place) => { + self.visit_local( + $(& $mutability)? *local, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + self.visit_place( + place, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + }, + } + } + fn super_statement( &mut self, statement: & $($mutability)? Statement<'tcx>, location: Location ) { - let Statement { source_info, kind } = statement; + let Statement { source_info, kind, debuginfos } = statement; self.visit_source_info(source_info); + for debuginfo in debuginfos as & $($mutability)? [_] { + self.visit_statement_debuginfo(debuginfo, location); + } match kind { StatementKind::Assign(box (place, rvalue)) => { self.visit_assign(place, rvalue, location); diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs index 0d25ce91c9a9..274c5943946c 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -5,16 +5,16 @@ use rustc_middle::mir::*; /// Return the set of locals that appear in debuginfo. pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet { let mut visitor = DebuginfoLocals(DenseBitSet::new_empty(body.local_decls.len())); - for debuginfo in body.var_debug_info.iter() { - visitor.visit_var_debug_info(debuginfo); - } + visitor.visit_body(body); visitor.0 } struct DebuginfoLocals(DenseBitSet); impl Visitor<'_> for DebuginfoLocals { - fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) { - self.0.insert(local); + fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) { + if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { + self.0.insert(local); + } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 5eba474a60c7..24da4b0bea28 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -210,6 +210,7 @@ impl DefUse { /// All of the caveats of `MaybeLiveLocals` apply. pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a DenseBitSet, + debuginfo_locals: &'a DenseBitSet, } impl<'a> MaybeTransitiveLiveLocals<'a> { @@ -217,8 +218,46 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { /// considered live. /// /// This should include at least all locals that are ever borrowed. - pub fn new(always_live: &'a DenseBitSet) -> Self { - MaybeTransitiveLiveLocals { always_live } + pub fn new( + always_live: &'a DenseBitSet, + debuginfo_locals: &'a DenseBitSet, + ) -> Self { + MaybeTransitiveLiveLocals { always_live, debuginfo_locals } + } + + pub fn can_be_removed_if_dead<'tcx>( + stmt_kind: &StatementKind<'tcx>, + always_live: &DenseBitSet, + debuginfo_locals: &'a DenseBitSet, + ) -> Option> { + // Compute the place that we are storing to, if any + let destination = match stmt_kind { + StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove() + && (!debuginfo_locals.contains(place.local) + || (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..))))) + .then_some(*place), + StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { + (!debuginfo_locals.contains(place.local)).then_some(**place) + } + StatementKind::FakeRead(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(..) + | StatementKind::AscribeUserType(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::Nop => None, + }; + if let Some(destination) = destination + && !destination.is_indirect() + && !always_live.contains(destination.local) + { + return Some(destination); + } + None } } @@ -243,32 +282,15 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { statement: &mir::Statement<'tcx>, location: Location, ) { - // Compute the place that we are storing to, if any - let destination = match &statement.kind { - StatementKind::Assign(assign) => assign.1.is_safe_to_remove().then_some(assign.0), - StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { - Some(**place) - } - StatementKind::FakeRead(_) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag(..) - | StatementKind::AscribeUserType(..) - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(..) - | StatementKind::Intrinsic(..) - | StatementKind::ConstEvalCounter - | StatementKind::BackwardIncompatibleDropHint { .. } - | StatementKind::Nop => None, - }; - if let Some(destination) = destination { - if !destination.is_indirect() - && !state.contains(destination.local) - && !self.always_live.contains(destination.local) - { - // This store is dead - return; - } + if let Some(destination) = + Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals) + && !state.contains(destination.local) + // FIXME: We can eliminate the statement, but we'll need the statements it depends on + // for debuginfos. We need a way to handle this. + && !self.debuginfo_locals.contains(destination.local) + { + // This store is dead + return; } TransferFunction(state).visit_statement(statement, location); } diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 4be67b873f73..b0bf7f484bed 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -36,7 +36,9 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. }, ) | StatementKind::FakeRead(..) - | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(), + | StatementKind::BackwardIncompatibleDropHint { .. } => { + statement.make_nop(true) + } StatementKind::Assign(box ( _, Rvalue::Cast( diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index cddeefca6817..f0bc286a9402 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -138,7 +138,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind && self.storage_to_remove.contains(l) { - stmt.make_nop(); + stmt.make_nop(true); return; } @@ -150,7 +150,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { *rhs && lhs == rhs { - stmt.make_nop(); + stmt.make_nop(true); } } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c5cd06f170c4..814eded910df 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -411,7 +411,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind && self.remap.contains(l) { - s.make_nop(); + s.make_nop(true); } } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index eea2b0990d73..a5f8a22e83c8 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -33,10 +33,9 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If the user requests complete debuginfo, mark the locals that appear in it as live, so // we don't remove assignments to them. - let mut always_live = debuginfo_locals(body); - always_live.union(&borrowed_locals); + let debuginfo_locals = debuginfo_locals(body); - let mut live = MaybeTransitiveLiveLocals::new(&always_live) + let mut live = MaybeTransitiveLiveLocals::new(&borrowed_locals, &debuginfo_locals) .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); @@ -75,35 +74,23 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() { - let loc = Location { block: bb, statement_index }; - if let StatementKind::Assign(assign) = &statement.kind { - if !assign.1.is_safe_to_remove() { - continue; - } - } - match &statement.kind { - StatementKind::Assign(box (place, _)) - | StatementKind::SetDiscriminant { place: box place, .. } - | StatementKind::Deinit(box place) => { - if !place.is_indirect() && !always_live.contains(place.local) { - live.seek_before_primary_effect(loc); - if !live.get().contains(place.local) { - patch.push(loc); - } - } - } - StatementKind::Retag(_, _) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Coverage(_) - | StatementKind::Intrinsic(_) - | StatementKind::ConstEvalCounter - | StatementKind::PlaceMention(_) - | StatementKind::BackwardIncompatibleDropHint { .. } - | StatementKind::Nop => {} - - StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { - bug!("{:?} not found in this MIR phase!", statement.kind) + if let Some(destination) = MaybeTransitiveLiveLocals::can_be_removed_if_dead( + &statement.kind, + &borrowed_locals, + &debuginfo_locals, + ) { + let loc = Location { block: bb, statement_index }; + live.seek_before_primary_effect(loc); + if !live.get().contains(destination.local) { + let drop_debuginfo = !debuginfo_locals.contains(destination.local); + // When eliminating a dead statement, we need to address + // the debug information for that statement. + assert!( + drop_debuginfo || statement.kind.as_debuginfo().is_some(), + "don't know how to retain the debug information for {:?}", + statement.kind + ); + patch.push((loc, drop_debuginfo)); } } } @@ -114,8 +101,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } let bbs = body.basic_blocks.as_mut_preserves_cfg(); - for Location { block, statement_index } in patch { - bbs[block].statements[statement_index].make_nop(); + for (Location { block, statement_index }, drop_debuginfo) in patch { + bbs[block].statements[statement_index].make_nop(drop_debuginfo); } for (block, argument_index) in call_operands_to_move { let TerminatorKind::Call { ref mut args, .. } = bbs[block].terminator_mut().kind else { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 74c22ff10c19..1f38433fa5a4 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -276,7 +276,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { StatementKind::StorageDead(local) | StatementKind::StorageLive(local) if self.merged_locals.contains(*local) => { - statement.make_nop(); + statement.make_nop(true); return; } _ => (), @@ -291,7 +291,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { // (this includes the original statement we wanted to eliminate). if dest == place { debug!("{:?} turned into self-assignment, deleting", location); - statement.make_nop(); + statement.make_nop(true); } } _ => {} diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 99691d9e045b..3ff8dc6dbb37 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1877,7 +1877,7 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) if self.reused_locals.contains(l) => { - stmt.make_nop() + stmt.make_nop(true) } _ => self.super_statement(stmt, loc), } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 1a91d6bd7da9..1b90e9158f6b 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -156,7 +156,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt { patch.add_statement(location, stmt); } - st.make_nop(); + st.make_nop(true); } } diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index cc8ea76011bf..2c535d011a0e 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -270,7 +270,7 @@ impl<'tcx> MirPatch<'tcx> { body.local_decls.extend(self.new_locals); for loc in self.nop_statements { - bbs[loc.block].statements[loc.statement_index].make_nop(); + bbs[loc.block].statements[loc.statement_index].make_nop(true); } let mut new_statements = self.new_statements; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 48ddf5a1bcab..c7dc18a4a134 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -1049,7 +1049,7 @@ fn promote_candidates<'tcx>( // Eliminate assignments to, and drops of promoted temps. let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in body.basic_blocks_mut() { - block.statements.retain(|statement| match &statement.kind { + block.retain_statements(|statement| match &statement.kind { StatementKind::Assign(box (place, _)) => { if let Some(index) = place.as_local() { !promoted(index) diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index b9d6e74ecae8..deb0a146476c 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -435,7 +435,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) if self.storage_to_remove.contains(l) => { - stmt.make_nop(); + stmt.make_nop(true); } // Do not remove assignments as they may still be useful for debuginfo. _ => self.super_statement(stmt, loc), diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs index cb598ceb4dfe..d56b51bb496e 100644 --- a/compiler/rustc_mir_transform/src/remove_place_mention.rs +++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs @@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention { fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemovePlaceMention on {:?}", body.source); for data in body.basic_blocks.as_mut_preserves_cfg() { - data.statements.retain(|statement| match statement.kind { + data.retain_statements(|statement| match statement.kind { StatementKind::PlaceMention(..) | StatementKind::Nop => false, _ => true, }) diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index 1ae33c009687..cb97d2c865ac 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running RemoveStorageMarkers on {:?}", body.source); for data in body.basic_blocks.as_mut_preserves_cfg() { - data.statements.retain(|statement| match statement.kind { + data.retain_statements(|statement| match statement.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Nop => false, diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index c4dc8638b26a..90c1b3520b96 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -141,7 +141,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty && self.known_to_be_zst(ty) { - statement.make_nop(); + statement.make_nop(true); } else { self.super_statement(statement, loc); } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 75917d23883b..9f7bb3b03795 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -36,7 +36,9 @@ use itertools::Itertools as _; use rustc_index::{Idx, IndexSlice, IndexVec}; -use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{ + MutVisitor, MutatingUseContext, NonUseContext, PlaceContext, Visitor, +}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_span::DUMMY_SP; @@ -303,7 +305,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + blk.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) } } } @@ -539,12 +541,20 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { self.super_statement(statement, location); } - StatementKind::ConstEvalCounter | StatementKind::Nop => {} - - StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {} + StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) => { + for debuginfo in statement.debuginfos.iter() { + self.visit_statement_debuginfo(debuginfo, location); + } + } StatementKind::Assign(box (ref place, ref rvalue)) => { if rvalue.is_safe_to_remove() { + for debuginfo in statement.debuginfos.iter() { + self.visit_statement_debuginfo(debuginfo, location); + } self.visit_lhs(place, location); self.visit_rvalue(rvalue, location); } else { @@ -555,15 +565,18 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::SetDiscriminant { ref place, variant_index: _ } | StatementKind::Deinit(ref place) | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { + for debuginfo in statement.debuginfos.iter() { + self.visit_statement_debuginfo(debuginfo, location); + } self.visit_lhs(place, location); } } } - fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) { + fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) { if self.increment { self.use_count[local] += 1; - } else { + } else if ctx != PlaceContext::NonUse(NonUseContext::VarDebugInfo) { assert_ne!(self.use_count[local], 0); self.use_count[local] -= 1; } @@ -583,7 +596,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. - data.statements.retain(|statement| { + data.retain_statements(|statement| { let keep = match &statement.kind { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { used_locals.is_used(*local) diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index c60eb566521c..4597439e269f 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { // delete comparison statement if it the value being switched on was moved, which means // it can not be user later on if opt.can_remove_bin_op_stmt { - bb.statements[opt.bin_op_stmt_idx].make_nop(); + bb.statements[opt.bin_op_stmt_idx].make_nop(true); } else { // if the integer being compared to a const integral is being moved into the // comparison, e.g `_2 = Eq(move _3, const 'x');` @@ -136,7 +136,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { } for (idx, bb_idx) in storage_deads_to_remove { - body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(); + body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(true); } for (idx, stmt) in storage_deads_to_insert { diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 38769885f368..99f10b8d91d2 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -318,7 +318,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageLive(fl)); } - statement.make_nop(); + statement.make_nop(true); } return; } @@ -327,7 +327,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageDead(fl)); } - statement.make_nop(); + statement.make_nop(true); } return; } @@ -337,7 +337,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.patch .add_statement(location, StatementKind::Deinit(Box::new(fl.into()))); } - statement.make_nop(); + statement.make_nop(true); return; } } @@ -367,7 +367,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { ); } } - statement.make_nop(); + statement.make_nop(true); return; } } @@ -429,7 +429,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { StatementKind::Assign(Box::new((new_local.into(), rvalue))), ); } - statement.make_nop(); + statement.make_nop(true); return; } } diff --git a/tests/codegen-llvm/debug-fndef-size.rs b/tests/codegen-llvm/debug-fndef-size.rs index 8f716c34e7b7..02629bd748c4 100644 --- a/tests/codegen-llvm/debug-fndef-size.rs +++ b/tests/codegen-llvm/debug-fndef-size.rs @@ -16,5 +16,5 @@ pub fn main() { // CHECK: %compare.dbg.spill = alloca [0 x i8], align 1 // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression() -// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) -// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) +// CHECK-DAG: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}}) +// CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8) diff --git a/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff new file mode 100644 index 000000000000..d823241bc620 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff @@ -0,0 +1,31 @@ +- // MIR for `dead_first` before DeadStoreElimination-initial ++ // MIR for `dead_first` after DeadStoreElimination-initial + + fn dead_first(_1: &Foo) -> &i32 { + debug v => _1; + let mut _0: &i32; + let mut _2: &i32; + let mut _3: &i32; + let _4: &i32; + scope 1 { + debug a => _2; + } + + bb0: { + StorageLive(_2); +- _2 = &((*_1).2: i32); ++ // DBG: _2 = &((*_1).2: i32); ++ nop; + StorageLive(_3); + StorageLive(_4); + _4 = &((*_1).0: i32); + _3 = &(*_4); + _2 = move _3; + StorageDead(_3); + StorageDead(_4); + _0 = &(*_2); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs new file mode 100644 index 000000000000..18d9ea8b84d7 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.rs @@ -0,0 +1,33 @@ +//@ test-mir-pass: DeadStoreElimination-initial + +pub struct Foo { + a: i32, + b: i64, + c: i32, +} + +// EMIT_MIR ref.tuple.DeadStoreElimination-initial.diff +pub fn tuple(v: (i32, &Foo)) -> i32 { + // CHECK-LABEL: fn tuple + // CHECK: debug _dead => [[dead:_[0-9]+]]; + // CHECK: bb0: + // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo. + // CHECK: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); + // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32) + let _dead = &v.1.c; + v.1.a +} + +// EMIT_MIR ref.dead_first.DeadStoreElimination-initial.diff +pub fn dead_first(v: &Foo) -> &i32 { + // CHECK-LABEL: fn dead_first + // CHECK: debug a => [[var_a:_[0-9]+]]; + // CHECK: bb0: + // CHECK: DBG: [[var_a]] = &((*_1).2: i32) + // CHECK: [[tmp_4:_[0-9]+]] = &((*_1).0: i32) + // CHECK: [[tmp_3:_[0-9]+]] = &(*[[tmp_4]]) + // CHECK: [[var_a]] = move [[tmp_3]] + let mut a = &v.c; + a = &v.a; + a +} diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff new file mode 100644 index 000000000000..0547a42cab24 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -0,0 +1,26 @@ +- // MIR for `tuple` before DeadStoreElimination-initial ++ // MIR for `tuple` after DeadStoreElimination-initial + + fn tuple(_1: (i32, &Foo)) -> i32 { + debug v => _1; + let mut _0: i32; + let _2: &i32; + let mut _3: &Foo; + let mut _4: &Foo; + scope 1 { + debug _dead => _2; + } + + bb0: { + StorageLive(_2); + _3 = deref_copy (_1.1: &Foo); +- _2 = &((*_3).2: i32); ++ // DBG: _2 = &((*_3).2: i32); ++ nop; + _4 = deref_copy (_1.1: &Foo); + _0 = copy ((*_4).0: i32); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff new file mode 100644 index 000000000000..d4a73351ee4a --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -0,0 +1,26 @@ +- // MIR for `drop_debuginfo` before SimplifyCfg-final ++ // MIR for `drop_debuginfo` after SimplifyCfg-final + + fn drop_debuginfo(_1: &Foo, _2: bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + + bb0: { +- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; +- } +- +- bb1: { +- // DBG: _3 = &((*_1).0: i32); +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64); + _0 = copy ((*_1).2: i32); + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff new file mode 100644 index 000000000000..1c12358ad893 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -0,0 +1,30 @@ +- // MIR for `preserve_debuginfo_1` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_1` after SimplifyCfg-final + + fn preserve_debuginfo_1(_1: &Foo, _2: &mut bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + debug foo_c => _5; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + let mut _5: &i32; + + bb0: { +- goto -> bb1; +- } +- +- bb1: { + (*_2) = const true; + // DBG: _3 = &((*_1).0: i32); +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64); + _0 = copy ((*_1).2: i32); + // DBG: _5 = &((*_1).2: i32); + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff new file mode 100644 index 000000000000..de8e5612c878 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -0,0 +1,29 @@ +- // MIR for `preserve_debuginfo_2` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_2` after SimplifyCfg-final + + fn preserve_debuginfo_2(_1: &Foo) -> i32 { + debug foo_a => _2; + debug foo_b => _3; + debug foo_c => _4; + let mut _0: i32; + let mut _2: &i32; + let mut _3: &i64; + let mut _4: &i32; + + bb0: { +- goto -> bb1; +- } +- +- bb1: { + // DBG: _2 = &((*_1).0: i32); +- goto -> bb2; +- } +- +- bb2: { + // DBG: _3 = &((*_1).1: i64); + _0 = copy ((*_1).2: i32); + // DBG: _4 = &((*_1).2: i32); + return; + } + } + diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index f6c111a2228a..f7729c7c5fa6 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -16,10 +16,12 @@ + let mut _9: *mut A; + let mut _10: usize; + scope 3 (inlined Vec::::as_mut_ptr) { ++ let mut _11: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { ++ let mut _12: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { -+ let mut _11: std::ptr::NonNull; ++ let mut _13: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + scope 8 (inlined NonNull::::cast::) { + scope 9 (inlined NonNull::::as_ptr) { @@ -39,15 +41,15 @@ + } + } + scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) { -+ let mut _12: usize; -+ let mut _13: *mut A; -+ let mut _14: bool; ++ let mut _14: usize; ++ let mut _15: *mut A; ++ let mut _16: bool; + } + } + } + scope 15 (inlined drop_in_place::> - shim(Some(Option))) { -+ let mut _15: isize; -+ let mut _16: isize; ++ let mut _17: isize; ++ let mut _18: isize; + } bb0: { @@ -62,16 +64,22 @@ + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); -+ _11 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); -+ _9 = copy _11 as *mut A (Transmute); ++ // DBG: _11 = &((*_6).0: alloc::raw_vec::RawVec); ++ StorageLive(_12); ++ // DBG: _12 = &(((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); ++ StorageLive(_13); ++ _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); ++ _9 = copy _13 as *mut A (Transmute); ++ StorageDead(_13); ++ StorageDead(_12); + StorageDead(_11); + _10 = copy ((*_6).1: usize); + _8 = *mut [A] from (copy _9, copy _10); + StorageDead(_9); -+ StorageLive(_12); -+ StorageLive(_13); + StorageLive(_14); -+ _12 = const 0_usize; ++ StorageLive(_15); ++ StorageLive(_16); ++ _14 = const 0_usize; + goto -> bb4; } @@ -83,35 +91,35 @@ StorageLive(_5); _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_15); -+ StorageLive(_16); -+ _15 = discriminant((*_5)); -+ switchInt(move _15) -> [0: bb5, otherwise: bb6]; ++ StorageLive(_17); ++ StorageLive(_18); ++ _17 = discriminant((*_5)); ++ switchInt(move _17) -> [0: bb5, otherwise: bb6]; } bb2: { ++ StorageDead(_16); ++ StorageDead(_15); + StorageDead(_14); -+ StorageDead(_13); -+ StorageDead(_12); + StorageDead(_8); + StorageDead(_10); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ _13 = &raw mut (*_8)[_12]; -+ _12 = Add(move _12, const 1_usize); -+ drop((*_13)) -> [return: bb4, unwind unreachable]; ++ _15 = &raw mut (*_8)[_14]; ++ _14 = Add(move _14, const 1_usize); ++ drop((*_15)) -> [return: bb4, unwind unreachable]; + } + + bb4: { -+ _14 = Eq(copy _12, copy _10); -+ switchInt(move _14) -> [0: bb3, otherwise: bb2]; ++ _16 = Eq(copy _14, copy _10); ++ switchInt(move _16) -> [0: bb3, otherwise: bb2]; + } + + bb5: { -+ StorageDead(_16); -+ StorageDead(_15); ++ StorageDead(_18); ++ StorageDead(_17); StorageDead(_5); return; + } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 2ae86e2eb8bb..649b5a652027 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -228,12 +228,12 @@ + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); -+ _45 = &mut _19; ++ // DBG: _45 = &_19; + StorageLive(_46); -+ _46 = &mut (_19.0: &mut std::future::Ready<()>); ++ // DBG: _46 = &(_19.0: &mut std::future::Ready<()>); + _44 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_46); -+ _43 = &mut ((*_44).0: std::option::Option<()>); ++ // DBG: _43 = &((*_44).0: std::option::Option<()>); + StorageLive(_47); + _47 = Option::<()>::None; + _42 = copy ((*_44).0: std::option::Option<()>); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index d7ae931aaae5..32021b20ef44 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -245,12 +245,12 @@ + StorageLive(_43); + StorageLive(_44); + StorageLive(_45); -+ _47 = &mut _19; ++ // DBG: _47 = &_19; + StorageLive(_48); -+ _48 = &mut (_19.0: &mut std::future::Ready<()>); ++ // DBG: _48 = &(_19.0: &mut std::future::Ready<()>); + _46 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_48); -+ _45 = &mut ((*_46).0: std::option::Option<()>); ++ // DBG: _45 = &((*_46).0: std::option::Option<()>); + StorageLive(_49); + _49 = Option::<()>::None; + _44 = copy ((*_46).0: std::option::Option<()>); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index 5cf36b9aebf2..a294c1b4588d 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -34,11 +34,11 @@ bb2: { StorageLive(_5); - _5 = &(*_2)[0 of 3]; + // DBG: _5 = &(*_2)[0 of 3]; StorageLive(_6); - _6 = &(*_2)[1 of 3]; + // DBG: _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[2 of 3]; + // DBG: _7 = &(*_2)[2 of 3]; StorageDead(_7); StorageDead(_6); StorageDead(_5); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index 0598a3aa3f19..691271cf94ed 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -34,11 +34,11 @@ bb2: { StorageLive(_5); - _5 = &(*_2)[0 of 3]; + // DBG: _5 = &(*_2)[0 of 3]; StorageLive(_6); - _6 = &(*_2)[1 of 3]; + // DBG: _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[2 of 3]; + // DBG: _7 = &(*_2)[2 of 3]; StorageDead(_7); StorageDead(_6); StorageDead(_5); diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index b5c23822162c..d4248f5d87fb 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -20,14 +21,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { + // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index f22b8835735d..a834932df5a8 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -20,14 +21,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { + // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index b5c23822162c..d4248f5d87fb 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -20,14 +21,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { + // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index f22b8835735d..a834932df5a8 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -6,6 +6,7 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; + let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -20,14 +21,17 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { + StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { + // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); + StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 83478e60b5d4..23dbc066dd52 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -5,7 +5,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let mut _8: u16; + let _8: std::option::Option; + let mut _10: u16; + let mut _11: &std::option::Option; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -13,8 +15,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; + let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _7: (); + let _9: (); } } } @@ -35,6 +38,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); + StorageLive(_11); + StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -53,34 +58,55 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); + StorageLive(_7); + _7 = AddUnchecked(copy _1, copy _4); + _8 = Option::::Some(move _7); + StorageDead(_7); + // DBG: _11 = &_8; + StorageDead(_8); + StorageDead(_11); goto -> bb7; } bb3: { - _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); + _8 = const Option::::None; + // DBG: _11 = &_8; goto -> bb6; } bb5: { StorageDead(_3); + _8 = const Option::::None; + // DBG: _11 = &_8; goto -> bb6; } bb6: { + StorageDead(_8); + StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind unreachable]; } bb7: { - StorageLive(_8); - _8 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _8); - StorageDead(_8); + StorageLive(_10); + _10 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _10); + StorageDead(_10); StorageDead(_4); return; } } + +ALLOC0 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} + +ALLOC1 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index ac7a6e044519..ac15f070597e 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -5,7 +5,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let mut _8: u16; + let _8: std::option::Option; + let mut _10: u16; + let mut _11: &std::option::Option; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -13,8 +15,9 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; + let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _7: (); + let _9: (); } } } @@ -35,6 +38,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); + StorageLive(_11); + StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -53,34 +58,55 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); + StorageLive(_7); + _7 = AddUnchecked(copy _1, copy _4); + _8 = Option::::Some(move _7); + StorageDead(_7); + // DBG: _11 = &_8; + StorageDead(_8); + StorageDead(_11); goto -> bb7; } bb3: { - _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); + _8 = const Option::::None; + // DBG: _11 = &_8; goto -> bb6; } bb5: { StorageDead(_3); + _8 = const Option::::None; + // DBG: _11 = &_8; goto -> bb6; } bb6: { + StorageDead(_8); + StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind continue]; } bb7: { - StorageLive(_8); - _8 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _8); - StorageDead(_8); + StorageLive(_10); + _10 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _10); + StorageDead(_10); StorageDead(_4); return; } } + +ALLOC0 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} + +ALLOC1 (size: 4, align: 2) { + 00 00 __ __ │ ..░░ +} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir index 34747e5a9285..66239a0ef663 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir @@ -13,7 +13,7 @@ fn clone_as_copy(_1: &NestCopy) -> NestCopy { bb0: { StorageLive(_2); - _2 = &((*_1).1: AllCopy); + // DBG: _2 = &((*_1).1: AllCopy); _0 = copy (*_1); StorageDead(_2); return; diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir index e67f362ee04a..aa03cec070ad 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir @@ -35,15 +35,15 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { } bb1: { - _3 = &(((*_1) as A).0: AllCopy); + // DBG: _3 = &(((*_1) as A).0: AllCopy); _0 = copy (*_1); goto -> bb3; } bb2: { - _4 = &(((*_1) as B).0: NestCopy); + // DBG: _4 = &(((*_1) as B).0: NestCopy); StorageLive(_5); - _5 = &((((*_1) as B).0: NestCopy).1: AllCopy); + // DBG: _5 = &((((*_1) as B).0: NestCopy).1: AllCopy); StorageDead(_5); _0 = copy (*_1); goto -> bb3; diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index ba6ce0ee5286..0dd2125dbe0d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -8,9 +8,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _11: (); + let _12: (); + let mut _13: &std::alloc::Layout; scope 3 { - let _8: std::ptr::alignment::AlignmentEnum; + let _8: std::alloc::Layout; scope 4 { scope 12 (inlined Layout::size) { } @@ -26,15 +27,19 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; + let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; + let mut _11: usize; + let mut _15: &std::alloc::Layout; + let mut _16: &std::alloc::Layout; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { + let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -63,6 +68,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { + StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -74,31 +80,45 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); + _8 = Layout { size: copy _5, align: copy _7 }; StorageDead(_6); StorageDead(_4); + StorageLive(_13); + // DBG: _13 = &_8; + StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_14); + // DBG: _14 = &_8; + StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_15); + // DBG: _15 = &_8; + StorageDead(_15); + StorageLive(_11); + StorageLive(_16); + // DBG: _16 = &_8; StorageLive(_10); - _10 = discriminant(_8); - _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; + _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _11 = discriminant(_10); + StorageDead(_10); + StorageDead(_16); + _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_10); + StorageDead(_11); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); + StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index ba6ce0ee5286..0dd2125dbe0d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -8,9 +8,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _11: (); + let _12: (); + let mut _13: &std::alloc::Layout; scope 3 { - let _8: std::ptr::alignment::AlignmentEnum; + let _8: std::alloc::Layout; scope 4 { scope 12 (inlined Layout::size) { } @@ -26,15 +27,19 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; + let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; + let mut _11: usize; + let mut _15: &std::alloc::Layout; + let mut _16: &std::alloc::Layout; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { + let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -63,6 +68,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { + StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -74,31 +80,45 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); + _8 = Layout { size: copy _5, align: copy _7 }; StorageDead(_6); StorageDead(_4); + StorageLive(_13); + // DBG: _13 = &_8; + StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_14); + // DBG: _14 = &_8; + StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_15); + // DBG: _15 = &_8; + StorageDead(_15); + StorageLive(_11); + StorageLive(_16); + // DBG: _16 = &_8; StorageLive(_10); - _10 = discriminant(_8); - _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; + _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _11 = discriminant(_10); + StorageDead(_10); + StorageDead(_16); + _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_10); + StorageDead(_11); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); + StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index ba6ce0ee5286..0dd2125dbe0d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -8,9 +8,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _11: (); + let _12: (); + let mut _13: &std::alloc::Layout; scope 3 { - let _8: std::ptr::alignment::AlignmentEnum; + let _8: std::alloc::Layout; scope 4 { scope 12 (inlined Layout::size) { } @@ -26,15 +27,19 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; + let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; + let mut _11: usize; + let mut _15: &std::alloc::Layout; + let mut _16: &std::alloc::Layout; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { + let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -63,6 +68,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { + StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -74,31 +80,45 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); + _8 = Layout { size: copy _5, align: copy _7 }; StorageDead(_6); StorageDead(_4); + StorageLive(_13); + // DBG: _13 = &_8; + StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_14); + // DBG: _14 = &_8; + StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_15); + // DBG: _15 = &_8; + StorageDead(_15); + StorageLive(_11); + StorageLive(_16); + // DBG: _16 = &_8; StorageLive(_10); - _10 = discriminant(_8); - _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; + _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _11 = discriminant(_10); + StorageDead(_10); + StorageDead(_16); + _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_10); + StorageDead(_11); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); + StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index ba6ce0ee5286..0dd2125dbe0d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -8,9 +8,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _11: (); + let _12: (); + let mut _13: &std::alloc::Layout; scope 3 { - let _8: std::ptr::alignment::AlignmentEnum; + let _8: std::alloc::Layout; scope 4 { scope 12 (inlined Layout::size) { } @@ -26,15 +27,19 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; + let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; + let mut _11: usize; + let mut _15: &std::alloc::Layout; + let mut _16: &std::alloc::Layout; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { + let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -63,6 +68,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { + StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -74,31 +80,45 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); - StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); - StorageDead(_7); + _8 = Layout { size: copy _5, align: copy _7 }; StorageDead(_6); StorageDead(_4); + StorageLive(_13); + // DBG: _13 = &_8; + StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { + StorageLive(_14); + // DBG: _14 = &_8; + StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_15); + // DBG: _15 = &_8; + StorageDead(_15); + StorageLive(_11); + StorageLive(_16); + // DBG: _16 = &_8; StorageLive(_10); - _10 = discriminant(_8); - _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; + _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _11 = discriminant(_10); + StorageDead(_10); + StorageDead(_16); + _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_10); + StorageDead(_11); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); + StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 9ceba9444b8d..c291366a694e 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -11,7 +11,7 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]> // CHECK: [[ALIGN:_.+]] = AlignOf(T); // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); - // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); + // CHECK: [[C:_.+]] = copy ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 75e8cb1d8618..8f30ad30fccd 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -6,20 +6,20 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () let mut _0: (); let mut _3: std::iter::FilterMap, impl Fn(T) -> Option>; let mut _4: std::iter::FilterMap, impl Fn(T) -> Option>; - let mut _5: &mut std::iter::FilterMap, impl Fn(T) -> Option>; - let mut _8: std::option::Option; - let mut _9: isize; - let _11: (); + let mut _7: std::option::Option; + let mut _8: isize; + let _10: (); + let mut _11: &mut std::iter::FilterMap, impl Fn(T) -> Option>; scope 1 { debug iter => _4; - let _10: U; + let _9: U; scope 2 { - debug x => _10; + debug x => _9; } scope 4 (inlined , impl Fn(T) -> Option> as Iterator>::next) { - debug self => _5; - let mut _6: &mut impl Iterator; - let mut _7: &mut impl Fn(T) -> Option; + debug self => _11; + let mut _5: &mut impl Iterator; + let mut _6: &mut impl Fn(T) -> Option; } } scope 3 (inlined , impl Fn(T) -> Option> as IntoIterator>::into_iter) { @@ -37,24 +37,24 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () } bb2: { - StorageLive(_8); - _5 = &mut _4; - StorageLive(_6); - _6 = &mut (_4.0: impl Iterator); StorageLive(_7); - _7 = &mut (_4.1: impl Fn(T) -> Option); - _8 = as Iterator>::find_map:: Option>(move _6, move _7) -> [return: bb3, unwind: bb9]; + // DBG: _11 = &_4; + StorageLive(_5); + _5 = &mut (_4.0: impl Iterator); + StorageLive(_6); + _6 = &mut (_4.1: impl Fn(T) -> Option); + _7 = as Iterator>::find_map:: Option>(move _5, move _6) -> [return: bb3, unwind: bb9]; } bb3: { - StorageDead(_7); StorageDead(_6); - _9 = discriminant(_8); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_5); + _8 = discriminant(_7); + switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb8]; } bb4: { - StorageDead(_8); + StorageDead(_7); drop(_4) -> [return: bb5, unwind continue]; } @@ -64,12 +64,12 @@ fn filter_mapped(_1: impl Iterator, _2: impl Fn(T) -> Option) -> () } bb6: { - _10 = move ((_8 as Some).0: U); - _11 = opaque::(move _10) -> [return: bb7, unwind: bb9]; + _9 = move ((_7 as Some).0: U); + _10 = opaque::(move _9) -> [return: bb7, unwind: bb9]; } bb7: { - StorageDead(_8); + StorageDead(_7); goto -> bb2; } diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index 154cbd3791cb..b1af3141ee61 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -5,32 +5,31 @@ fn int_range(_1: usize, _2: usize) -> () { debug end => _2; let mut _0: (); let mut _3: std::ops::Range; - let mut _4: std::ops::Range; - let mut _5: &mut std::ops::Range; - let mut _13: std::option::Option; - let _15: (); + let mut _9: std::option::Option; + let _11: (); + let mut _12: &mut std::ops::Range; scope 1 { - debug iter => _4; - let _14: usize; + debug iter => _3; + let _10: usize; scope 2 { - debug i => _14; + debug i => _10; } scope 4 (inlined iter::range::>::next) { - debug self => _5; + debug self => _12; scope 5 (inlined as iter::range::RangeIteratorImpl>::spec_next) { - debug self => _5; - let mut _6: &usize; - let mut _7: &usize; - let mut _10: bool; - let _11: usize; - let mut _12: usize; + debug self => _12; + let mut _6: bool; + let _7: usize; + let mut _8: usize; + let mut _13: &usize; + let mut _14: &usize; scope 6 { - debug old => _11; + debug old => _7; scope 8 (inlined ::forward_unchecked) { - debug start => _11; + debug start => _7; debug n => const 1_usize; scope 9 (inlined #[track_caller] core::num::::unchecked_add) { - debug self => _11; + debug self => _7; debug rhs => const 1_usize; scope 10 (inlined core::ub_checks::check_language_ub) { scope 11 (inlined core::ub_checks::check_language_ub::runtime) { @@ -40,10 +39,10 @@ fn int_range(_1: usize, _2: usize) -> () { } } scope 7 (inlined std::cmp::impls::::lt) { - debug self => _6; - debug other => _7; - let mut _8: usize; - let mut _9: usize; + debug self => _13; + debug other => _14; + let mut _4: usize; + let mut _5: usize; } } } @@ -54,54 +53,51 @@ fn int_range(_1: usize, _2: usize) -> () { bb0: { _3 = std::ops::Range:: { start: copy _1, end: copy _2 }; - StorageLive(_4); - _4 = copy _3; goto -> bb1; } bb1: { - StorageLive(_13); - _5 = &mut _4; - StorageLive(_10); - StorageLive(_6); - _6 = &(_4.0: usize); - StorageLive(_7); - _7 = &(_4.1: usize); - StorageLive(_8); - _8 = copy (_4.0: usize); StorageLive(_9); - _9 = copy (_4.1: usize); - _10 = Lt(move _8, move _9); - StorageDead(_9); - StorageDead(_8); - switchInt(move _10) -> [0: bb2, otherwise: bb3]; + // DBG: _12 = &_3; + StorageLive(_6); + StorageLive(_13); + // DBG: _13 = &(_3.0: usize); + StorageLive(_14); + // DBG: _14 = &(_3.1: usize); + StorageLive(_4); + _4 = copy (_3.0: usize); + StorageLive(_5); + _5 = copy (_3.1: usize); + _6 = Lt(move _4, move _5); + StorageDead(_5); + StorageDead(_4); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - StorageDead(_7); - StorageDead(_6); - StorageDead(_10); + StorageDead(_14); StorageDead(_13); - StorageDead(_4); + StorageDead(_6); + StorageDead(_9); return; } bb3: { - StorageDead(_7); + StorageDead(_14); + StorageDead(_13); + _7 = copy (_3.0: usize); + StorageLive(_8); + _8 = AddUnchecked(copy _7, const 1_usize); + (_3.0: usize) = move _8; + StorageDead(_8); + _9 = Option::::Some(copy _7); StorageDead(_6); - _11 = copy (_4.0: usize); - StorageLive(_12); - _12 = AddUnchecked(copy _11, const 1_usize); - (_4.0: usize) = move _12; - StorageDead(_12); - _13 = Option::::Some(copy _11); - StorageDead(_10); - _14 = copy ((_13 as Some).0: usize); - _15 = opaque::(move _14) -> [return: bb4, unwind continue]; + _10 = copy ((_9 as Some).0: usize); + _11 = opaque::(move _10) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_13); + StorageDead(_9); goto -> bb1; } } diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index d22ea54004c9..406c96fc32f4 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -6,32 +6,32 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { let mut _0: (); let mut _3: std::iter::Map, impl Fn(T) -> U>; let mut _4: std::iter::Map, impl Fn(T) -> U>; - let mut _5: &mut std::iter::Map, impl Fn(T) -> U>; - let mut _13: std::option::Option; - let _15: (); + let mut _12: std::option::Option; + let _14: (); + let mut _15: &mut std::iter::Map, impl Fn(T) -> U>; scope 1 { debug iter => _4; - let _14: U; + let _13: U; scope 2 { - debug x => _14; + debug x => _13; } scope 4 (inlined , impl Fn(T) -> U> as Iterator>::next) { - debug self => _5; - let mut _6: &mut impl Iterator; - let mut _7: std::option::Option; - let mut _8: &mut impl Fn(T) -> U; + debug self => _15; + let mut _5: &mut impl Iterator; + let mut _6: std::option::Option; + let mut _7: &mut impl Fn(T) -> U; scope 5 (inlined Option::::map:: U>) { - debug self => _7; - debug f => _8; - let mut _9: isize; - let _10: T; - let mut _11: (T,); - let mut _12: U; + debug self => _6; + debug f => _7; + let mut _8: isize; + let _9: T; + let mut _10: (T,); + let mut _11: U; scope 6 { - debug x => _10; + debug x => _9; scope 7 (inlined ops::function::impls:: for &mut impl Fn(T) -> U>::call_once) { - debug self => _8; - debug args => _11; + debug self => _7; + debug args => _10; } } } @@ -52,30 +52,30 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { } bb2: { - StorageLive(_13); - _5 = &mut _4; - StorageLive(_8); + StorageLive(_12); + // DBG: _15 = &_4; StorageLive(_7); StorageLive(_6); - _6 = &mut (_4.0: impl Iterator); - _7 = as Iterator>::next(move _6) -> [return: bb3, unwind: bb10]; + StorageLive(_5); + _5 = &mut (_4.0: impl Iterator); + _6 = as Iterator>::next(move _5) -> [return: bb3, unwind: bb10]; } bb3: { - StorageDead(_6); - _8 = &mut (_4.1: impl Fn(T) -> U); + StorageDead(_5); + _7 = &mut (_4.1: impl Fn(T) -> U); + StorageLive(_8); StorageLive(_9); - StorageLive(_10); - _9 = discriminant(_7); - switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb9]; + _8 = discriminant(_6); + switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb9]; } bb4: { - StorageDead(_10); StorageDead(_9); - StorageDead(_7); StorageDead(_8); - StorageDead(_13); + StorageDead(_6); + StorageDead(_7); + StorageDead(_12); drop(_4) -> [return: bb5, unwind continue]; } @@ -85,27 +85,27 @@ fn mapped(_1: impl Iterator, _2: impl Fn(T) -> U) -> () { } bb6: { - _10 = move ((_7 as Some).0: T); - StorageLive(_12); + _9 = move ((_6 as Some).0: T); StorageLive(_11); - _11 = (copy _10,); - _12 = U as FnMut<(T,)>>::call_mut(move _8, move _11) -> [return: bb7, unwind: bb10]; + StorageLive(_10); + _10 = (copy _9,); + _11 = U as FnMut<(T,)>>::call_mut(move _7, move _10) -> [return: bb7, unwind: bb10]; } bb7: { - StorageDead(_11); - _13 = Option::::Some(move _12); - StorageDead(_12); StorageDead(_10); + _12 = Option::::Some(move _11); + StorageDead(_11); StorageDead(_9); - StorageDead(_7); StorageDead(_8); - _14 = move ((_13 as Some).0: U); - _15 = opaque::(move _14) -> [return: bb8, unwind: bb10]; + StorageDead(_6); + StorageDead(_7); + _13 = move ((_12 as Some).0: U); + _14 = opaque::(move _13) -> [return: bb8, unwind: bb10]; } bb8: { - StorageDead(_13); + StorageDead(_12); goto -> bb2; } diff --git a/tests/mir-opt/pre-codegen/loops.rs b/tests/mir-opt/pre-codegen/loops.rs index d0b8cc8db7a9..952dd8cac60f 100644 --- a/tests/mir-opt/pre-codegen/loops.rs +++ b/tests/mir-opt/pre-codegen/loops.rs @@ -1,5 +1,6 @@ // skip-filecheck //@ compile-flags: -O -Zmir-opt-level=2 -g +//@ ignore-std-debug-assertions (debug assertions result in different inlines) //@ needs-unwind #![crate_type = "lib"] diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir index e537dd6a28ef..03cdc221c308 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir @@ -3,72 +3,354 @@ fn vec_move(_1: Vec) -> () { debug v => _1; let mut _0: (); - let mut _2: std::vec::IntoIter; - let mut _3: std::vec::IntoIter; - let mut _4: &mut std::vec::IntoIter; - let mut _5: std::option::Option; - let mut _6: isize; - let _8: (); + let mut _22: std::vec::IntoIter; + let mut _23: std::vec::IntoIter; + let mut _24: &mut std::vec::IntoIter; + let mut _25: std::option::Option; + let mut _26: isize; + let _28: (); scope 1 { - debug iter => _3; - let _7: impl Sized; + debug iter => _23; + let _27: impl Sized; scope 2 { - debug x => _7; + debug x => _27; + } + } + scope 3 (inlined as IntoIterator>::into_iter) { + debug self => _1; + let _2: std::mem::ManuallyDrop>; + let mut _3: *const std::alloc::Global; + let mut _8: usize; + let mut _10: *mut impl Sized; + let mut _11: *const impl Sized; + let mut _12: usize; + let _29: &std::vec::Vec; + let mut _30: &std::mem::ManuallyDrop>; + let mut _31: &alloc::raw_vec::RawVec; + let mut _32: &std::mem::ManuallyDrop>; + let _33: &std::vec::Vec; + let mut _34: &std::mem::ManuallyDrop>; + let _35: &std::vec::Vec; + let mut _36: &std::mem::ManuallyDrop>; + let mut _37: &alloc::raw_vec::RawVec; + let mut _38: &std::mem::ManuallyDrop>; + scope 4 { + debug me => _2; + scope 5 { + debug alloc => const ManuallyDrop:: {{ value: std::alloc::Global }}; + let _6: std::ptr::NonNull; + scope 6 { + debug buf => _6; + let _7: *mut impl Sized; + scope 7 { + debug begin => _7; + scope 8 { + debug end => _11; + let _20: usize; + scope 9 { + debug cap => _20; + } + scope 39 (inlined > as Deref>::deref) { + debug self => _38; + } + scope 40 (inlined alloc::raw_vec::RawVec::::capacity) { + debug self => _37; + let mut _19: usize; + let mut _42: &alloc::raw_vec::RawVecInner; + scope 41 (inlined std::mem::size_of::) { + } + scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) { + debug self => _42; + debug elem_size => _19; + let mut _21: core::num::niche_types::UsizeNoHighBit; + scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { + debug self => _21; + } + } + } + } + scope 25 (inlined > as Deref>::deref) { + debug self => _34; + } + scope 26 (inlined Vec::::len) { + debug self => _33; + let mut _13: bool; + scope 27 { + } + } + scope 28 (inlined std::ptr::mut_ptr::::wrapping_byte_add) { + debug self => _7; + debug count => _12; + let mut _14: *mut u8; + let mut _18: *mut u8; + scope 29 (inlined std::ptr::mut_ptr::::cast::) { + debug self => _7; + } + scope 30 (inlined std::ptr::mut_ptr::::wrapping_add) { + debug self => _14; + debug count => _12; + let mut _15: isize; + scope 31 (inlined std::ptr::mut_ptr::::wrapping_offset) { + debug self => _14; + debug count => _15; + let mut _16: *const u8; + let mut _17: *const u8; + } + } + scope 32 (inlined std::ptr::mut_ptr::::with_metadata_of::) { + debug self => _18; + debug meta => _5; + scope 33 (inlined std::ptr::metadata::) { + debug ptr => _5; + } + scope 34 (inlined std::ptr::from_raw_parts_mut::) { + } + } + } + scope 35 (inlined > as Deref>::deref) { + debug self => _36; + } + scope 36 (inlined Vec::::len) { + debug self => _35; + let mut _9: bool; + scope 37 { + } + } + scope 38 (inlined #[track_caller] std::ptr::mut_ptr::::add) { + debug self => _7; + debug count => _8; + } + } + scope 24 (inlined NonNull::::as_ptr) { + debug self => _6; + } + } + scope 17 (inlined > as Deref>::deref) { + debug self => _32; + } + scope 18 (inlined alloc::raw_vec::RawVec::::non_null) { + debug self => _31; + let mut _41: &alloc::raw_vec::RawVecInner; + scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _4: std::ptr::NonNull; + scope 20 (inlined Unique::::cast::) { + scope 21 (inlined NonNull::::cast::) { + let mut _5: *const impl Sized; + scope 22 (inlined NonNull::::as_ptr) { + } + } + } + scope 23 (inlined Unique::::as_non_null_ptr) { + } + } + } + } + scope 11 (inlined > as Deref>::deref) { + debug self => _30; + } + scope 12 (inlined Vec::::allocator) { + debug self => _29; + let mut _39: &alloc::raw_vec::RawVec; + scope 13 (inlined alloc::raw_vec::RawVec::::allocator) { + let mut _40: &alloc::raw_vec::RawVecInner; + scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) { + } + } + } + scope 15 (inlined #[track_caller] std::ptr::read::) { + debug src => _3; + } + scope 16 (inlined ManuallyDrop::::new) { + debug value => const std::alloc::Global; + } + } + scope 10 (inlined ManuallyDrop::>::new) { + debug value => _1; } } bb0: { + StorageLive(_22); + StorageLive(_29); + StorageLive(_6); + StorageLive(_7); + StorageLive(_33); + StorageLive(_11); + StorageLive(_35); + StorageLive(_20); + StorageLive(_5); + StorageLive(_4); + StorageLive(_17); StorageLive(_2); - _2 = as IntoIterator>::into_iter(move _1) -> [return: bb1, unwind continue]; + _2 = ManuallyDrop::> { value: copy _1 }; + StorageLive(_3); + StorageLive(_30); + // DBG: _30 = &_2; + // DBG: _29 = &(_2.0: std::vec::Vec); + StorageDead(_30); + StorageLive(_39); + // DBG: _39 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + StorageLive(_40); + // DBG: _40 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + StorageDead(_40); + StorageDead(_39); + _3 = &raw const ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); + StorageDead(_3); + StorageLive(_31); + StorageLive(_32); + // DBG: _32 = &_2; + StorageDead(_32); + // DBG: _31 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + StorageLive(_41); + // DBG: _41 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + _4 = copy (((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _5 = copy _4 as *const impl Sized (Transmute); + _6 = NonNull:: { pointer: copy _5 }; + StorageDead(_41); + StorageDead(_31); + _7 = copy _4 as *mut impl Sized (Transmute); + switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_3); - _3 = move _2; - goto -> bb2; + StorageLive(_10); + StorageLive(_8); + StorageLive(_36); + // DBG: _36 = &_2; + // DBG: _35 = &(_2.0: std::vec::Vec); + StorageDead(_36); + _8 = copy ((_2.0: std::vec::Vec).1: usize); + StorageLive(_9); + _9 = Le(copy _8, const ::MAX_SLICE_LEN); + assume(move _9); + StorageDead(_9); + _10 = Offset(copy _7, copy _8); + _11 = copy _10 as *const impl Sized (PtrToPtr); + StorageDead(_8); + StorageDead(_10); + goto -> bb4; } bb2: { - StorageLive(_5); - _4 = &mut _3; - _5 = as Iterator>::next(move _4) -> [return: bb3, unwind: bb9]; + StorageLive(_12); + StorageLive(_34); + // DBG: _34 = &_2; + // DBG: _33 = &(_2.0: std::vec::Vec); + StorageDead(_34); + _12 = copy ((_2.0: std::vec::Vec).1: usize); + StorageLive(_13); + _13 = Le(copy _12, const ::MAX_SLICE_LEN); + assume(move _13); + StorageDead(_13); + StorageLive(_18); + StorageLive(_14); + _14 = copy _4 as *mut u8 (Transmute); + StorageLive(_15); + _15 = copy _12 as isize (IntToInt); + StorageLive(_16); + _16 = copy _4 as *const u8 (Transmute); + _17 = arith_offset::(move _16, move _15) -> [return: bb3, unwind unreachable]; } bb3: { - _6 = discriminant(_5); - switchInt(move _6) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_16); + _18 = copy _17 as *mut u8 (PtrToPtr); + StorageDead(_15); + StorageDead(_14); + StorageDead(_18); + StorageDead(_12); + _11 = copy _17 as *const impl Sized (PtrToPtr); + goto -> bb4; } bb4: { - StorageDead(_5); - drop(_3) -> [return: bb5, unwind continue]; + StorageLive(_37); + StorageLive(_38); + // DBG: _38 = &_2; + StorageDead(_38); + // DBG: _37 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); + StorageLive(_42); + // DBG: _42 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + StorageLive(_19); + _19 = SizeOf(impl Sized); + switchInt(move _19) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_3); - StorageDead(_2); - return; + _20 = const usize::MAX; + goto -> bb7; } bb6: { - _7 = move ((_5 as Some).0: impl Sized); - _8 = opaque::(move _7) -> [return: bb7, unwind: bb9]; + StorageLive(_21); + _21 = copy ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit); + _20 = copy _21 as usize (Transmute); + StorageDead(_21); + goto -> bb7; } bb7: { + StorageDead(_19); + StorageDead(_42); + StorageDead(_37); + _22 = std::vec::IntoIter:: { buf: copy _6, phantom: const ZeroSized: PhantomData, cap: move _20, alloc: const ManuallyDrop:: {{ value: std::alloc::Global }}, ptr: copy _6, end: copy _11 }; + StorageDead(_2); + StorageDead(_17); + StorageDead(_4); StorageDead(_5); - goto -> bb2; + StorageDead(_20); + StorageDead(_35); + StorageDead(_11); + StorageDead(_33); + StorageDead(_7); + StorageDead(_6); + StorageDead(_29); + StorageLive(_23); + _23 = move _22; + goto -> bb8; } bb8: { + StorageLive(_25); + _24 = &mut _23; + _25 = as Iterator>::next(move _24) -> [return: bb9, unwind: bb15]; + } + + bb9: { + _26 = discriminant(_25); + switchInt(move _26) -> [0: bb10, 1: bb12, otherwise: bb14]; + } + + bb10: { + StorageDead(_25); + drop(_23) -> [return: bb11, unwind continue]; + } + + bb11: { + StorageDead(_23); + StorageDead(_22); + return; + } + + bb12: { + _27 = move ((_25 as Some).0: impl Sized); + _28 = opaque::(move _27) -> [return: bb13, unwind: bb15]; + } + + bb13: { + StorageDead(_25); + goto -> bb8; + } + + bb14: { unreachable; } - bb9 (cleanup): { - drop(_3) -> [return: bb10, unwind terminate(cleanup)]; + bb15 (cleanup): { + drop(_23) -> [return: bb16, unwind terminate(cleanup)]; } - bb10 (cleanup): { + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index cbdd194afd3a..9d4bacef954e 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -3,183 +3,164 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; let mut _3: &(usize, usize, usize, usize); - let _4: &usize; - let _5: &usize; - let _6: &usize; - let _7: &usize; - let mut _8: &&usize; - let _9: &usize; - let mut _10: &&usize; - let mut _13: bool; - let mut _14: &&usize; + let mut _6: bool; + let mut _9: bool; + let mut _10: bool; + let _13: &usize; + let _14: &usize; let _15: &usize; - let mut _16: &&usize; - let mut _19: bool; + let _16: &usize; + let mut _17: &&usize; + let mut _18: &&usize; + let mut _19: &&usize; let mut _20: &&usize; - let _21: &usize; + let mut _21: &&usize; let mut _22: &&usize; - let mut _23: bool; + let mut _23: &&usize; let mut _24: &&usize; - let _25: &usize; - let mut _26: &&usize; scope 1 { - debug a => _4; - debug b => _5; - debug c => _6; - debug d => _7; + debug a => _13; + debug b => _14; + debug c => _15; + debug d => _16; scope 2 (inlined std::cmp::impls::::le) { - debug self => _8; - debug other => _10; + debug self => _17; + debug other => _18; scope 3 (inlined std::cmp::impls::::le) { - debug self => _4; - debug other => _6; - let mut _11: usize; - let mut _12: usize; + debug self => _13; + debug other => _15; + let mut _4: usize; + let mut _5: usize; } } scope 4 (inlined std::cmp::impls::::le) { - debug self => _14; - debug other => _16; + debug self => _19; + debug other => _20; scope 5 (inlined std::cmp::impls::::le) { - debug self => _7; - debug other => _5; - let mut _17: usize; - let mut _18: usize; + debug self => _16; + debug other => _14; + let mut _7: usize; + let mut _8: usize; } } scope 6 (inlined std::cmp::impls::::le) { - debug self => _20; + debug self => _21; debug other => _22; scope 7 (inlined std::cmp::impls::::le) { - debug self => _6; - debug other => _4; + debug self => _15; + debug other => _13; } } scope 8 (inlined std::cmp::impls::::le) { - debug self => _24; - debug other => _26; + debug self => _23; + debug other => _24; scope 9 (inlined std::cmp::impls::::le) { - debug self => _5; - debug other => _7; - let mut _27: usize; - let mut _28: usize; + debug self => _14; + debug other => _16; + let mut _11: usize; + let mut _12: usize; } } } bb0: { _3 = copy (*_2); - _4 = &((*_3).0: usize); - _5 = &((*_3).1: usize); - _6 = &((*_3).2: usize); - _7 = &((*_3).3: usize); - StorageLive(_13); - StorageLive(_8); - _8 = &_4; - StorageLive(_10); - StorageLive(_9); - _9 = copy _6; - _10 = &_9; - _11 = copy ((*_3).0: usize); - _12 = copy ((*_3).2: usize); - _13 = Le(copy _11, copy _12); - switchInt(move _13) -> [0: bb1, otherwise: bb2]; + // DBG: _13 = &((*_3).0: usize); + // DBG: _14 = &((*_3).1: usize); + // DBG: _15 = &((*_3).2: usize); + // DBG: _16 = &((*_3).3: usize); + StorageLive(_6); + StorageLive(_17); + // DBG: _17 = &_13; + StorageLive(_18); + // DBG: _18 = &_15; + _4 = copy ((*_3).0: usize); + _5 = copy ((*_3).2: usize); + _6 = Le(copy _4, copy _5); + switchInt(move _6) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageDead(_9); - StorageDead(_10); - StorageDead(_8); + StorageDead(_18); + StorageDead(_17); goto -> bb4; } bb2: { - StorageDead(_9); - StorageDead(_10); - StorageDead(_8); - StorageLive(_19); - StorageLive(_14); - _14 = &_7; - StorageLive(_16); - StorageLive(_15); - _15 = copy _5; - _16 = &_15; - StorageLive(_17); - _17 = copy ((*_3).3: usize); - StorageLive(_18); - _18 = copy ((*_3).1: usize); - _19 = Le(move _17, move _18); StorageDead(_18); StorageDead(_17); - switchInt(move _19) -> [0: bb3, otherwise: bb8]; + StorageLive(_9); + StorageLive(_19); + // DBG: _19 = &_16; + StorageLive(_20); + // DBG: _20 = &_14; + StorageLive(_7); + _7 = copy ((*_3).3: usize); + StorageLive(_8); + _8 = copy ((*_3).1: usize); + _9 = Le(move _7, move _8); + StorageDead(_8); + StorageDead(_7); + switchInt(move _9) -> [0: bb3, otherwise: bb8]; } bb3: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); + StorageDead(_20); + StorageDead(_19); goto -> bb4; } bb4: { - StorageLive(_23); - StorageLive(_20); - _20 = &_6; - StorageLive(_22); + StorageLive(_10); StorageLive(_21); - _21 = copy _4; - _22 = &_21; - _23 = Le(copy _12, copy _11); - switchInt(move _23) -> [0: bb5, otherwise: bb6]; + // DBG: _21 = &_15; + StorageLive(_22); + // DBG: _22 = &_13; + _10 = Le(copy _5, copy _4); + switchInt(move _10) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_21); StorageDead(_22); - StorageDead(_20); + StorageDead(_21); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_21); StorageDead(_22); - StorageDead(_20); + StorageDead(_21); + StorageLive(_23); + // DBG: _23 = &_14; StorageLive(_24); - _24 = &_5; - StorageLive(_26); - StorageLive(_25); - _25 = copy _7; - _26 = &_25; - StorageLive(_27); - _27 = copy ((*_3).1: usize); - StorageLive(_28); - _28 = copy ((*_3).3: usize); - _0 = Le(move _27, move _28); - StorageDead(_28); - StorageDead(_27); - StorageDead(_25); - StorageDead(_26); + // DBG: _24 = &_16; + StorageLive(_11); + _11 = copy ((*_3).1: usize); + StorageLive(_12); + _12 = copy ((*_3).3: usize); + _0 = Le(move _11, move _12); + StorageDead(_12); + StorageDead(_11); StorageDead(_24); + StorageDead(_23); goto -> bb7; } bb7: { - StorageDead(_23); + StorageDead(_10); goto -> bb9; } bb8: { - StorageDead(_15); - StorageDead(_16); - StorageDead(_14); + StorageDead(_20); + StorageDead(_19); _0 = const true; goto -> bb9; } bb9: { - StorageDead(_19); - StorageDead(_13); + StorageDead(_9); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 104987b0fdda..1b2e7b7163cd 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -51,6 +51,9 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _16: bool; let mut _20: usize; let _22: &T; + let mut _34: &std::ptr::NonNull; + let mut _35: &std::ptr::NonNull; + let mut _36: &std::ptr::NonNull; scope 29 { let _12: *const T; scope 30 { @@ -186,7 +189,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb5: { StorageLive(_16); + StorageLive(_34); + // DBG: _34 = &_11; + StorageLive(_35); _13 = copy _12 as std::ptr::NonNull (Transmute); + // DBG: _35 = &_13; StorageLive(_14); _14 = copy _11 as *mut T (Transmute); StorageLive(_15); @@ -198,6 +205,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb6: { + StorageDead(_35); + StorageDead(_34); StorageDead(_16); StorageLive(_18); StorageLive(_17); @@ -210,6 +219,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb7: { + StorageDead(_35); + StorageDead(_34); StorageDead(_16); StorageDead(_22); StorageDead(_13); @@ -255,10 +266,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb13: { + StorageLive(_36); + // DBG: _36 = &_11; StorageLive(_21); _21 = copy _11 as *const T (Transmute); _22 = &(*_21); StorageDead(_21); + StorageDead(_36); _23 = Option::<&T>::Some(copy _22); StorageDead(_22); StorageDead(_13); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 4d0e3548e7d6..c18dd01a189a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -23,6 +23,9 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _15: bool; let mut _19: usize; let _21: &T; + let mut _27: &std::ptr::NonNull; + let mut _28: &std::ptr::NonNull; + let mut _29: &std::ptr::NonNull; scope 17 { let _11: *const T; scope 18 { @@ -148,7 +151,11 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { StorageLive(_15); + StorageLive(_27); + // DBG: _27 = &_10; + StorageLive(_28); _12 = copy _11 as std::ptr::NonNull (Transmute); + // DBG: _28 = &_12; StorageLive(_13); _13 = copy _10 as *mut T (Transmute); StorageLive(_14); @@ -160,6 +167,8 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb6: { + StorageDead(_28); + StorageDead(_27); StorageDead(_15); StorageLive(_17); StorageLive(_16); @@ -172,6 +181,8 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb7: { + StorageDead(_28); + StorageDead(_27); StorageDead(_15); StorageDead(_21); StorageDead(_12); @@ -213,10 +224,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb13: { + StorageLive(_29); + // DBG: _29 = &_10; StorageLive(_20); _20 = copy _10 as *const T (Transmute); _21 = &(*_20); StorageDead(_20); + StorageDead(_29); _22 = Option::<&T>::Some(copy _21); StorageDead(_21); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 2b5d8c27d710..6334c611430a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -23,6 +23,9 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _15: bool; let mut _19: usize; let _21: &T; + let mut _27: &std::ptr::NonNull; + let mut _28: &std::ptr::NonNull; + let mut _29: &std::ptr::NonNull; scope 17 { let _11: *const T; scope 18 { @@ -148,7 +151,11 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { StorageLive(_15); + StorageLive(_27); + // DBG: _27 = &_10; + StorageLive(_28); _12 = copy _11 as std::ptr::NonNull (Transmute); + // DBG: _28 = &_12; StorageLive(_13); _13 = copy _10 as *mut T (Transmute); StorageLive(_14); @@ -160,6 +167,8 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb6: { + StorageDead(_28); + StorageDead(_27); StorageDead(_15); StorageLive(_17); StorageLive(_16); @@ -172,6 +181,8 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb7: { + StorageDead(_28); + StorageDead(_27); StorageDead(_15); StorageDead(_21); StorageDead(_12); @@ -213,10 +224,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb13: { + StorageLive(_29); + // DBG: _29 = &_10; StorageLive(_20); _20 = copy _10 as *const T (Transmute); _21 = &(*_20); StorageDead(_20); + StorageDead(_29); _22 = Option::<&T>::Some(copy _21); StorageDead(_21); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 0adf268d766d..24c6618d31ca 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -7,19 +7,90 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _10: std::slice::Iter<'_, T>; let mut _11: std::iter::Rev>; let mut _12: std::iter::Rev>; - let mut _14: std::option::Option<&T>; - let mut _15: isize; - let mut _17: &impl Fn(&T); - let mut _18: (&T,); - let _19: (); + let mut _33: std::option::Option<&T>; + let mut _35: &impl Fn(&T); + let mut _36: (&T,); + let _37: (); scope 1 { debug iter => _12; - let _16: &T; + let _34: &T; scope 2 { - debug x => _16; + debug x => _34; } scope 18 (inlined > as Iterator>::next) { - let mut _13: &mut std::slice::Iter<'_, T>; + scope 19 (inlined as DoubleEndedIterator>::next_back) { + let mut _13: *const T; + let mut _18: bool; + let mut _19: *const T; + let _32: &T; + let mut _38: &std::ptr::NonNull; + let mut _39: &std::ptr::NonNull; + scope 20 { + let _14: std::ptr::NonNull; + let _20: usize; + scope 21 { + } + scope 22 { + scope 25 (inlined as PartialEq>::eq) { + let mut _15: std::ptr::NonNull; + let mut _16: *mut T; + let mut _17: *mut T; + scope 26 (inlined NonNull::::as_ptr) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + } + } + scope 23 (inlined std::ptr::const_ptr::::addr) { + scope 24 (inlined std::ptr::const_ptr::::cast::<()>) { + } + } + } + scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { + let _26: std::ptr::NonNull; + let mut _40: &std::ptr::NonNull; + scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { + let mut _21: *mut *const T; + let mut _22: *mut std::ptr::NonNull; + let mut _23: std::ptr::NonNull; + let mut _27: *mut *const T; + let mut _28: *mut usize; + let mut _29: usize; + let mut _30: usize; + scope 30 { + scope 31 { + } + scope 32 { + scope 35 (inlined NonNull::::sub) { + scope 36 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 37 (inlined core::ub_checks::check_language_ub) { + scope 38 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 39 (inlined NonNull::::offset) { + let mut _24: *const T; + let mut _25: *const T; + scope 40 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 33 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 34 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 41 (inlined NonNull::::as_ref::<'_>) { + let _31: *const T; + scope 42 (inlined NonNull::::as_ptr) { + } + scope 43 (inlined std::ptr::mut_ptr::::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::::iter) { @@ -105,45 +176,145 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb4: { + StorageLive(_33); + StorageLive(_20); + StorageLive(_19); StorageLive(_14); - StorageLive(_13); - _13 = &mut (_12.0: std::slice::Iter<'_, T>); - _14 = as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind unreachable]; + StorageLive(_32); + StorageLive(_18); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb6]; } bb5: { + StorageLive(_13); + _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _14 = copy _13 as std::ptr::NonNull (Transmute); StorageDead(_13); - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_38); + // DBG: _38 = &((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + StorageLive(_39); + // DBG: _39 = &_14; + StorageLive(_16); + StorageLive(_15); + _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + _16 = copy _15 as *mut T (Transmute); + StorageDead(_15); + StorageLive(_17); + _17 = copy _14 as *mut T (Transmute); + _18 = Eq(copy _16, copy _17); + StorageDead(_17); + StorageDead(_16); + StorageDead(_39); + StorageDead(_38); + goto -> bb7; } bb6: { - StorageDead(_14); - StorageDead(_12); - drop(_2) -> [return: bb7, unwind unreachable]; + _19 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _20 = copy _19 as usize (Transmute); + _18 = Eq(copy _20, const 0_usize); + goto -> bb7; } bb7: { - return; + switchInt(move _18) -> [0: bb8, otherwise: bb15]; } bb8: { - _16 = copy ((_14 as Some).0: &T); - StorageLive(_17); - _17 = &_2; - StorageLive(_18); - _18 = (copy _16,); - _19 = >::call(move _17, move _18) -> [return: bb9, unwind unreachable]; + StorageLive(_26); + StorageLive(_40); + StorageLive(_28); + StorageLive(_22); + StorageLive(_23); + switchInt(const ::IS_ZST) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_18); - StorageDead(_17); - StorageDead(_14); - goto -> bb4; + StorageLive(_21); + _21 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _22 = copy _21 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_21); + _23 = copy (*_22); + switchInt(const ::IS_ZST) -> [0: bb10, otherwise: bb11]; } bb10: { - unreachable; + StorageLive(_25); + StorageLive(_24); + _24 = copy _23 as *const T (Transmute); + _25 = Offset(copy _24, const -1_isize); + StorageDead(_24); + _23 = NonNull:: { pointer: copy _25 }; + StorageDead(_25); + goto -> bb11; + } + + bb11: { + (*_22) = move _23; + _26 = copy (*_22); + goto -> bb13; + } + + bb12: { + StorageLive(_27); + _27 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _28 = copy _27 as *mut usize (PtrToPtr); + StorageDead(_27); + StorageLive(_30); + StorageLive(_29); + _29 = copy (*_28); + _30 = SubUnchecked(move _29, const 1_usize); + StorageDead(_29); + (*_28) = move _30; + StorageDead(_30); + _26 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + goto -> bb13; + } + + bb13: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_28); + // DBG: _40 = &_26; + StorageLive(_31); + _31 = copy _26 as *const T (Transmute); + _32 = &(*_31); + StorageDead(_31); + StorageDead(_40); + StorageDead(_26); + _33 = Option::<&T>::Some(copy _32); + StorageDead(_18); + StorageDead(_32); + StorageDead(_14); + StorageDead(_19); + StorageDead(_20); + _34 = copy ((_33 as Some).0: &T); + StorageLive(_35); + _35 = &_2; + StorageLive(_36); + _36 = (copy _34,); + _37 = >::call(move _35, move _36) -> [return: bb14, unwind unreachable]; + } + + bb14: { + StorageDead(_36); + StorageDead(_35); + StorageDead(_33); + goto -> bb4; + } + + bb15: { + StorageDead(_18); + StorageDead(_32); + StorageDead(_14); + StorageDead(_19); + StorageDead(_20); + StorageDead(_33); + StorageDead(_12); + drop(_2) -> [return: bb16, unwind unreachable]; + } + + bb16: { + return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index cb0d640d445b..e5c7bcca44b6 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -7,19 +7,90 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _10: std::slice::Iter<'_, T>; let mut _11: std::iter::Rev>; let mut _12: std::iter::Rev>; - let mut _14: std::option::Option<&T>; - let mut _15: isize; - let mut _17: &impl Fn(&T); - let mut _18: (&T,); - let _19: (); + let mut _33: std::option::Option<&T>; + let mut _35: &impl Fn(&T); + let mut _36: (&T,); + let _37: (); scope 1 { debug iter => _12; - let _16: &T; + let _34: &T; scope 2 { - debug x => _16; + debug x => _34; } scope 18 (inlined > as Iterator>::next) { - let mut _13: &mut std::slice::Iter<'_, T>; + scope 19 (inlined as DoubleEndedIterator>::next_back) { + let mut _13: *const T; + let mut _18: bool; + let mut _19: *const T; + let _32: &T; + let mut _38: &std::ptr::NonNull; + let mut _39: &std::ptr::NonNull; + scope 20 { + let _14: std::ptr::NonNull; + let _20: usize; + scope 21 { + } + scope 22 { + scope 25 (inlined as PartialEq>::eq) { + let mut _15: std::ptr::NonNull; + let mut _16: *mut T; + let mut _17: *mut T; + scope 26 (inlined NonNull::::as_ptr) { + } + scope 27 (inlined NonNull::::as_ptr) { + } + } + } + scope 23 (inlined std::ptr::const_ptr::::addr) { + scope 24 (inlined std::ptr::const_ptr::::cast::<()>) { + } + } + } + scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { + let _26: std::ptr::NonNull; + let mut _40: &std::ptr::NonNull; + scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { + let mut _21: *mut *const T; + let mut _22: *mut std::ptr::NonNull; + let mut _23: std::ptr::NonNull; + let mut _27: *mut *const T; + let mut _28: *mut usize; + let mut _29: usize; + let mut _30: usize; + scope 30 { + scope 31 { + } + scope 32 { + scope 35 (inlined NonNull::::sub) { + scope 36 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 37 (inlined core::ub_checks::check_language_ub) { + scope 38 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 39 (inlined NonNull::::offset) { + let mut _24: *const T; + let mut _25: *const T; + scope 40 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 33 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 34 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 41 (inlined NonNull::::as_ref::<'_>) { + let _31: *const T; + scope 42 (inlined NonNull::::as_ptr) { + } + scope 43 (inlined std::ptr::mut_ptr::::cast_const) { + } + } + } + } } } scope 3 (inlined core::slice::::iter) { @@ -105,53 +176,153 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb4: { + StorageLive(_33); + StorageLive(_20); + StorageLive(_19); StorageLive(_14); - StorageLive(_13); - _13 = &mut (_12.0: std::slice::Iter<'_, T>); - _14 = as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind: bb11]; + StorageLive(_32); + StorageLive(_18); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb6]; } bb5: { + StorageLive(_13); + _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _14 = copy _13 as std::ptr::NonNull (Transmute); StorageDead(_13); - _15 = discriminant(_14); - switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageLive(_38); + // DBG: _38 = &((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + StorageLive(_39); + // DBG: _39 = &_14; + StorageLive(_16); + StorageLive(_15); + _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + _16 = copy _15 as *mut T (Transmute); + StorageDead(_15); + StorageLive(_17); + _17 = copy _14 as *mut T (Transmute); + _18 = Eq(copy _16, copy _17); + StorageDead(_17); + StorageDead(_16); + StorageDead(_39); + StorageDead(_38); + goto -> bb7; } bb6: { - StorageDead(_14); - StorageDead(_12); - drop(_2) -> [return: bb7, unwind continue]; + _19 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _20 = copy _19 as usize (Transmute); + _18 = Eq(copy _20, const 0_usize); + goto -> bb7; } bb7: { - return; + switchInt(move _18) -> [0: bb8, otherwise: bb17]; } bb8: { - _16 = copy ((_14 as Some).0: &T); - StorageLive(_17); - _17 = &_2; - StorageLive(_18); - _18 = (copy _16,); - _19 = >::call(move _17, move _18) -> [return: bb9, unwind: bb11]; + StorageLive(_26); + StorageLive(_40); + StorageLive(_28); + StorageLive(_22); + StorageLive(_23); + switchInt(const ::IS_ZST) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_18); - StorageDead(_17); - StorageDead(_14); - goto -> bb4; + StorageLive(_21); + _21 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _22 = copy _21 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_21); + _23 = copy (*_22); + switchInt(const ::IS_ZST) -> [0: bb10, otherwise: bb11]; } bb10: { - unreachable; + StorageLive(_25); + StorageLive(_24); + _24 = copy _23 as *const T (Transmute); + _25 = Offset(copy _24, const -1_isize); + StorageDead(_24); + _23 = NonNull:: { pointer: copy _25 }; + StorageDead(_25); + goto -> bb11; } - bb11 (cleanup): { - drop(_2) -> [return: bb12, unwind terminate(cleanup)]; + bb11: { + (*_22) = move _23; + _26 = copy (*_22); + goto -> bb13; } - bb12 (cleanup): { + bb12: { + StorageLive(_27); + _27 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T); + _28 = copy _27 as *mut usize (PtrToPtr); + StorageDead(_27); + StorageLive(_30); + StorageLive(_29); + _29 = copy (*_28); + _30 = SubUnchecked(move _29, const 1_usize); + StorageDead(_29); + (*_28) = move _30; + StorageDead(_30); + _26 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); + goto -> bb13; + } + + bb13: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_28); + // DBG: _40 = &_26; + StorageLive(_31); + _31 = copy _26 as *const T (Transmute); + _32 = &(*_31); + StorageDead(_31); + StorageDead(_40); + StorageDead(_26); + _33 = Option::<&T>::Some(copy _32); + StorageDead(_18); + StorageDead(_32); + StorageDead(_14); + StorageDead(_19); + StorageDead(_20); + _34 = copy ((_33 as Some).0: &T); + StorageLive(_35); + _35 = &_2; + StorageLive(_36); + _36 = (copy _34,); + _37 = >::call(move _35, move _36) -> [return: bb14, unwind: bb15]; + } + + bb14: { + StorageDead(_36); + StorageDead(_35); + StorageDead(_33); + goto -> bb4; + } + + bb15 (cleanup): { + drop(_2) -> [return: bb16, unwind terminate(cleanup)]; + } + + bb16 (cleanup): { resume; } + + bb17: { + StorageDead(_18); + StorageDead(_32); + StorageDead(_14); + StorageDead(_19); + StorageDead(_20); + StorageDead(_33); + StorageDead(_12); + drop(_2) -> [return: bb18, unwind continue]; + } + + bb18: { + return; + } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir index 9b510380b10b..18a3d8e7c4ad 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir @@ -6,6 +6,8 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const T; let mut _7: *const T; + let mut _9: &std::ptr::NonNull; + let mut _10: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _8: usize; @@ -41,6 +43,10 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _2 = copy ((*_1).1: *const T); _3 = copy _2 as std::ptr::NonNull (Transmute); StorageDead(_2); + StorageLive(_9); + // DBG: _9 = &((*_1).0: std::ptr::NonNull); + StorageLive(_10); + // DBG: _10 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -51,6 +57,8 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); + StorageDead(_10); + StorageDead(_9); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir index 9b510380b10b..18a3d8e7c4ad 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir @@ -6,6 +6,8 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const T; let mut _7: *const T; + let mut _9: &std::ptr::NonNull; + let mut _10: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _8: usize; @@ -41,6 +43,10 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _2 = copy ((*_1).1: *const T); _3 = copy _2 as std::ptr::NonNull (Transmute); StorageDead(_2); + StorageLive(_9); + // DBG: _9 = &((*_1).0: std::ptr::NonNull); + StorageLive(_10); + // DBG: _10 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -51,6 +57,8 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); + StorageDead(_10); + StorageDead(_9); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir index 78f96bf41955..590d4ac2c838 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir @@ -3,12 +3,199 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> { debug it => _1; let mut _0: std::option::Option<&mut T>; + scope 1 (inlined as DoubleEndedIterator>::next_back) { + let mut _2: *mut T; + let mut _7: bool; + let mut _8: *mut T; + let mut _21: &mut T; + let mut _22: &std::ptr::NonNull; + let mut _23: &std::ptr::NonNull; + scope 2 { + let _3: std::ptr::NonNull; + let _9: usize; + scope 3 { + } + scope 4 { + scope 7 (inlined as PartialEq>::eq) { + let mut _4: std::ptr::NonNull; + let mut _5: *mut T; + let mut _6: *mut T; + scope 8 (inlined NonNull::::as_ptr) { + } + scope 9 (inlined NonNull::::as_ptr) { + } + } + } + scope 5 (inlined std::ptr::mut_ptr::::addr) { + scope 6 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + } + } + scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { + let mut _15: std::ptr::NonNull; + let mut _24: &mut std::ptr::NonNull; + scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { + let mut _10: *mut *mut T; + let mut _11: *mut std::ptr::NonNull; + let mut _12: std::ptr::NonNull; + let mut _16: *mut *mut T; + let mut _17: *mut usize; + let mut _18: usize; + let mut _19: usize; + scope 12 { + scope 13 { + } + scope 14 { + scope 17 (inlined NonNull::::sub) { + scope 18 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 19 (inlined core::ub_checks::check_language_ub) { + scope 20 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 21 (inlined NonNull::::offset) { + let mut _13: *const T; + let mut _14: *const T; + scope 22 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 15 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 16 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 23 (inlined NonNull::::as_mut::<'_>) { + let mut _20: *mut T; + scope 24 (inlined NonNull::::as_ptr) { + } + } + } + } bb0: { - _0 = as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind unreachable]; + StorageLive(_9); + StorageLive(_8); + StorageLive(_3); + StorageLive(_2); + StorageLive(_21); + StorageLive(_7); + switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { + _2 = copy ((*_1).1: *mut T); + _3 = copy _2 as std::ptr::NonNull (Transmute); + StorageLive(_22); + // DBG: _22 = &((*_1).0: std::ptr::NonNull); + StorageLive(_23); + // DBG: _23 = &_3; + StorageLive(_5); + StorageLive(_4); + _4 = copy ((*_1).0: std::ptr::NonNull); + _5 = copy _4 as *mut T (Transmute); + StorageDead(_4); + StorageLive(_6); + _6 = copy _3 as *mut T (Transmute); + _7 = Eq(copy _5, copy _6); + StorageDead(_6); + StorageDead(_5); + StorageDead(_23); + StorageDead(_22); + goto -> bb3; + } + + bb2: { + _8 = copy ((*_1).1: *mut T); + _9 = copy _8 as usize (Transmute); + _7 = Eq(copy _9, const 0_usize); + goto -> bb3; + } + + bb3: { + switchInt(move _7) -> [0: bb4, otherwise: bb10]; + } + + bb4: { + StorageLive(_15); + StorageLive(_24); + StorageLive(_17); + StorageLive(_11); + StorageLive(_12); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb8]; + } + + bb5: { + StorageLive(_10); + _10 = &raw mut ((*_1).1: *mut T); + _11 = copy _10 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_10); + _12 = copy (*_11); + switchInt(const ::IS_ZST) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageLive(_14); + StorageLive(_13); + _13 = copy _12 as *const T (Transmute); + _14 = Offset(copy _13, const -1_isize); + StorageDead(_13); + _12 = NonNull:: { pointer: copy _14 }; + StorageDead(_14); + goto -> bb7; + } + + bb7: { + (*_11) = move _12; + _15 = copy (*_11); + goto -> bb9; + } + + bb8: { + StorageLive(_16); + _16 = &raw mut ((*_1).1: *mut T); + _17 = copy _16 as *mut usize (PtrToPtr); + StorageDead(_16); + StorageLive(_19); + StorageLive(_18); + _18 = copy (*_17); + _19 = SubUnchecked(move _18, const 1_usize); + StorageDead(_18); + (*_17) = move _19; + StorageDead(_19); + _15 = copy ((*_1).0: std::ptr::NonNull); + goto -> bb9; + } + + bb9: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_17); + // DBG: _24 = &_15; + StorageLive(_20); + _20 = copy _15 as *mut T (Transmute); + _21 = &mut (*_20); + StorageDead(_20); + StorageDead(_24); + StorageDead(_15); + _0 = Option::<&mut T>::Some(copy _21); + goto -> bb11; + } + + bb10: { + _0 = const {transmute(0x0000000000000000): Option<&mut T>}; + goto -> bb11; + } + + bb11: { + StorageDead(_7); + StorageDead(_21); + StorageDead(_2); + StorageDead(_3); + StorageDead(_8); + StorageDead(_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir index dfe5e206fada..590d4ac2c838 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir @@ -3,12 +3,199 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> { debug it => _1; let mut _0: std::option::Option<&mut T>; + scope 1 (inlined as DoubleEndedIterator>::next_back) { + let mut _2: *mut T; + let mut _7: bool; + let mut _8: *mut T; + let mut _21: &mut T; + let mut _22: &std::ptr::NonNull; + let mut _23: &std::ptr::NonNull; + scope 2 { + let _3: std::ptr::NonNull; + let _9: usize; + scope 3 { + } + scope 4 { + scope 7 (inlined as PartialEq>::eq) { + let mut _4: std::ptr::NonNull; + let mut _5: *mut T; + let mut _6: *mut T; + scope 8 (inlined NonNull::::as_ptr) { + } + scope 9 (inlined NonNull::::as_ptr) { + } + } + } + scope 5 (inlined std::ptr::mut_ptr::::addr) { + scope 6 (inlined std::ptr::mut_ptr::::cast::<()>) { + } + } + } + scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { + let mut _15: std::ptr::NonNull; + let mut _24: &mut std::ptr::NonNull; + scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { + let mut _10: *mut *mut T; + let mut _11: *mut std::ptr::NonNull; + let mut _12: std::ptr::NonNull; + let mut _16: *mut *mut T; + let mut _17: *mut usize; + let mut _18: usize; + let mut _19: usize; + scope 12 { + scope 13 { + } + scope 14 { + scope 17 (inlined NonNull::::sub) { + scope 18 (inlined #[track_caller] core::num::::unchecked_neg) { + scope 19 (inlined core::ub_checks::check_language_ub) { + scope 20 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + } + scope 21 (inlined NonNull::::offset) { + let mut _13: *const T; + let mut _14: *const T; + scope 22 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 15 (inlined std::ptr::mut_ptr::::cast::) { + } + scope 16 (inlined std::ptr::mut_ptr::::cast::>) { + } + } + } + scope 23 (inlined NonNull::::as_mut::<'_>) { + let mut _20: *mut T; + scope 24 (inlined NonNull::::as_ptr) { + } + } + } + } bb0: { - _0 = as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind continue]; + StorageLive(_9); + StorageLive(_8); + StorageLive(_3); + StorageLive(_2); + StorageLive(_21); + StorageLive(_7); + switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { + _2 = copy ((*_1).1: *mut T); + _3 = copy _2 as std::ptr::NonNull (Transmute); + StorageLive(_22); + // DBG: _22 = &((*_1).0: std::ptr::NonNull); + StorageLive(_23); + // DBG: _23 = &_3; + StorageLive(_5); + StorageLive(_4); + _4 = copy ((*_1).0: std::ptr::NonNull); + _5 = copy _4 as *mut T (Transmute); + StorageDead(_4); + StorageLive(_6); + _6 = copy _3 as *mut T (Transmute); + _7 = Eq(copy _5, copy _6); + StorageDead(_6); + StorageDead(_5); + StorageDead(_23); + StorageDead(_22); + goto -> bb3; + } + + bb2: { + _8 = copy ((*_1).1: *mut T); + _9 = copy _8 as usize (Transmute); + _7 = Eq(copy _9, const 0_usize); + goto -> bb3; + } + + bb3: { + switchInt(move _7) -> [0: bb4, otherwise: bb10]; + } + + bb4: { + StorageLive(_15); + StorageLive(_24); + StorageLive(_17); + StorageLive(_11); + StorageLive(_12); + switchInt(const ::IS_ZST) -> [0: bb5, otherwise: bb8]; + } + + bb5: { + StorageLive(_10); + _10 = &raw mut ((*_1).1: *mut T); + _11 = copy _10 as *mut std::ptr::NonNull (PtrToPtr); + StorageDead(_10); + _12 = copy (*_11); + switchInt(const ::IS_ZST) -> [0: bb6, otherwise: bb7]; + } + + bb6: { + StorageLive(_14); + StorageLive(_13); + _13 = copy _12 as *const T (Transmute); + _14 = Offset(copy _13, const -1_isize); + StorageDead(_13); + _12 = NonNull:: { pointer: copy _14 }; + StorageDead(_14); + goto -> bb7; + } + + bb7: { + (*_11) = move _12; + _15 = copy (*_11); + goto -> bb9; + } + + bb8: { + StorageLive(_16); + _16 = &raw mut ((*_1).1: *mut T); + _17 = copy _16 as *mut usize (PtrToPtr); + StorageDead(_16); + StorageLive(_19); + StorageLive(_18); + _18 = copy (*_17); + _19 = SubUnchecked(move _18, const 1_usize); + StorageDead(_18); + (*_17) = move _19; + StorageDead(_19); + _15 = copy ((*_1).0: std::ptr::NonNull); + goto -> bb9; + } + + bb9: { + StorageDead(_12); + StorageDead(_11); + StorageDead(_17); + // DBG: _24 = &_15; + StorageLive(_20); + _20 = copy _15 as *mut T (Transmute); + _21 = &mut (*_20); + StorageDead(_20); + StorageDead(_24); + StorageDead(_15); + _0 = Option::<&mut T>::Some(copy _21); + goto -> bb11; + } + + bb10: { + _0 = const {transmute(0x0000000000000000): Option<&mut T>}; + goto -> bb11; + } + + bb11: { + StorageDead(_7); + StorageDead(_21); + StorageDead(_2); + StorageDead(_3); + StorageDead(_8); + StorageDead(_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir index cc0fce26149e..e9ed932cbafb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir @@ -10,6 +10,9 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { let mut _10: std::ptr::NonNull; let mut _12: usize; let _14: &T; + let mut _15: &std::ptr::NonNull; + let mut _16: &std::ptr::NonNull; + let mut _17: &std::ptr::NonNull; scope 2 { let _3: *const T; scope 3 { @@ -67,7 +70,11 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { bb1: { StorageLive(_7); + StorageLive(_15); + // DBG: _15 = &_2; + StorageLive(_16); _4 = copy _3 as std::ptr::NonNull (Transmute); + // DBG: _16 = &_4; StorageLive(_5); _5 = copy _2 as *mut T (Transmute); StorageLive(_6); @@ -79,6 +86,8 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb2: { + StorageDead(_16); + StorageDead(_15); StorageDead(_7); StorageLive(_10); StorageLive(_9); @@ -94,6 +103,8 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb3: { + StorageDead(_16); + StorageDead(_15); _0 = const {transmute(0x0000000000000000): Option<&T>}; StorageDead(_7); goto -> bb8; @@ -116,10 +127,13 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb7: { + StorageLive(_17); + // DBG: _17 = &_2; StorageLive(_13); _13 = copy _2 as *const T (Transmute); _14 = &(*_13); StorageDead(_13); + StorageDead(_17); _0 = Option::<&T>::Some(copy _14); goto -> bb8; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir index cc0fce26149e..e9ed932cbafb 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir @@ -10,6 +10,9 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { let mut _10: std::ptr::NonNull; let mut _12: usize; let _14: &T; + let mut _15: &std::ptr::NonNull; + let mut _16: &std::ptr::NonNull; + let mut _17: &std::ptr::NonNull; scope 2 { let _3: *const T; scope 3 { @@ -67,7 +70,11 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { bb1: { StorageLive(_7); + StorageLive(_15); + // DBG: _15 = &_2; + StorageLive(_16); _4 = copy _3 as std::ptr::NonNull (Transmute); + // DBG: _16 = &_4; StorageLive(_5); _5 = copy _2 as *mut T (Transmute); StorageLive(_6); @@ -79,6 +86,8 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb2: { + StorageDead(_16); + StorageDead(_15); StorageDead(_7); StorageLive(_10); StorageLive(_9); @@ -94,6 +103,8 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb3: { + StorageDead(_16); + StorageDead(_15); _0 = const {transmute(0x0000000000000000): Option<&T>}; StorageDead(_7); goto -> bb8; @@ -116,10 +127,13 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb7: { + StorageLive(_17); + // DBG: _17 = &_2; StorageLive(_13); _13 = copy _2 as *const T (Transmute); _14 = &(*_13); StorageDead(_13); + StorageDead(_17); _0 = Option::<&T>::Some(copy _14); goto -> bb8; } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir index fe4e2deab870..79aa9c5ae1e3 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir @@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 { } bb0: { - _2 = &_1; // scope 0 at $DIR/spans.rs:11:11: 11:13 + // DBG: _2 = &_1; _0 = copy _1; // scope 1 at $DIR/spans.rs:15:5: 15:7 return; // scope 0 at $DIR/spans.rs:12:2: 12:2 } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir index fe4e2deab870..79aa9c5ae1e3 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir @@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 { } bb0: { - _2 = &_1; // scope 0 at $DIR/spans.rs:11:11: 11:13 + // DBG: _2 = &_1; _0 = copy _1; // scope 1 at $DIR/spans.rs:15:5: 15:7 return; // scope 0 at $DIR/spans.rs:12:2: 12:2 } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 2eee8a97db0d..eebd4a7eb50e 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -11,7 +11,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; + let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -55,8 +57,14 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); + StorageLive(_6); + // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec); + StorageLive(_7); + // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 2eee8a97db0d..eebd4a7eb50e 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -11,7 +11,9 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; + let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -55,8 +57,14 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); + StorageLive(_6); + // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec); + StorageLive(_7); + // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); From cc93132ae4f5477297ecddb0c07d2e8c74075f0c Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 10 Jul 2025 21:20:54 +0800 Subject: [PATCH 471/537] simplifycfg: Preserve debuginfos when merging bbs --- compiler/rustc_middle/src/mir/terminator.rs | 8 + compiler/rustc_mir_transform/src/simplify.rs | 30 ++- ...ycfg.drop_debuginfo.SimplifyCfg-final.diff | 2 + ...reserve_debuginfo_1.SimplifyCfg-final.diff | 3 + ...reserve_debuginfo_2.SimplifyCfg-final.diff | 3 + ...reserve_debuginfo_3.SimplifyCfg-final.diff | 40 ++++ ...nfo_identical_succs.SimplifyCfg-final.diff | 32 +++ tests/mir-opt/debuginfo/simplifycfg.rs | 207 ++++++++++++++++++ 8 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff create mode 100644 tests/mir-opt/debuginfo/simplifycfg.rs diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 4034a3a06e94..4249914346cd 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -444,6 +444,14 @@ impl<'tcx> Terminator<'tcx> { self.kind.successors() } + /// Return `Some` if all successors are identical. + #[inline] + pub fn identical_successor(&self) -> Option { + let mut successors = self.successors(); + let first_succ = successors.next()?; + if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None } + } + #[inline] pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) { self.kind.successors_mut(f) diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 9f7bb3b03795..edea5cb2c724 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // statements itself to avoid moving the (relatively) large statements twice. // We do not push the statements directly into the target block (`bb`) as that is slower // due to additional reallocations - let mut merged_blocks = Vec::new(); + let mut merged_blocks: Vec = Vec::new(); let mut outer_changed = false; loop { let mut changed = false; @@ -159,8 +159,9 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { let mut terminator = self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); - terminator - .successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed)); + terminator.successors_mut(|successor| { + self.collapse_goto_chain(successor, &mut changed); + }); let mut inner_changed = true; merged_blocks.clear(); @@ -177,10 +178,18 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { if statements_to_merge > 0 { let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); statements.reserve(statements_to_merge); + let mut parent_bb_last_debuginfos = + std::mem::take(&mut self.basic_blocks[bb].after_last_stmt_debuginfos); for &from in &merged_blocks { + if let Some(stmt) = self.basic_blocks[from].statements.first_mut() { + stmt.debuginfos.prepend(&mut parent_bb_last_debuginfos); + } statements.append(&mut self.basic_blocks[from].statements); + parent_bb_last_debuginfos = + std::mem::take(&mut self.basic_blocks[from].after_last_stmt_debuginfos); } self.basic_blocks[bb].statements = statements; + self.basic_blocks[bb].after_last_stmt_debuginfos = parent_bb_last_debuginfos; } self.basic_blocks[bb].terminator = Some(terminator); @@ -220,10 +229,14 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // goto chains. We should probably benchmark different sizes. let mut terminators: SmallVec<[_; 1]> = Default::default(); let mut current = *start; + // If each successor has only one predecessor, it's a trivial goto chain. + // We can move all debuginfos to the last basic block. + let mut trivial_goto_chain = true; while let Some(terminator) = self.take_terminator_if_simple_goto(current) { let Terminator { kind: TerminatorKind::Goto { target }, .. } = terminator else { unreachable!(); }; + trivial_goto_chain &= self.pred_count[target] == 1; terminators.push((current, terminator)); current = target; } @@ -235,6 +248,17 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { else { unreachable!(); }; + if trivial_goto_chain { + let mut pred_debuginfos = + std::mem::take(&mut self.basic_blocks[current].after_last_stmt_debuginfos); + let debuginfos = if let Some(stmt) = self.basic_blocks[last].statements.first_mut() + { + &mut stmt.debuginfos + } else { + &mut self.basic_blocks[last].after_last_stmt_debuginfos + }; + debuginfos.prepend(&mut pred_debuginfos); + } *changed |= *target != last; *target = last; debug!("collapsing goto chain from {:?} to {:?}", current, target); diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff index d4a73351ee4a..7a1ac92f6dde 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -14,11 +14,13 @@ - - bb1: { - // DBG: _3 = &((*_1).0: i32); +- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); +- nop; _0 = copy ((*_1).2: i32); return; } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff index 1c12358ad893..fa4d3aebf838 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -17,13 +17,16 @@ - bb1: { (*_2) = const true; // DBG: _3 = &((*_1).0: i32); +- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); +- nop; _0 = copy ((*_1).2: i32); // DBG: _5 = &((*_1).2: i32); +- nop; return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff index de8e5612c878..b01c91f196b6 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -16,13 +16,16 @@ - - bb1: { // DBG: _2 = &((*_1).0: i32); +- nop; - goto -> bb2; - } - - bb2: { // DBG: _3 = &((*_1).1: i64); +- nop; _0 = copy ((*_1).2: i32); // DBG: _4 = &((*_1).2: i32); +- nop; return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff new file mode 100644 index 000000000000..caa90d79a1c2 --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff @@ -0,0 +1,40 @@ +- // MIR for `preserve_debuginfo_3` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_3` after SimplifyCfg-final + + fn preserve_debuginfo_3(_1: &Foo, _2: bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + debug foo_c => _5; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + let mut _5: &i32; + + bb0: { +- switchInt(copy _2) -> [1: bb1, otherwise: bb2]; ++ switchInt(copy _2) -> [1: bb2, otherwise: bb1]; + } + + bb1: { +- // DBG: _3 = &((*_1).0: i32); +- nop; +- goto -> bb3; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64); +- nop; + _0 = copy ((*_1).2: i32); + return; + } + +- bb3: { ++ bb2: { ++ // DBG: _3 = &((*_1).0: i32); + // DBG: _5 = &((*_1).2: i32); +- nop; + _0 = copy ((*_1).0: i32); + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff new file mode 100644 index 000000000000..d8c36990a5ff --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff @@ -0,0 +1,32 @@ +- // MIR for `preserve_debuginfo_identical_succs` before SimplifyCfg-final ++ // MIR for `preserve_debuginfo_identical_succs` after SimplifyCfg-final + + fn preserve_debuginfo_identical_succs(_1: &Foo, _2: bool) -> i32 { + debug foo_a => _3; + debug foo_b => _4; + debug foo_c => _5; + let mut _0: i32; + let mut _3: &i32; + let mut _4: &i64; + let mut _5: &i32; + + bb0: { +- switchInt(copy _2) -> [1: bb1, otherwise: bb1]; +- } +- +- bb1: { + // DBG: _3 = &((*_1).0: i32); +- nop; +- goto -> bb2; +- } +- +- bb2: { + // DBG: _4 = &((*_1).1: i64); +- nop; + _0 = copy ((*_1).2: i32); + // DBG: _5 = &((*_1).2: i32); +- nop; + return; + } + } + diff --git a/tests/mir-opt/debuginfo/simplifycfg.rs b/tests/mir-opt/debuginfo/simplifycfg.rs new file mode 100644 index 000000000000..2bd510fd3b9d --- /dev/null +++ b/tests/mir-opt/debuginfo/simplifycfg.rs @@ -0,0 +1,207 @@ +//@ test-mir-pass: SimplifyCfg-final +//@ compile-flags: -Zmir-enable-passes=+DeadStoreElimination-initial + +#![feature(core_intrinsics, custom_mir)] +#![crate_type = "lib"] + +use std::intrinsics::mir::*; + +pub struct Foo { + a: i32, + b: i64, + c: i32, +} + +// EMIT_MIR simplifycfg.drop_debuginfo.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn drop_debuginfo(foo: &Foo, c: bool) -> i32 { + // CHECK-LABEL: fn drop_debuginfo + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + { + match c { + true => tmp, + _ => ret, + } + } + tmp = { + // Because we don't know if `c` is always true, we must drop this debuginfo. + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn preserve_debuginfo_1(foo: &Foo, v: &mut bool) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_1 + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: (*_2) = const true; + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + Goto(tmp) + } + tmp = { + *v = true; + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + _foo_c = &(*foo).c; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn preserve_debuginfo_2(foo: &Foo) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_2 + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + Goto(tmp) + } + tmp = { + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + _foo_c = &(*foo).c; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn preserve_debuginfo_3(foo: &Foo, c: bool) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_3 + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: switchInt(copy _2) -> [1: bb2, otherwise: bb1]; + // CHECK: bb1: { + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: return; + // CHECK: bb2: { + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: _0 = copy ((*_1).0: i32); + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + match c { + true => tmp, + _ => ret, + } + } + tmp = { + _foo_a = &(*foo).a; + Goto(ret_1) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + Return() + } + ret_1 = { + _foo_c = &(*foo).c; + RET = (*foo).a; + Return() + } + } +} + +// EMIT_MIR simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn preserve_debuginfo_identical_succs(foo: &Foo, c: bool) -> i32 { + // CHECK-LABEL: fn preserve_debuginfo_identical_succs + // CHECK: debug foo_a => [[foo_a:_[0-9]+]]; + // CHECK: debug foo_b => [[foo_b:_[0-9]+]]; + // CHECK: debug foo_c => [[foo_c:_[0-9]+]]; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32) + // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64) + // CHECK-NEXT: _0 = copy ((*_1).2: i32); + // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32) + // CHECK-NEXT: return; + mir! { + let _foo_a: &i32; + let _foo_b: &i64; + let _foo_c: &i32; + debug foo_a => _foo_a; + debug foo_b => _foo_b; + debug foo_c => _foo_c; + { + match c { + true => tmp, + _ => tmp, + } + } + tmp = { + _foo_a = &(*foo).a; + Goto(ret) + } + ret = { + _foo_b = &(*foo).b; + RET = (*foo).c; + _foo_c = &(*foo).c; + Return() + } + } +} From 85b2f706939528b5796d98e82c183637f8338cd1 Mon Sep 17 00:00:00 2001 From: dianqk Date: Tue, 15 Jul 2025 22:54:54 +0800 Subject: [PATCH 472/537] mir-opt: Eliminate trivial unnecessary storage annotations --- compiler/rustc_middle/src/mir/statement.rs | 14 +-- .../rustc_mir_dataflow/src/impls/liveness.rs | 4 +- .../src/dead_store_elimination.rs | 16 ++- compiler/rustc_mir_transform/src/inline.rs | 8 +- compiler/rustc_mir_transform/src/simplify.rs | 118 ++++++++++++------ ...le.cycle.DeadStoreElimination-initial.diff | 4 - ...ad_first.DeadStoreElimination-initial.diff | 1 - ...ef.tuple.DeadStoreElimination-initial.diff | 5 +- ...ycfg.drop_debuginfo.SimplifyCfg-final.diff | 2 - ...reserve_debuginfo_1.SimplifyCfg-final.diff | 3 - ...reserve_debuginfo_2.SimplifyCfg-final.diff | 3 - ...reserve_debuginfo_3.SimplifyCfg-final.diff | 3 - ...nfo_identical_succs.SimplifyCfg-final.diff | 3 - .../inline_shims.drop.Inline.panic-abort.diff | 4 - ...inline_shims.drop.Inline.panic-unwind.diff | 2 - ...y.run2-{closure#0}.Inline.panic-abort.diff | 11 -- ....run2-{closure#0}.Inline.panic-unwind.diff | 11 -- .../issue_101973.inner.GVN.panic-abort.diff | 1 - .../issue_101973.inner.GVN.panic-unwind.diff | 1 - ...implifyComparisonIntegral.panic-abort.diff | 6 - ...mplifyComparisonIntegral.panic-unwind.diff | 6 - ...git.PreCodegen.after.32bit.panic-abort.mir | 4 - ...it.PreCodegen.after.32bit.panic-unwind.mir | 4 - ...git.PreCodegen.after.64bit.panic-abort.mir | 4 - ...it.PreCodegen.after.64bit.panic-unwind.mir | 4 - ...p_forward.PreCodegen.after.panic-abort.mir | 40 ++---- ..._forward.PreCodegen.after.panic-unwind.mir | 40 ++---- ...as_copy.clone_as_copy.PreCodegen.after.mir | 2 - ...py.enum_clone_as_copy.PreCodegen.after.mir | 46 ++----- tests/mir-opt/pre-codegen/clone_as_copy.rs | 16 +-- ...ace.PreCodegen.after.32bit.panic-abort.mir | 38 ++---- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 38 ++---- ...ace.PreCodegen.after.64bit.panic-abort.mir | 38 ++---- ...ce.PreCodegen.after.64bit.panic-unwind.mir | 38 ++---- tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 2 +- .../loops.int_range.PreCodegen.after.mir | 6 - .../loops.vec_move.PreCodegen.after.mir | 28 ----- ...variant_a-{closure#0}.PreCodegen.after.mir | 22 ---- ...ated_loop.PreCodegen.after.panic-abort.mir | 14 --- ...ward_loop.PreCodegen.after.panic-abort.mir | 14 --- ...ard_loop.PreCodegen.after.panic-unwind.mir | 14 --- ...erse_loop.PreCodegen.after.panic-abort.mir | 12 -- ...rse_loop.PreCodegen.after.panic-unwind.mir | 12 -- ..._is_empty.PreCodegen.after.panic-abort.mir | 8 -- ...is_empty.PreCodegen.after.panic-unwind.mir | 8 -- ...next_back.PreCodegen.after.panic-abort.mir | 12 -- ...ext_back.PreCodegen.after.panic-unwind.mir | 12 -- ...iter_next.PreCodegen.after.panic-abort.mir | 14 --- ...ter_next.PreCodegen.after.panic-unwind.mir | 14 --- tests/ui/extern/extern-types-field-offset.rs | 5 + 50 files changed, 179 insertions(+), 556 deletions(-) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 9deb43eb7084..67b4448cfcdd 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -30,16 +30,10 @@ impl<'tcx> Statement<'tcx> { } let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop); if !drop_debuginfo { - match replaced_stmt { - StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place))) - if let Some(local) = place.as_local() => - { - self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place)); - } - _ => { - bug!("debuginfo is not yet supported.") - } - } + let Some(debuginfo) = replaced_stmt.as_debuginfo() else { + bug!("debuginfo is not yet supported.") + }; + self.debuginfos.push(debuginfo); } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 24da4b0bea28..037e2720f365 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -233,8 +233,10 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { // Compute the place that we are storing to, if any let destination = match stmt_kind { StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove() + // FIXME: We are not sure how we should represent this debugging information for some statements, + // keep it for now. && (!debuginfo_locals.contains(place.local) - || (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..))))) + || (place.as_local().is_some() && stmt_kind.as_debuginfo().is_some()))) .then_some(*place), StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { (!debuginfo_locals.contains(place.local)).then_some(**place) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index a5f8a22e83c8..732c3dcd44ab 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -22,13 +22,15 @@ use rustc_mir_dataflow::impls::{ LivenessTransferFunction, MaybeTransitiveLiveLocals, borrowed_locals, }; +use crate::simplify::UsedInStmtLocals; use crate::util::is_within_packed; /// Performs the optimization on the body /// /// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this /// body. It can be generated via the [`borrowed_locals`] function. -fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +/// Returns true if any instruction is eliminated. +fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let borrowed_locals = borrowed_locals(body); // If the user requests complete debuginfo, mark the locals that appear in it as live, so @@ -97,8 +99,9 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } if patch.is_empty() && call_operands_to_move.is_empty() { - return; + return false; } + let eliminated = !patch.is_empty(); let bbs = body.basic_blocks.as_mut_preserves_cfg(); for (Location { block, statement_index }, drop_debuginfo) in patch { @@ -112,6 +115,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Operand::Copy(place) = *arg else { bug!() }; *arg = Operand::Move(place); } + + eliminated } pub(super) enum DeadStoreElimination { @@ -132,7 +137,12 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - eliminate(tcx, body); + if eliminate(tcx, body) { + UsedInStmtLocals::new(body).remove_unused_storage_annotations(body); + for data in body.basic_blocks.as_mut_preserves_cfg() { + data.strip_nops(); + } + } } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 3d49eb4e8ef7..8593e25d6aa5 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -21,7 +21,7 @@ use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::{CostChecker, is_call_like}; use crate::deref_separator::deref_finder; -use crate::simplify::simplify_cfg; +use crate::simplify::{UsedInStmtLocals, simplify_cfg}; use crate::validate::validate_types; use crate::{check_inline, util}; @@ -935,7 +935,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( in_cleanup_block: false, return_block, tcx, - always_live_locals: DenseBitSet::new_filled(callee_body.local_decls.len()), + always_live_locals: UsedInStmtLocals::new(&callee_body).locals, }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -995,6 +995,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( // people working on rust can build with or without debuginfo while // still getting consistent results from the mir-opt tests. caller_body.var_debug_info.append(&mut callee_body.var_debug_info); + } else { + for bb in callee_body.basic_blocks_mut() { + bb.drop_debuginfo(); + } } caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut()); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index edea5cb2c724..0f23482ea8b1 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -35,12 +35,12 @@ //! pre-"runtime" MIR! use itertools::Itertools as _; +use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; -use rustc_middle::mir::visit::{ - MutVisitor, MutatingUseContext, NonUseContext, PlaceContext, Visitor, -}; +use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_span::DUMMY_SP; use smallvec::SmallVec; use tracing::{debug, trace}; @@ -329,7 +329,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop)) + blk.strip_nops(); } } } @@ -502,17 +502,22 @@ fn make_local_map( /// Keeps track of used & unused locals. struct UsedLocals { increment: bool, - arg_count: u32, use_count: IndexVec, + always_used: DenseBitSet, } impl UsedLocals { /// Determines which locals are used & unused in the given body. fn new(body: &Body<'_>) -> Self { + let mut always_used = debuginfo_locals(body); + always_used.insert(RETURN_PLACE); + for arg in body.args_iter() { + always_used.insert(arg); + } let mut this = Self { increment: true, - arg_count: body.arg_count.try_into().unwrap(), use_count: IndexVec::from_elem(0, &body.local_decls), + always_used, }; this.visit_body(body); this @@ -520,10 +525,16 @@ impl UsedLocals { /// Checks if local is used. /// - /// Return place and arguments are always considered used. + /// Return place, arguments, var debuginfo are always considered used. fn is_used(&self, local: Local) -> bool { - trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]); - local.as_u32() <= self.arg_count || self.use_count[local] != 0 + trace!( + "is_used({:?}): use_count: {:?}, always_used: {}", + local, + self.use_count[local], + self.always_used.contains(local) + ); + // To keep things simple, we don't handle debugging information here, these are in DSE. + self.always_used.contains(local) || self.use_count[local] != 0 } /// Updates the use counts to reflect the removal of given statement. @@ -568,17 +579,9 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::ConstEvalCounter | StatementKind::Nop | StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) => { - for debuginfo in statement.debuginfos.iter() { - self.visit_statement_debuginfo(debuginfo, location); - } - } - + | StatementKind::StorageDead(..) => {} StatementKind::Assign(box (ref place, ref rvalue)) => { if rvalue.is_safe_to_remove() { - for debuginfo in statement.debuginfos.iter() { - self.visit_statement_debuginfo(debuginfo, location); - } self.visit_lhs(place, location); self.visit_rvalue(rvalue, location); } else { @@ -589,18 +592,18 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { StatementKind::SetDiscriminant { ref place, variant_index: _ } | StatementKind::Deinit(ref place) | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { - for debuginfo in statement.debuginfos.iter() { - self.visit_statement_debuginfo(debuginfo, location); - } self.visit_lhs(place, location); } } } fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) { + if matches!(ctx, PlaceContext::NonUse(_)) { + return; + } if self.increment { self.use_count[local] += 1; - } else if ctx != PlaceContext::NonUse(NonUseContext::VarDebugInfo) { + } else { assert_ne!(self.use_count[local], 0); self.use_count[local] -= 1; } @@ -620,28 +623,26 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. - data.retain_statements(|statement| { - let keep = match &statement.kind { + for statement in data.statements.iter_mut() { + let keep_statement = match &statement.kind { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { used_locals.is_used(*local) } - StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), - - StatementKind::SetDiscriminant { place, .. } - | StatementKind::BackwardIncompatibleDropHint { place, reason: _ } - | StatementKind::Deinit(place) => used_locals.is_used(place.local), - StatementKind::Nop => false, - _ => true, + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { box place, .. } + | StatementKind::BackwardIncompatibleDropHint { box place, .. } + | StatementKind::Deinit(box place) => used_locals.is_used(place.local), + _ => continue, }; - - if !keep { - trace!("removing statement {:?}", statement); - modified = true; - used_locals.statement_removed(statement); + if keep_statement { + continue; } - - keep - }); + trace!("removing statement {:?}", statement); + modified = true; + used_locals.statement_removed(statement); + statement.make_nop(true); + } + data.strip_nops(); } } } @@ -660,3 +661,42 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { *l = self.map[*l].unwrap(); } } + +pub(crate) struct UsedInStmtLocals { + pub(crate) locals: DenseBitSet, +} + +impl UsedInStmtLocals { + pub(crate) fn new(body: &Body<'_>) -> Self { + let mut this = Self { locals: DenseBitSet::new_empty(body.local_decls.len()) }; + this.visit_body(body); + this + } + + pub(crate) fn remove_unused_storage_annotations<'tcx>(&self, body: &mut Body<'tcx>) { + for data in body.basic_blocks.as_mut_preserves_cfg() { + // Remove unnecessary StorageLive and StorageDead annotations. + for statement in data.statements.iter_mut() { + let keep_statement = match &statement.kind { + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + self.locals.contains(*local) + } + _ => continue, + }; + if keep_statement { + continue; + } + statement.make_nop(true); + } + } + } +} + +impl<'tcx> Visitor<'tcx> for UsedInStmtLocals { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + if matches!(context, PlaceContext::NonUse(_)) { + return; + } + self.locals.insert(local); + } +} diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff index ff18df1efcfc..d584de6861c0 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff @@ -19,10 +19,6 @@ - _3 = copy _2; - _2 = copy _1; - _1 = copy _5; -+ nop; -+ nop; -+ nop; -+ nop; _4 = cond() -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff index d823241bc620..2a793e24990a 100644 --- a/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff @@ -15,7 +15,6 @@ StorageLive(_2); - _2 = &((*_1).2: i32); + // DBG: _2 = &((*_1).2: i32); -+ nop; StorageLive(_3); StorageLive(_4); _4 = &((*_1).0: i32); diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff index 0547a42cab24..af28c1b9aa87 100644 --- a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -12,14 +12,13 @@ } bb0: { - StorageLive(_2); +- StorageLive(_2); _3 = deref_copy (_1.1: &Foo); - _2 = &((*_3).2: i32); + // DBG: _2 = &((*_3).2: i32); -+ nop; _4 = deref_copy (_1.1: &Foo); _0 = copy ((*_4).0: i32); - StorageDead(_2); +- StorageDead(_2); return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff index 7a1ac92f6dde..d4a73351ee4a 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff @@ -14,13 +14,11 @@ - - bb1: { - // DBG: _3 = &((*_1).0: i32); -- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); -- nop; _0 = copy ((*_1).2: i32); return; } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff index fa4d3aebf838..1c12358ad893 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff @@ -17,16 +17,13 @@ - bb1: { (*_2) = const true; // DBG: _3 = &((*_1).0: i32); -- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); -- nop; _0 = copy ((*_1).2: i32); // DBG: _5 = &((*_1).2: i32); -- nop; return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff index b01c91f196b6..de8e5612c878 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff @@ -16,16 +16,13 @@ - - bb1: { // DBG: _2 = &((*_1).0: i32); -- nop; - goto -> bb2; - } - - bb2: { // DBG: _3 = &((*_1).1: i64); -- nop; _0 = copy ((*_1).2: i32); // DBG: _4 = &((*_1).2: i32); -- nop; return; } } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff index caa90d79a1c2..11372a262a76 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff @@ -17,13 +17,11 @@ bb1: { - // DBG: _3 = &((*_1).0: i32); -- nop; - goto -> bb3; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); -- nop; _0 = copy ((*_1).2: i32); return; } @@ -32,7 +30,6 @@ + bb2: { + // DBG: _3 = &((*_1).0: i32); // DBG: _5 = &((*_1).2: i32); -- nop; _0 = copy ((*_1).0: i32); return; } diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff index d8c36990a5ff..0c6a75237d8b 100644 --- a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff +++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff @@ -16,16 +16,13 @@ - - bb1: { // DBG: _3 = &((*_1).0: i32); -- nop; - goto -> bb2; - } - - bb2: { // DBG: _4 = &((*_1).1: i64); -- nop; _0 = copy ((*_1).2: i32); // DBG: _5 = &((*_1).2: i32); -- nop; return; } } diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index f7729c7c5fa6..7fa22524f008 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -64,9 +64,7 @@ + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); -+ // DBG: _11 = &((*_6).0: alloc::raw_vec::RawVec); + StorageLive(_12); -+ // DBG: _12 = &(((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + StorageLive(_13); + _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _9 = copy _13 as *mut A (Transmute); @@ -92,7 +90,6 @@ _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; + StorageLive(_17); -+ StorageLive(_18); + _17 = discriminant((*_5)); + switchInt(move _17) -> [0: bb5, otherwise: bb6]; } @@ -118,7 +115,6 @@ + } + + bb5: { -+ StorageDead(_18); + StorageDead(_17); StorageDead(_5); return; diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff index 183242764252..34f89da19f51 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff @@ -27,13 +27,11 @@ _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind continue]; + StorageLive(_6); -+ StorageLive(_7); + _6 = discriminant((*_5)); + switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { -+ StorageDead(_7); + StorageDead(_6); StorageDead(_5); return; diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 649b5a652027..bb81cb4e2600 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -129,11 +129,8 @@ _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); - _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable]; -+ StorageLive(_11); -+ StorageLive(_15); + StorageLive(_16); + StorageLive(_25); -+ StorageLive(_27); + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); @@ -166,11 +163,8 @@ + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); -+ StorageDead(_27); + StorageDead(_25); + StorageDead(_16); -+ StorageDead(_15); -+ StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -223,17 +217,13 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_44); -+ StorageLive(_45); + StorageLive(_49); + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); -+ // DBG: _45 = &_19; + StorageLive(_46); -+ // DBG: _46 = &(_19.0: &mut std::future::Ready<()>); + _44 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_46); -+ // DBG: _43 = &((*_44).0: std::option::Option<()>); + StorageLive(_47); + _47 = Option::<()>::None; + _42 = copy ((*_44).0: std::option::Option<()>); @@ -315,7 +305,6 @@ + _18 = Poll::<()>::Ready(move _41); + StorageDead(_41); + StorageDead(_49); -+ StorageDead(_45); + StorageDead(_44); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 32021b20ef44..520c54824e15 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -131,11 +131,8 @@ _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); - _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5]; -+ StorageLive(_11); -+ StorageLive(_15); + StorageLive(_16); + StorageLive(_25); -+ StorageLive(_27); + StorageLive(_30); + StorageLive(_31); + StorageLive(_32); @@ -180,11 +177,8 @@ + StorageDead(_32); + StorageDead(_31); + StorageDead(_30); -+ StorageDead(_27); + StorageDead(_25); + StorageDead(_16); -+ StorageDead(_15); -+ StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -240,17 +234,13 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_46); -+ StorageLive(_47); + StorageLive(_51); + StorageLive(_43); + StorageLive(_44); + StorageLive(_45); -+ // DBG: _47 = &_19; + StorageLive(_48); -+ // DBG: _48 = &(_19.0: &mut std::future::Ready<()>); + _46 = copy (_19.0: &mut std::future::Ready<()>); + StorageDead(_48); -+ // DBG: _45 = &((*_46).0: std::option::Option<()>); + StorageLive(_49); + _49 = Option::<()>::None; + _44 = copy ((*_46).0: std::option::Option<()>); @@ -356,7 +346,6 @@ + _18 = Poll::<()>::Ready(move _43); + StorageDead(_43); + StorageDead(_51); -+ StorageDead(_47); + StorageDead(_46); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff index ac88fe67bb86..3ea7387a48d3 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff @@ -30,7 +30,6 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; - nop; - StorageLive(_14); - _14 = BitAnd(copy _5, const 255_u32); - _4 = BitOr(const 0_u32, move _14); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff index 96c3cae2d334..832db856b2cf 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff @@ -30,7 +30,6 @@ StorageLive(_4); StorageLive(_5); _5 = copy _1; - nop; - StorageLive(_14); - _14 = BitAnd(copy _5, const 255_u32); - _4 = BitOr(const 0_u32, move _14); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index a294c1b4588d..614d9ad440d2 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -33,15 +33,9 @@ } bb2: { - StorageLive(_5); // DBG: _5 = &(*_2)[0 of 3]; - StorageLive(_6); // DBG: _6 = &(*_2)[1 of 3]; - StorageLive(_7); // DBG: _7 = &(*_2)[2 of 3]; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); StorageDead(_4); return; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index 691271cf94ed..57a88cf89841 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -33,15 +33,9 @@ } bb2: { - StorageLive(_5); // DBG: _5 = &(*_2)[0 of 3]; - StorageLive(_6); // DBG: _6 = &(*_2)[1 of 3]; - StorageLive(_7); // DBG: _7 = &(*_2)[2 of 3]; - StorageDead(_7); - StorageDead(_6); - StorageDead(_5); StorageDead(_4); return; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir index d4248f5d87fb..b5c23822162c 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-abort.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -21,17 +20,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir index a834932df5a8..f22b8835735d 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.32bit.panic-unwind.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -21,17 +20,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir index d4248f5d87fb..b5c23822162c 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-abort.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -21,17 +20,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable]; } bb1: { - // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir index a834932df5a8..f22b8835735d 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.64bit.panic-unwind.mir @@ -6,7 +6,6 @@ fn num_to_digit(_1: char) -> u32 { let mut _4: std::option::Option; scope 1 (inlined char::methods::::is_digit) { let _2: std::option::Option; - let mut _7: &std::option::Option; scope 2 (inlined Option::::is_some) { let mut _3: isize; scope 3 { @@ -21,17 +20,14 @@ fn num_to_digit(_1: char) -> u32 { } bb0: { - StorageLive(_7); StorageLive(_2); _2 = char::methods::::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue]; } bb1: { - // DBG: _7 = &_2; StorageLive(_3); _3 = discriminant(_2); StorageDead(_2); - StorageDead(_7); switchInt(move _3) -> [1: bb2, otherwise: bb7]; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index 23dbc066dd52..83478e60b5d4 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -5,9 +5,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let _8: std::option::Option; - let mut _10: u16; - let mut _11: &std::option::Option; + let mut _8: u16; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -15,9 +13,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _9: (); + let _7: (); } } } @@ -38,8 +35,6 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); - StorageLive(_11); - StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -58,55 +53,34 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); - StorageLive(_7); - _7 = AddUnchecked(copy _1, copy _4); - _8 = Option::::Some(move _7); - StorageDead(_7); - // DBG: _11 = &_8; - StorageDead(_8); - StorageDead(_11); goto -> bb7; } bb3: { - _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); - _8 = const Option::::None; - // DBG: _11 = &_8; goto -> bb6; } bb5: { StorageDead(_3); - _8 = const Option::::None; - // DBG: _11 = &_8; goto -> bb6; } bb6: { - StorageDead(_8); - StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind unreachable]; } bb7: { - StorageLive(_10); - _10 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _10); - StorageDead(_10); + StorageLive(_8); + _8 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _8); + StorageDead(_8); StorageDead(_4); return; } } - -ALLOC0 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} - -ALLOC1 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index ac15f070597e..ac7a6e044519 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -5,9 +5,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { debug n => _2; let mut _0: u16; scope 1 (inlined ::forward) { - let _8: std::option::Option; - let mut _10: u16; - let mut _11: &std::option::Option; + let mut _8: u16; scope 2 { } scope 3 (inlined ::forward_checked) { @@ -15,9 +13,8 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - let mut _7: u16; scope 7 (inlined std::intrinsics::unlikely) { - let _9: (); + let _7: (); } } } @@ -38,8 +35,6 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb0: { StorageLive(_4); - StorageLive(_11); - StorageLive(_8); StorageLive(_3); _3 = Gt(copy _2, const 65535_usize); switchInt(move _3) -> [0: bb1, otherwise: bb5]; @@ -58,55 +53,34 @@ fn step_forward(_1: u16, _2: usize) -> u16 { bb2: { StorageDead(_5); StorageDead(_6); - StorageLive(_7); - _7 = AddUnchecked(copy _1, copy _4); - _8 = Option::::Some(move _7); - StorageDead(_7); - // DBG: _11 = &_8; - StorageDead(_8); - StorageDead(_11); goto -> bb7; } bb3: { - _9 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_5); StorageDead(_6); - _8 = const Option::::None; - // DBG: _11 = &_8; goto -> bb6; } bb5: { StorageDead(_3); - _8 = const Option::::None; - // DBG: _11 = &_8; goto -> bb6; } bb6: { - StorageDead(_8); - StorageDead(_11); assert(!const true, "attempt to compute `{} + {}`, which would overflow", const core::num::::MAX, const 1_u16) -> [success: bb7, unwind continue]; } bb7: { - StorageLive(_10); - _10 = copy _2 as u16 (IntToInt); - _0 = Add(copy _1, copy _10); - StorageDead(_10); + StorageLive(_8); + _8 = copy _2 as u16 (IntToInt); + _0 = Add(copy _1, copy _8); + StorageDead(_8); StorageDead(_4); return; } } - -ALLOC0 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} - -ALLOC1 (size: 4, align: 2) { - 00 00 __ __ │ ..░░ -} diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir index 66239a0ef663..1e6e2ee1b8b7 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir @@ -12,10 +12,8 @@ fn clone_as_copy(_1: &NestCopy) -> NestCopy { } bb0: { - StorageLive(_2); // DBG: _2 = &((*_1).1: AllCopy); _0 = copy (*_1); - StorageDead(_2); return; } } diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir index aa03cec070ad..76bb49bc9c1b 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir @@ -5,58 +5,28 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 { let mut _0: Enum1; scope 1 (inlined ::clone) { debug self => _1; - let mut _2: isize; - let _3: &AllCopy; - let _4: &NestCopy; + let _2: &AllCopy; + let _3: &NestCopy; scope 2 { - debug __self_0 => _3; + debug __self_0 => _2; scope 6 (inlined ::clone) { - debug self => _3; + debug self => _2; } } scope 3 { - debug __self_0 => _4; + debug __self_0 => _3; scope 4 (inlined ::clone) { - debug self => _4; - let _5: &AllCopy; + debug self => _3; + let _4: &AllCopy; scope 5 (inlined ::clone) { - debug self => _5; + debug self => _4; } } } } bb0: { - StorageLive(_2); - StorageLive(_3); - StorageLive(_4); - _2 = discriminant((*_1)); - switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; - } - - bb1: { - // DBG: _3 = &(((*_1) as A).0: AllCopy); _0 = copy (*_1); - goto -> bb3; - } - - bb2: { - // DBG: _4 = &(((*_1) as B).0: NestCopy); - StorageLive(_5); - // DBG: _5 = &((((*_1) as B).0: NestCopy).1: AllCopy); - StorageDead(_5); - _0 = copy (*_1); - goto -> bb3; - } - - bb3: { - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); return; } - - bb4: { - unreachable; - } } diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.rs b/tests/mir-opt/pre-codegen/clone_as_copy.rs index f5ff1854d387..00f24754d591 100644 --- a/tests/mir-opt/pre-codegen/clone_as_copy.rs +++ b/tests/mir-opt/pre-codegen/clone_as_copy.rs @@ -25,19 +25,19 @@ enum Enum1 { // EMIT_MIR clone_as_copy.clone_as_copy.PreCodegen.after.mir fn clone_as_copy(v: &NestCopy) -> NestCopy { // CHECK-LABEL: fn clone_as_copy( - // CHECK-NOT: = AllCopy { {{.*}} }; - // CHECK-NOT: = NestCopy { {{.*}} }; - // CHECK: _0 = copy (*_1); - // CHECK: return; + // CHECK: let [[DEAD_VAR:_.*]]: &AllCopy; + // CHECK: bb0: { + // CHECK-NEXT: DBG: [[DEAD_VAR]] = &((*_1).1: AllCopy) + // CHECK-NEXT: _0 = copy (*_1); + // CHECK-NEXT: return; v.clone() } -// FIXME: We can merge into exactly one assignment statement. // EMIT_MIR clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir fn enum_clone_as_copy(v: &Enum1) -> Enum1 { // CHECK-LABEL: fn enum_clone_as_copy( - // CHECK-NOT: = Enum1:: - // CHECK: _0 = copy (*_1); - // CHECK: _0 = copy (*_1); + // CHECK: bb0: { + // CHECK-NEXT: _0 = copy (*_1); + // CHECK-NEXT: return; v.clone() } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 0dd2125dbe0d..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -8,10 +8,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); - let mut _13: &std::alloc::Layout; + let _11: (); scope 3 { - let _8: std::alloc::Layout; + let _8: std::ptr::alignment::AlignmentEnum; scope 4 { scope 12 (inlined Layout::size) { } @@ -27,19 +26,15 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; - let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; - let mut _15: &std::alloc::Layout; - let mut _16: &std::alloc::Layout; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { - let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -68,7 +63,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { - StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -80,45 +74,31 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); + StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = Layout { size: copy _5, align: copy _7 }; + _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_6); StorageDead(_4); - StorageLive(_13); - // DBG: _13 = &_8; - StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_14); - // DBG: _14 = &_8; - StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_15); - // DBG: _15 = &_8; - StorageDead(_15); - StorageLive(_11); - StorageLive(_16); - // DBG: _16 = &_8; StorageLive(_10); - _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _11 = discriminant(_10); - StorageDead(_10); - StorageDead(_16); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _10 = discriminant(_8); + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 0dd2125dbe0d..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -8,10 +8,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); - let mut _13: &std::alloc::Layout; + let _11: (); scope 3 { - let _8: std::alloc::Layout; + let _8: std::ptr::alignment::AlignmentEnum; scope 4 { scope 12 (inlined Layout::size) { } @@ -27,19 +26,15 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; - let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; - let mut _15: &std::alloc::Layout; - let mut _16: &std::alloc::Layout; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { - let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -68,7 +63,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { - StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -80,45 +74,31 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); + StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = Layout { size: copy _5, align: copy _7 }; + _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_6); StorageDead(_4); - StorageLive(_13); - // DBG: _13 = &_8; - StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_14); - // DBG: _14 = &_8; - StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_15); - // DBG: _15 = &_8; - StorageDead(_15); - StorageLive(_11); - StorageLive(_16); - // DBG: _16 = &_8; StorageLive(_10); - _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _11 = discriminant(_10); - StorageDead(_10); - StorageDead(_16); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _10 = discriminant(_8); + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 0dd2125dbe0d..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -8,10 +8,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); - let mut _13: &std::alloc::Layout; + let _11: (); scope 3 { - let _8: std::alloc::Layout; + let _8: std::ptr::alignment::AlignmentEnum; scope 4 { scope 12 (inlined Layout::size) { } @@ -27,19 +26,15 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; - let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; - let mut _15: &std::alloc::Layout; - let mut _16: &std::alloc::Layout; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { - let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -68,7 +63,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { - StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -80,45 +74,31 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); + StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = Layout { size: copy _5, align: copy _7 }; + _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_6); StorageDead(_4); - StorageLive(_13); - // DBG: _13 = &_8; - StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_14); - // DBG: _14 = &_8; - StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_15); - // DBG: _15 = &_8; - StorageDead(_15); - StorageLive(_11); - StorageLive(_16); - // DBG: _16 = &_8; StorageLive(_10); - _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _11 = discriminant(_10); - StorageDead(_10); - StorageDead(_16); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _10 = discriminant(_8); + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 0dd2125dbe0d..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -8,10 +8,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); - let mut _13: &std::alloc::Layout; + let _11: (); scope 3 { - let _8: std::alloc::Layout; + let _8: std::ptr::alignment::AlignmentEnum; scope 4 { scope 12 (inlined Layout::size) { } @@ -27,19 +26,15 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } scope 18 (inlined ::deallocate) { let mut _9: *mut u8; - let mut _14: &std::alloc::Layout; scope 19 (inlined Layout::size) { } scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; - let mut _15: &std::alloc::Layout; - let mut _16: &std::alloc::Layout; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { - let mut _10: std::ptr::alignment::AlignmentEnum; scope 24 (inlined std::ptr::Alignment::as_usize) { } } @@ -68,7 +63,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } bb0: { - StorageLive(_8); StorageLive(_2); _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); StorageLive(_4); @@ -80,45 +74,31 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb1: { _6 = AlignOf(T); + StorageLive(_7); _7 = copy _6 as std::ptr::Alignment (Transmute); - _8 = Layout { size: copy _5, align: copy _7 }; + _8 = move (_7.0: std::ptr::alignment::AlignmentEnum); + StorageDead(_7); StorageDead(_6); StorageDead(_4); - StorageLive(_13); - // DBG: _13 = &_8; - StorageDead(_13); switchInt(copy _5) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_14); - // DBG: _14 = &_8; - StorageDead(_14); StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_15); - // DBG: _15 = &_8; - StorageDead(_15); - StorageLive(_11); - StorageLive(_16); - // DBG: _16 = &_8; StorageLive(_10); - _10 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _11 = discriminant(_10); - StorageDead(_10); - StorageDead(_16); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _10 = discriminant(_8); + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } bb4: { StorageDead(_2); - StorageDead(_8); return; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index c291366a694e..9ceba9444b8d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -11,7 +11,7 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]> // CHECK: [[ALIGN:_.+]] = AlignOf(T); // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); - // CHECK: [[C:_.+]] = copy ([[B]].0: std::ptr::alignment::AlignmentEnum); + // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir index b1af3141ee61..beb7b936ccf7 100644 --- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir @@ -60,9 +60,7 @@ fn int_range(_1: usize, _2: usize) -> () { StorageLive(_9); // DBG: _12 = &_3; StorageLive(_6); - StorageLive(_13); // DBG: _13 = &(_3.0: usize); - StorageLive(_14); // DBG: _14 = &(_3.1: usize); StorageLive(_4); _4 = copy (_3.0: usize); @@ -75,16 +73,12 @@ fn int_range(_1: usize, _2: usize) -> () { } bb2: { - StorageDead(_14); - StorageDead(_13); StorageDead(_6); StorageDead(_9); return; } bb3: { - StorageDead(_14); - StorageDead(_13); _7 = copy (_3.0: usize); StorageLive(_8); _8 = AddUnchecked(copy _7, const 1_usize); diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir index 03cdc221c308..f453741dc6c7 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir @@ -171,12 +171,9 @@ fn vec_move(_1: Vec) -> () { bb0: { StorageLive(_22); - StorageLive(_29); StorageLive(_6); StorageLive(_7); - StorageLive(_33); StorageLive(_11); - StorageLive(_35); StorageLive(_20); StorageLive(_5); StorageLive(_4); @@ -184,30 +181,18 @@ fn vec_move(_1: Vec) -> () { StorageLive(_2); _2 = ManuallyDrop::> { value: copy _1 }; StorageLive(_3); - StorageLive(_30); // DBG: _30 = &_2; // DBG: _29 = &(_2.0: std::vec::Vec); - StorageDead(_30); - StorageLive(_39); // DBG: _39 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - StorageLive(_40); // DBG: _40 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); - StorageDead(_40); - StorageDead(_39); _3 = &raw const ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); StorageDead(_3); - StorageLive(_31); - StorageLive(_32); // DBG: _32 = &_2; - StorageDead(_32); // DBG: _31 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - StorageLive(_41); // DBG: _41 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _4 = copy (((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _5 = copy _4 as *const impl Sized (Transmute); _6 = NonNull:: { pointer: copy _5 }; - StorageDead(_41); - StorageDead(_31); _7 = copy _4 as *mut impl Sized (Transmute); switchInt(const ::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -215,10 +200,8 @@ fn vec_move(_1: Vec) -> () { bb1: { StorageLive(_10); StorageLive(_8); - StorageLive(_36); // DBG: _36 = &_2; // DBG: _35 = &(_2.0: std::vec::Vec); - StorageDead(_36); _8 = copy ((_2.0: std::vec::Vec).1: usize); StorageLive(_9); _9 = Le(copy _8, const ::MAX_SLICE_LEN); @@ -233,10 +216,8 @@ fn vec_move(_1: Vec) -> () { bb2: { StorageLive(_12); - StorageLive(_34); // DBG: _34 = &_2; // DBG: _33 = &(_2.0: std::vec::Vec); - StorageDead(_34); _12 = copy ((_2.0: std::vec::Vec).1: usize); StorageLive(_13); _13 = Le(copy _12, const ::MAX_SLICE_LEN); @@ -264,12 +245,8 @@ fn vec_move(_1: Vec) -> () { } bb4: { - StorageLive(_37); - StorageLive(_38); // DBG: _38 = &_2; - StorageDead(_38); // DBG: _37 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - StorageLive(_42); // DBG: _42 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); StorageLive(_19); _19 = SizeOf(impl Sized); @@ -291,20 +268,15 @@ fn vec_move(_1: Vec) -> () { bb7: { StorageDead(_19); - StorageDead(_42); - StorageDead(_37); _22 = std::vec::IntoIter:: { buf: copy _6, phantom: const ZeroSized: PhantomData, cap: move _20, alloc: const ManuallyDrop:: {{ value: std::alloc::Global }}, ptr: copy _6, end: copy _11 }; StorageDead(_2); StorageDead(_17); StorageDead(_4); StorageDead(_5); StorageDead(_20); - StorageDead(_35); StorageDead(_11); - StorageDead(_33); StorageDead(_7); StorageDead(_6); - StorageDead(_29); StorageLive(_23); _23 = move _22; goto -> bb8; diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 9d4bacef954e..86c729b3e95e 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -70,9 +70,7 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 // DBG: _15 = &((*_3).2: usize); // DBG: _16 = &((*_3).3: usize); StorageLive(_6); - StorageLive(_17); // DBG: _17 = &_13; - StorageLive(_18); // DBG: _18 = &_15; _4 = copy ((*_3).0: usize); _5 = copy ((*_3).2: usize); @@ -81,18 +79,12 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb1: { - StorageDead(_18); - StorageDead(_17); goto -> bb4; } bb2: { - StorageDead(_18); - StorageDead(_17); StorageLive(_9); - StorageLive(_19); // DBG: _19 = &_16; - StorageLive(_20); // DBG: _20 = &_14; StorageLive(_7); _7 = copy ((*_3).3: usize); @@ -105,34 +97,24 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb3: { - StorageDead(_20); - StorageDead(_19); goto -> bb4; } bb4: { StorageLive(_10); - StorageLive(_21); // DBG: _21 = &_15; - StorageLive(_22); // DBG: _22 = &_13; _10 = Le(copy _5, copy _4); switchInt(move _10) -> [0: bb5, otherwise: bb6]; } bb5: { - StorageDead(_22); - StorageDead(_21); _0 = const false; goto -> bb7; } bb6: { - StorageDead(_22); - StorageDead(_21); - StorageLive(_23); // DBG: _23 = &_14; - StorageLive(_24); // DBG: _24 = &_16; StorageLive(_11); _11 = copy ((*_3).1: usize); @@ -141,8 +123,6 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _0 = Le(move _11, move _12); StorageDead(_12); StorageDead(_11); - StorageDead(_24); - StorageDead(_23); goto -> bb7; } @@ -152,8 +132,6 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 } bb8: { - StorageDead(_20); - StorageDead(_19); _0 = const true; goto -> bb9; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 1b2e7b7163cd..104987b0fdda 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -51,9 +51,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _16: bool; let mut _20: usize; let _22: &T; - let mut _34: &std::ptr::NonNull; - let mut _35: &std::ptr::NonNull; - let mut _36: &std::ptr::NonNull; scope 29 { let _12: *const T; scope 30 { @@ -189,11 +186,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb5: { StorageLive(_16); - StorageLive(_34); - // DBG: _34 = &_11; - StorageLive(_35); _13 = copy _12 as std::ptr::NonNull (Transmute); - // DBG: _35 = &_13; StorageLive(_14); _14 = copy _11 as *mut T (Transmute); StorageLive(_15); @@ -205,8 +198,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb6: { - StorageDead(_35); - StorageDead(_34); StorageDead(_16); StorageLive(_18); StorageLive(_17); @@ -219,8 +210,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb7: { - StorageDead(_35); - StorageDead(_34); StorageDead(_16); StorageDead(_22); StorageDead(_13); @@ -266,13 +255,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb13: { - StorageLive(_36); - // DBG: _36 = &_11; StorageLive(_21); _21 = copy _11 as *const T (Transmute); _22 = &(*_21); StorageDead(_21); - StorageDead(_36); _23 = Option::<&T>::Some(copy _22); StorageDead(_22); StorageDead(_13); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index c18dd01a189a..4d0e3548e7d6 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -23,9 +23,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _15: bool; let mut _19: usize; let _21: &T; - let mut _27: &std::ptr::NonNull; - let mut _28: &std::ptr::NonNull; - let mut _29: &std::ptr::NonNull; scope 17 { let _11: *const T; scope 18 { @@ -151,11 +148,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { StorageLive(_15); - StorageLive(_27); - // DBG: _27 = &_10; - StorageLive(_28); _12 = copy _11 as std::ptr::NonNull (Transmute); - // DBG: _28 = &_12; StorageLive(_13); _13 = copy _10 as *mut T (Transmute); StorageLive(_14); @@ -167,8 +160,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb6: { - StorageDead(_28); - StorageDead(_27); StorageDead(_15); StorageLive(_17); StorageLive(_16); @@ -181,8 +172,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb7: { - StorageDead(_28); - StorageDead(_27); StorageDead(_15); StorageDead(_21); StorageDead(_12); @@ -224,13 +213,10 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb13: { - StorageLive(_29); - // DBG: _29 = &_10; StorageLive(_20); _20 = copy _10 as *const T (Transmute); _21 = &(*_20); StorageDead(_20); - StorageDead(_29); _22 = Option::<&T>::Some(copy _21); StorageDead(_21); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 6334c611430a..2b5d8c27d710 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -23,9 +23,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _15: bool; let mut _19: usize; let _21: &T; - let mut _27: &std::ptr::NonNull; - let mut _28: &std::ptr::NonNull; - let mut _29: &std::ptr::NonNull; scope 17 { let _11: *const T; scope 18 { @@ -151,11 +148,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb5: { StorageLive(_15); - StorageLive(_27); - // DBG: _27 = &_10; - StorageLive(_28); _12 = copy _11 as std::ptr::NonNull (Transmute); - // DBG: _28 = &_12; StorageLive(_13); _13 = copy _10 as *mut T (Transmute); StorageLive(_14); @@ -167,8 +160,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb6: { - StorageDead(_28); - StorageDead(_27); StorageDead(_15); StorageLive(_17); StorageLive(_16); @@ -181,8 +172,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb7: { - StorageDead(_28); - StorageDead(_27); StorageDead(_15); StorageDead(_21); StorageDead(_12); @@ -224,13 +213,10 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb13: { - StorageLive(_29); - // DBG: _29 = &_10; StorageLive(_20); _20 = copy _10 as *const T (Transmute); _21 = &(*_20); StorageDead(_20); - StorageDead(_29); _22 = Option::<&T>::Some(copy _21); StorageDead(_21); StorageDead(_12); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 24c6618d31ca..3009be3f9dc6 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -23,8 +23,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _18: bool; let mut _19: *const T; let _32: &T; - let mut _38: &std::ptr::NonNull; - let mut _39: &std::ptr::NonNull; scope 20 { let _14: std::ptr::NonNull; let _20: usize; @@ -48,7 +46,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { let _26: std::ptr::NonNull; - let mut _40: &std::ptr::NonNull; scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { let mut _21: *mut *const T; let mut _22: *mut std::ptr::NonNull; @@ -190,10 +187,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); _14 = copy _13 as std::ptr::NonNull (Transmute); StorageDead(_13); - StorageLive(_38); - // DBG: _38 = &((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); - StorageLive(_39); - // DBG: _39 = &_14; StorageLive(_16); StorageLive(_15); _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); @@ -204,8 +197,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _18 = Eq(copy _16, copy _17); StorageDead(_17); StorageDead(_16); - StorageDead(_39); - StorageDead(_38); goto -> bb7; } @@ -222,7 +213,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb8: { StorageLive(_26); - StorageLive(_40); StorageLive(_28); StorageLive(_22); StorageLive(_23); @@ -275,12 +265,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_23); StorageDead(_22); StorageDead(_28); - // DBG: _40 = &_26; StorageLive(_31); _31 = copy _26 as *const T (Transmute); _32 = &(*_31); StorageDead(_31); - StorageDead(_40); StorageDead(_26); _33 = Option::<&T>::Some(copy _32); StorageDead(_18); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index e5c7bcca44b6..e40bff5ea350 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -23,8 +23,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _18: bool; let mut _19: *const T; let _32: &T; - let mut _38: &std::ptr::NonNull; - let mut _39: &std::ptr::NonNull; scope 20 { let _14: std::ptr::NonNull; let _20: usize; @@ -48,7 +46,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) { let _26: std::ptr::NonNull; - let mut _40: &std::ptr::NonNull; scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) { let mut _21: *mut *const T; let mut _22: *mut std::ptr::NonNull; @@ -190,10 +187,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T); _14 = copy _13 as std::ptr::NonNull (Transmute); StorageDead(_13); - StorageLive(_38); - // DBG: _38 = &((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); - StorageLive(_39); - // DBG: _39 = &_14; StorageLive(_16); StorageLive(_15); _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull); @@ -204,8 +197,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _18 = Eq(copy _16, copy _17); StorageDead(_17); StorageDead(_16); - StorageDead(_39); - StorageDead(_38); goto -> bb7; } @@ -222,7 +213,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb8: { StorageLive(_26); - StorageLive(_40); StorageLive(_28); StorageLive(_22); StorageLive(_23); @@ -275,12 +265,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageDead(_23); StorageDead(_22); StorageDead(_28); - // DBG: _40 = &_26; StorageLive(_31); _31 = copy _26 as *const T (Transmute); _32 = &(*_31); StorageDead(_31); - StorageDead(_40); StorageDead(_26); _33 = Option::<&T>::Some(copy _32); StorageDead(_18); diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir index 18a3d8e7c4ad..9b510380b10b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir @@ -6,8 +6,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const T; let mut _7: *const T; - let mut _9: &std::ptr::NonNull; - let mut _10: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _8: usize; @@ -43,10 +41,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _2 = copy ((*_1).1: *const T); _3 = copy _2 as std::ptr::NonNull (Transmute); StorageDead(_2); - StorageLive(_9); - // DBG: _9 = &((*_1).0: std::ptr::NonNull); - StorageLive(_10); - // DBG: _10 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -57,8 +51,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); - StorageDead(_10); - StorageDead(_9); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir index 18a3d8e7c4ad..9b510380b10b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir @@ -6,8 +6,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { scope 1 (inlined as ExactSizeIterator>::is_empty) { let mut _2: *const T; let mut _7: *const T; - let mut _9: &std::ptr::NonNull; - let mut _10: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _8: usize; @@ -43,10 +41,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _2 = copy ((*_1).1: *const T); _3 = copy _2 as std::ptr::NonNull (Transmute); StorageDead(_2); - StorageLive(_9); - // DBG: _9 = &((*_1).0: std::ptr::NonNull); - StorageLive(_10); - // DBG: _10 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -57,8 +51,6 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); - StorageDead(_10); - StorageDead(_9); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir index 590d4ac2c838..62b738c36bf4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir @@ -8,8 +8,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut let mut _7: bool; let mut _8: *mut T; let mut _21: &mut T; - let mut _22: &std::ptr::NonNull; - let mut _23: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _9: usize; @@ -33,7 +31,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut } scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { let mut _15: std::ptr::NonNull; - let mut _24: &mut std::ptr::NonNull; scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { let mut _10: *mut *mut T; let mut _11: *mut std::ptr::NonNull; @@ -88,10 +85,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut bb1: { _2 = copy ((*_1).1: *mut T); _3 = copy _2 as std::ptr::NonNull (Transmute); - StorageLive(_22); - // DBG: _22 = &((*_1).0: std::ptr::NonNull); - StorageLive(_23); - // DBG: _23 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -102,8 +95,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut _7 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); - StorageDead(_23); - StorageDead(_22); goto -> bb3; } @@ -120,7 +111,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut bb4: { StorageLive(_15); - StorageLive(_24); StorageLive(_17); StorageLive(_11); StorageLive(_12); @@ -173,12 +163,10 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut StorageDead(_12); StorageDead(_11); StorageDead(_17); - // DBG: _24 = &_15; StorageLive(_20); _20 = copy _15 as *mut T (Transmute); _21 = &mut (*_20); StorageDead(_20); - StorageDead(_24); StorageDead(_15); _0 = Option::<&mut T>::Some(copy _21); goto -> bb11; diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir index 590d4ac2c838..62b738c36bf4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir @@ -8,8 +8,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut let mut _7: bool; let mut _8: *mut T; let mut _21: &mut T; - let mut _22: &std::ptr::NonNull; - let mut _23: &std::ptr::NonNull; scope 2 { let _3: std::ptr::NonNull; let _9: usize; @@ -33,7 +31,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut } scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) { let mut _15: std::ptr::NonNull; - let mut _24: &mut std::ptr::NonNull; scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) { let mut _10: *mut *mut T; let mut _11: *mut std::ptr::NonNull; @@ -88,10 +85,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut bb1: { _2 = copy ((*_1).1: *mut T); _3 = copy _2 as std::ptr::NonNull (Transmute); - StorageLive(_22); - // DBG: _22 = &((*_1).0: std::ptr::NonNull); - StorageLive(_23); - // DBG: _23 = &_3; StorageLive(_5); StorageLive(_4); _4 = copy ((*_1).0: std::ptr::NonNull); @@ -102,8 +95,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut _7 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); - StorageDead(_23); - StorageDead(_22); goto -> bb3; } @@ -120,7 +111,6 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut bb4: { StorageLive(_15); - StorageLive(_24); StorageLive(_17); StorageLive(_11); StorageLive(_12); @@ -173,12 +163,10 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut StorageDead(_12); StorageDead(_11); StorageDead(_17); - // DBG: _24 = &_15; StorageLive(_20); _20 = copy _15 as *mut T (Transmute); _21 = &mut (*_20); StorageDead(_20); - StorageDead(_24); StorageDead(_15); _0 = Option::<&mut T>::Some(copy _21); goto -> bb11; diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir index e9ed932cbafb..cc0fce26149e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir @@ -10,9 +10,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { let mut _10: std::ptr::NonNull; let mut _12: usize; let _14: &T; - let mut _15: &std::ptr::NonNull; - let mut _16: &std::ptr::NonNull; - let mut _17: &std::ptr::NonNull; scope 2 { let _3: *const T; scope 3 { @@ -70,11 +67,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { bb1: { StorageLive(_7); - StorageLive(_15); - // DBG: _15 = &_2; - StorageLive(_16); _4 = copy _3 as std::ptr::NonNull (Transmute); - // DBG: _16 = &_4; StorageLive(_5); _5 = copy _2 as *mut T (Transmute); StorageLive(_6); @@ -86,8 +79,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb2: { - StorageDead(_16); - StorageDead(_15); StorageDead(_7); StorageLive(_10); StorageLive(_9); @@ -103,8 +94,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb3: { - StorageDead(_16); - StorageDead(_15); _0 = const {transmute(0x0000000000000000): Option<&T>}; StorageDead(_7); goto -> bb8; @@ -127,13 +116,10 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb7: { - StorageLive(_17); - // DBG: _17 = &_2; StorageLive(_13); _13 = copy _2 as *const T (Transmute); _14 = &(*_13); StorageDead(_13); - StorageDead(_17); _0 = Option::<&T>::Some(copy _14); goto -> bb8; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir index e9ed932cbafb..cc0fce26149e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir @@ -10,9 +10,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { let mut _10: std::ptr::NonNull; let mut _12: usize; let _14: &T; - let mut _15: &std::ptr::NonNull; - let mut _16: &std::ptr::NonNull; - let mut _17: &std::ptr::NonNull; scope 2 { let _3: *const T; scope 3 { @@ -70,11 +67,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { bb1: { StorageLive(_7); - StorageLive(_15); - // DBG: _15 = &_2; - StorageLive(_16); _4 = copy _3 as std::ptr::NonNull (Transmute); - // DBG: _16 = &_4; StorageLive(_5); _5 = copy _2 as *mut T (Transmute); StorageLive(_6); @@ -86,8 +79,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb2: { - StorageDead(_16); - StorageDead(_15); StorageDead(_7); StorageLive(_10); StorageLive(_9); @@ -103,8 +94,6 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb3: { - StorageDead(_16); - StorageDead(_15); _0 = const {transmute(0x0000000000000000): Option<&T>}; StorageDead(_7); goto -> bb8; @@ -127,13 +116,10 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { } bb7: { - StorageLive(_17); - // DBG: _17 = &_2; StorageLive(_13); _13 = copy _2 as *const T (Transmute); _14 = &(*_13); StorageDead(_13); - StorageDead(_17); _0 = Option::<&T>::Some(copy _14); goto -> bb8; } diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs index 7a5f36da2091..470ae07a0b55 100644 --- a/tests/ui/extern/extern-types-field-offset.rs +++ b/tests/ui/extern/extern-types-field-offset.rs @@ -23,12 +23,17 @@ fn main() { let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) }; // Projecting to the newtype works, because it is always at offset 0. let field = &x.0; + // Avoid being eliminated by DSE. + std::hint::black_box(field); let x: &S = unsafe { &*(&buf as *const _ as *const S) }; // Accessing sized fields is perfectly fine, even at non-zero offsets. let field = &x.i; + std::hint::black_box(field); let field = &x.j; + std::hint::black_box(field); // This needs to compute the field offset, but we don't know the type's alignment, // so this panics. let field = &x.a; + std::hint::black_box(field); } From 1bd89bd42e0bb6f29b8af5d6bdf3f756196bb8ee Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 18 Jun 2025 22:04:48 +0800 Subject: [PATCH 473/537] codegen: Generate `dbg_value` for the ref statement --- compiler/rustc_codegen_gcc/src/debuginfo.rs | 13 +- .../src/debuginfo/dwarf_const.rs | 3 + .../rustc_codegen_llvm/src/debuginfo/mod.rs | 53 +++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 9 + compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + .../rustc_codegen_ssa/src/mir/debuginfo.rs | 54 +++++- compiler/rustc_codegen_ssa/src/mir/operand.rs | 17 +- .../rustc_codegen_ssa/src/mir/statement.rs | 70 +++++++- .../rustc_codegen_ssa/src/traits/debuginfo.rs | 14 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 1 + tests/codegen-llvm/debuginfo-dse.rs | 160 ++++++++++++++++++ tests/debuginfo/opt/dead_refs.rs | 50 ++++++ 12 files changed, 431 insertions(+), 14 deletions(-) create mode 100644 tests/codegen-llvm/debuginfo-dse.rs create mode 100644 tests/debuginfo/opt/dead_refs.rs diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 4c8585192a1b..0f015cc23f52 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -29,13 +29,24 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size], - _fragment: Option>, + _fragment: &Option>, ) { // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here. #[cfg(feature = "master")] _variable_alloca.set_location(_dbg_loc); } + fn dbg_var_value( + &mut self, + _dbg_var: Self::DIVariable, + _dbg_loc: Self::DILocation, + _value: Self::Value, + _direct_offset: Size, + _indirect_offsets: &[Size], + _fragment: &Option>, + ) { + } + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { // TODO(antoyo): insert reference to gdb debug scripts section global. } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs index 408429152223..52d04625749b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs @@ -35,3 +35,6 @@ declare_constant!(DW_OP_plus_uconst: u64); /// Double-checked by a static assertion in `RustWrapper.cpp`. #[allow(non_upper_case_globals)] pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000; +// It describes the actual value of a source variable which might not exist in registers or in memory. +#[allow(non_upper_case_globals)] +pub(crate) const DW_OP_stack_value: u64 = 0x9f; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index af64e4ebed0f..c6ad1c2e18ec 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -156,7 +156,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { variable_alloca: Self::Value, direct_offset: Size, indirect_offsets: &[Size], - fragment: Option>, + fragment: &Option>, ) { use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst}; @@ -187,7 +187,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) }; unsafe { - // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`. llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( di_builder, variable_alloca, @@ -199,6 +198,56 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { }; } + fn dbg_var_value( + &mut self, + dbg_var: &'ll DIVariable, + dbg_loc: &'ll DILocation, + value: Self::Value, + direct_offset: Size, + indirect_offsets: &[Size], + fragment: &Option>, + ) { + use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value}; + + // Convert the direct and indirect offsets and fragment byte range to address ops. + let mut addr_ops = SmallVec::<[u64; 8]>::new(); + + if direct_offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(direct_offset.bytes() as u64); + addr_ops.push(DW_OP_stack_value); + } + for &offset in indirect_offsets { + addr_ops.push(DW_OP_deref); + if offset.bytes() > 0 { + addr_ops.push(DW_OP_plus_uconst); + addr_ops.push(offset.bytes() as u64); + } + } + if let Some(fragment) = fragment { + // `DW_OP_LLVM_fragment` takes as arguments the fragment's + // offset and size, both of them in bits. + addr_ops.push(DW_OP_LLVM_fragment); + addr_ops.push(fragment.start.bits() as u64); + addr_ops.push((fragment.end - fragment.start).bits() as u64); + } + + let di_builder = DIB(self.cx()); + let addr_expr = unsafe { + llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) + }; + unsafe { + llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd( + di_builder, + value, + dbg_var, + addr_expr, + dbg_loc, + self.llbb(), + ); + } + } + fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { unsafe { llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e9f92267a7d4..7fbba0294073 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1991,6 +1991,15 @@ unsafe extern "C" { Block: &'ll BasicBlock, ) -> &'ll DbgRecord; + pub(crate) fn LLVMDIBuilderInsertDbgValueRecordAtEnd<'ll>( + Builder: &DIBuilder<'ll>, + Val: &'ll Value, + VarInfo: &'ll Metadata, + Expr: &'ll Metadata, + DebugLoc: &'ll Metadata, + Block: &'ll BasicBlock, + ) -> &'ll DbgRecord; + pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>( Builder: &DIBuilder<'ll>, Scope: &'ll Metadata, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b2dc4fe32b0f..e371f1a76231 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1320,6 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for statement in &data.statements { self.codegen_statement(bx, statement); } + self.codegen_stmt_debuginfos(bx, &data.after_last_stmt_debuginfos); let merging_succ = self.codegen_terminator(bx, bb, data.terminator()); if let MergingSucc::False = merging_succ { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index b8f635ab7816..38bb6f24b1c3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -253,6 +253,54 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { spill_slot } + // Indicates that local is set to a new value. The `layout` and `projection` are used to + // calculate the offset. + pub(crate) fn debug_new_val_to_local( + &self, + bx: &mut Bx, + local: mir::Local, + base: PlaceValue, + layout: TyAndLayout<'tcx>, + projection: &[mir::PlaceElem<'tcx>], + ) { + let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; + if !full_debug_info { + return; + } + + let vars = match &self.per_local_var_debug_info { + Some(per_local) => &per_local[local], + None => return, + }; + + let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, projection, layout); + for var in vars.iter() { + let Some(dbg_var) = var.dbg_var else { + continue; + }; + let Some(dbg_loc) = self.dbg_loc(var.source_info) else { + continue; + }; + bx.dbg_var_value( + dbg_var, + dbg_loc, + base.llval, + direct_offset, + &indirect_offsets, + &var.fragment, + ); + } + } + + pub(crate) fn debug_poison_to_local(&self, bx: &mut Bx, local: mir::Local) { + let ty = self.monomorphize(self.mir.local_decls[local].ty); + let layout = bx.cx().layout_of(ty); + let to_backend_ty = bx.cx().immediate_backend_type(layout); + let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); + self.debug_new_val_to_local(bx, local, place_ref.val, layout, &[]); + } + /// Apply debuginfo and/or name, after creating the `alloca` for a local, /// or initializing the local with an operand (whichever applies). pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { @@ -424,7 +472,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { alloca.val.llval, Size::ZERO, &[Size::ZERO], - var.fragment, + &var.fragment, ); } else { bx.dbg_var_addr( @@ -433,7 +481,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { base.val.llval, direct_offset, &indirect_offsets, - var.fragment, + &var.fragment, ); } } @@ -455,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx); bx.clear_dbg_loc(); - bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment); + bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], &fragment); } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5f7f87fc6920..88a8e2a844cb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -71,16 +71,23 @@ pub enum OperandValue { } impl OperandValue { + /// Return the data pointer and optional metadata as backend values + /// if this value can be treat as a pointer. + pub(crate) fn try_pointer_parts(self) -> Option<(V, Option)> { + match self { + OperandValue::Immediate(llptr) => Some((llptr, None)), + OperandValue::Pair(llptr, llextra) => Some((llptr, Some(llextra))), + OperandValue::Ref(_) | OperandValue::ZeroSized => None, + } + } + /// Treat this value as a pointer and return the data pointer and /// optional metadata as backend values. /// /// If you're making a place, use [`Self::deref`] instead. pub(crate) fn pointer_parts(self) -> (V, Option) { - match self { - OperandValue::Immediate(llptr) => (llptr, None), - OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), - _ => bug!("OperandValue cannot be a pointer: {self:?}"), - } + self.try_pointer_parts() + .unwrap_or_else(|| bug!("OperandValue cannot be a pointer: {self:?}")) } /// Treat this value as a pointer and return the place to which it points. diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 0a50d7f18dbe..99bb31a68b68 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,13 +1,17 @@ -use rustc_middle::mir::{self, NonDivergingIntrinsic}; -use rustc_middle::span_bug; +use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo}; +use rustc_middle::{bug, span_bug}; +use rustc_target::callconv::PassMode; use tracing::instrument; use super::{FunctionCx, LocalRef}; +use crate::common::TypeKind; +use crate::mir::place::PlaceRef; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "debug", skip(self, bx))] pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { + self.codegen_stmt_debuginfos(bx, &statement.debuginfos); self.set_debug_loc(bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box (ref place, ref rvalue)) => { @@ -101,4 +105,66 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | mir::StatementKind::Nop => {} } } + + pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) { + match debuginfo { + StmtDebugInfo::AssignRef(dest, place) => { + let local_ref = match self.locals[place.local] { + LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { + Some(place_ref) + } + LocalRef::Operand(operand_ref) => operand_ref + .val + .try_pointer_parts() + .map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)), + LocalRef::PendingOperand => None, + } + .filter(|place_ref| { + // For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is + // llval. + let local_ref_pass_mode = place.as_local().and_then(|local| { + if local == RETURN_PLACE { + None + } else { + self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode) + } + }); + matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) && + // Drop unsupported projections. + place.projection.iter().all(|p| p.can_use_in_debuginfo()) && + // Only pointers can be calculated addresses. + bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer + }); + if let Some(local_ref) = local_ref { + let (base_layout, projection) = if place.is_indirect_first_projection() { + // For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so + // we should drop the deref projection. + let projected_ty = local_ref + .layout + .ty + .builtin_deref(true) + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref)); + let layout = bx.cx().layout_of(projected_ty); + (layout, &place.projection[1..]) + } else { + (local_ref.layout, place.projection.as_slice()) + }; + self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection); + } else { + // If the address cannot be computed, use poison to indicate that the value has been optimized out. + self.debug_poison_to_local(bx, *dest); + } + } + } + } + + pub(crate) fn codegen_stmt_debuginfos( + &mut self, + bx: &mut Bx, + debuginfos: &[StmtDebugInfo<'tcx>], + ) { + for debuginfo in debuginfos { + self.codegen_stmt_debuginfo(bx, debuginfo); + } + } } diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index b9d4950e0ad3..a4da6c915dee 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -77,7 +77,19 @@ pub trait DebugInfoBuilderMethods: BackendTypes { indirect_offsets: &[Size], // Byte range in the `dbg_var` covered by this fragment, // if this is a fragment of a composite `DIVariable`. - fragment: Option>, + fragment: &Option>, + ); + fn dbg_var_value( + &mut self, + dbg_var: Self::DIVariable, + dbg_loc: Self::DILocation, + value: Self::Value, + direct_offset: Size, + // NB: each offset implies a deref (i.e. they're steps in a pointer chain). + indirect_offsets: &[Size], + // Byte range in the `dbg_var` covered by this fragment, + // if this is a fragment of a composite `DIVariable`. + fragment: &Option>, ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); fn clear_dbg_loc(&mut self); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 2b83ea24ac61..e38474f09ff7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -58,6 +58,7 @@ using namespace llvm::object; // This opcode is an LLVM detail that could hypothetically change (?), so // verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM. static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000); +static_assert(dwarf::DW_OP_stack_value == 0x9f); // LLVMAtomicOrdering is already an enum - don't create another // one. diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs new file mode 100644 index 000000000000..1fcb5fcfc543 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-dse.rs @@ -0,0 +1,160 @@ +//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir +//@ revisions: CODEGEN OPTIMIZED +//@[CODEGEN] compile-flags: -Cno-prepopulate-passes +// ignore-tidy-linelength + +#![crate_type = "lib"] + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Foo(i32, i64, i32); + +#[no_mangle] +fn r#ref(ref_foo: &Foo) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @ref + // CHECK-SAME: (ptr {{.*}} [[ARG_ref_foo:%.*]]) + // OPTIMIZED: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_foo:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr poison, [[VAR_invalid_ref_of_ref_foo:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v0:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let invalid_ref_of_ref_foo = &ref_foo; + let ref_v0 = &ref_foo.0; + let ref_v1 = &ref_foo.1; + let ref_v2 = &ref_foo.2; + ref_foo.0 +} + +#[no_mangle] +pub fn dead_first(dead_first_foo: &Foo) -> &i32 { + // CHECK-LABEL: def {{.*}} ptr @dead_first + // CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]]) + // CODEGEN: #dbg_declare(ptr %dead_first_foo.dbg.spill, [[ARG_dead_first_foo:![0-9]+]], !DIExpression() + // OPTIMIZED: #dbg_value(ptr %dead_first_foo, [[ARG_dead_first_foo:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr %dead_first_foo, [[VAR_dead_first_v0:![0-9]+]], !DIExpression() + // CHECK: %dead_first_v0 = getelementptr{{.*}} i8, ptr %dead_first_foo, i64 16 + // CODEGEN: #dbg_declare(ptr %dead_first_v0.dbg.spill, [[VAR_dead_first_v0]], !DIExpression() + // OPTIMIZED: #dbg_value(ptr %dead_first_v0, [[VAR_dead_first_v0]], !DIExpression() + let mut dead_first_v0 = &dead_first_foo.0; + dead_first_v0 = &dead_first_foo.2; + dead_first_v0 +} + +#[no_mangle] +fn ptr(ptr_foo: Foo) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @ptr + // CHECK-SAME: (ptr {{.*}} [[ARG_ptr_foo:%.*]]) + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[ref_ptr_foo:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v0:![0-9]+]], !DIExpression() + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_ptr_foo = &ptr_foo; + let ptr_v0 = &ptr_foo.0; + let ptr_v1 = &ptr_foo.1; + let ptr_v2 = &ptr_foo.2; + ptr_foo.2 +} + +#[no_mangle] +fn no_ptr(val: i32) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @no_ptr + // CODEGEN: #dbg_value(ptr poison, [[VAR_val_ref:![0-9]+]], !DIExpression() + let val_ref = &val; + val +} + +#[no_mangle] +pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { + // CHECK-LABEL: define void @fragment + // CHECK-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]]) + // CHECK: #dbg_declare(ptr [[ARG_fragment_v1]] + // CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]] + // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v2]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64) + // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v1]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 64, 64) + let fragment_f = || { + fragment_v2 = fragment_v1; + }; + fragment_v2 = fragment_v1; + fragment_v2 +} + +#[no_mangle] +pub fn tuple(foo: (i32, &Foo)) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @tuple + // CHECK-SAME: (i32 {{.*}}, ptr {{.*}} [[ARG_tuple_foo_1:%.*]]) + // CHECK: #dbg_value(ptr [[ARG_tuple_foo_1]], [[VAR_tuple_dead:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let tuple_dead = &foo.1.2; + foo.1.0 +} + +pub struct ZST; + +#[no_mangle] +pub fn zst(zst: ZST, v: &i32) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @zst + // CHECK: #dbg_value(ptr poison, [[VAR_zst_ref:![0-9]+]], !DIExpression() + let zst_ref = &zst; + *v +} + +#[no_mangle] +fn index(slice: &[i32; 4], idx: usize) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @index + // CHECK: bb1: + // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression() + // CODEGEN: bb3: + // CHECK-NEXT: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression() + // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression() + let index_from_var = &slice[idx]; + let [ref const_index_from_start, .., ref const_index_from_end] = slice[..] else { + return 0; + }; + slice[0] +} + +unsafe extern "Rust" { + safe fn opaque_inner(_: *const core::ffi::c_void); +} + +#[inline(never)] +pub fn opaque_use(p: &T) { + opaque_inner(&raw const p as *const _); +} + +#[no_mangle] +pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 { + // CHECK-LABEL: define{{.*}} i32 @non_arg_ref + // CHECK: #dbg_value(ptr %non_arg_ref_scalar, [[VAR_non_arg_ref_scalar_ref:![0-9]+]], !DIExpression() + // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref:![0-9]+]], !DIExpression() + // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref_2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let non_arg_ref_scalar = scalar; + let non_arg_ref_foo = foo; + opaque_use(&non_arg_ref_scalar); + opaque_use(&non_arg_ref_foo); + let non_arg_ref_scalar_ref = &non_arg_ref_scalar; + let non_arg_ref_foo_ref = &non_arg_ref_foo; + let non_arg_ref_foo_ref_2 = &non_arg_ref_foo.2; + *a +} + +// CHECK-DAG: [[VAR_invalid_ref_of_ref_foo]] = !DILocalVariable(name: "invalid_ref_of_ref_foo" +// OPTIMIZED-DAG: [[VAR_ref_foo]] = !DILocalVariable(name: "ref_foo" +// CHECK-DAG: [[VAR_ref_v0]] = !DILocalVariable(name: "ref_v0" +// CHECK-DAG: [[VAR_ref_v1]] = !DILocalVariable(name: "ref_v1" +// CHECK-DAG: [[VAR_ref_v2]] = !DILocalVariable(name: "ref_v2" +// CHECK-DAG: [[ref_ptr_foo]] = !DILocalVariable(name: "ref_ptr_foo" +// CHECK-DAG: [[VAR_ptr_v0]] = !DILocalVariable(name: "ptr_v0" +// CHECK-DAG: [[VAR_ptr_v1]] = !DILocalVariable(name: "ptr_v1" +// CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2" +// CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" +// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" +// CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" +// CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo" +// CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0" +// CHECK-DAG: [[VAR_index_from_var]] = !DILocalVariable(name: "index_from_var" +// CHECK-DAG: [[VAR_const_index_from_start]] = !DILocalVariable(name: "const_index_from_start" +// CHECK-DAG: [[VAR_const_index_from_end]] = !DILocalVariable(name: "const_index_from_end" +// CHECK-DAG: [[VAR_zst_ref]] = !DILocalVariable(name: "zst_ref" +// CHECK-DAG: [[VAR_non_arg_ref_scalar_ref]] = !DILocalVariable(name: "non_arg_ref_scalar_ref" +// CHECK-DAG: [[VAR_non_arg_ref_foo_ref]] = !DILocalVariable(name: "non_arg_ref_foo_ref" +// CHECK-DAG: [[VAR_non_arg_ref_foo_ref_2]] = !DILocalVariable(name: "non_arg_ref_foo_ref_2" diff --git a/tests/debuginfo/opt/dead_refs.rs b/tests/debuginfo/opt/dead_refs.rs new file mode 100644 index 000000000000..61e741573346 --- /dev/null +++ b/tests/debuginfo/opt/dead_refs.rs @@ -0,0 +1,50 @@ +//@ min-lldb-version: 1800 +//@ min-gdb-version: 13.0 +//@ compile-flags: -g -Copt-level=3 +//@ disable-gdb-pretty-printers + +// Checks that we still can access dead variables from debuginfos. + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:print *ref_v0 +// gdb-check:$1 = 0 + +// gdb-command:print *ref_v1 +// gdb-check:$2 = 1 + +// gdb-command:print *ref_v2 +// gdb-check:$3 = 2 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:v *ref_v0 +// lldb-check:[...] 0 + +// lldb-command:v *ref_v1 +// lldb-check:[...] 1 + +// lldb-command:v *ref_v2 +// lldb-check:[...] 2 + +#![allow(unused_variables)] + +use std::hint::black_box; + +pub struct Foo(i32, i64, i32); + +#[inline(never)] +#[no_mangle] +fn test_ref(ref_foo: &Foo) -> i32 { + let ref_v0 = &ref_foo.0; + let ref_v1 = &ref_foo.1; + let ref_v2 = &ref_foo.2; + ref_foo.0 // #break +} + +fn main() { + let foo = black_box(Foo(0, 1, 2)); + black_box(test_ref(&foo)); +} From 8da04285cf6fe61587e16155a8b224dba64bf0be Mon Sep 17 00:00:00 2001 From: dianqk Date: Sat, 19 Jul 2025 18:49:47 +0800 Subject: [PATCH 474/537] mir-opt: Eliminate dead statements even if they are used by debuginfos --- .../rustc_codegen_ssa/src/mir/statement.rs | 3 + compiler/rustc_middle/src/mir/pretty.rs | 3 + compiler/rustc_middle/src/mir/statement.rs | 15 +++++ compiler/rustc_middle/src/mir/visit.rs | 7 +++ compiler/rustc_mir_dataflow/src/debuginfo.rs | 10 ++-- .../rustc_mir_dataflow/src/impls/liveness.rs | 3 - compiler/rustc_mir_transform/src/simplify.rs | 16 +++++ .../src/strip_debuginfo.rs | 17 ++++++ tests/codegen-llvm/debuginfo-dse.rs | 23 +++++++- tests/mir-opt/dead-store-elimination/ref.rs | 4 +- ...ef.tuple.DeadStoreElimination-initial.diff | 2 +- .../inline_shims.drop.Inline.panic-abort.diff | 50 +++++++--------- ...y.run2-{closure#0}.Inline.panic-abort.diff | 4 -- ....run2-{closure#0}.Inline.panic-unwind.diff | 4 -- ...d_place.invalid_place.PreCodegen.after.mir | 13 +++++ .../pre-codegen/dead_on_invalid_place.rs | 27 +++++++++ .../loops.vec_move.PreCodegen.after.mir | 12 +--- ...variant_a-{closure#0}.PreCodegen.after.mir | 58 ++++++++----------- ..._to_slice.PreCodegen.after.panic-abort.mir | 8 --- ...to_slice.PreCodegen.after.panic-unwind.mir | 8 --- 20 files changed, 178 insertions(+), 109 deletions(-) create mode 100644 tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir create mode 100644 tests/mir-opt/pre-codegen/dead_on_invalid_place.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 99bb31a68b68..80f4f0fcda1c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -155,6 +155,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.debug_poison_to_local(bx, *dest); } } + StmtDebugInfo::InvalidAssign(local) => { + self.debug_poison_to_local(bx, *local); + } } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8cf89f778a2a..d87e3abe3b2e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -844,6 +844,9 @@ impl Debug for StmtDebugInfo<'_> { StmtDebugInfo::AssignRef(local, place) => { write!(fmt, "{local:?} = &{place:?}") } + StmtDebugInfo::InvalidAssign(local) => { + write!(fmt, "{local:?} = &?") + } } } } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 67b4448cfcdd..f310e1e57625 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -527,6 +527,20 @@ impl<'tcx> PlaceRef<'tcx> { }) } + /// Return the place accessed locals that include the base local. + pub fn accessed_locals(self) -> impl Iterator { + std::iter::once(self.local).chain(self.projection.iter().filter_map(|proj| match proj { + ProjectionElem::Index(local) => Some(*local), + ProjectionElem::Deref + | ProjectionElem::Field(_, _) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(_, _) + | ProjectionElem::OpaqueCast(_) + | ProjectionElem::UnwrapUnsafeBinder(_) => None, + })) + } + /// Generates a new place by appending `more_projections` to the existing ones /// and interning the result. pub fn project_deeper( @@ -1057,4 +1071,5 @@ impl<'tcx> ops::DerefMut for StmtDebugInfos<'tcx> { #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum StmtDebugInfo<'tcx> { AssignRef(Local, Place<'tcx>), + InvalidAssign(Local), } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 47ae23afd556..9654e189f2ed 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -406,6 +406,13 @@ macro_rules! make_mir_visitor { location ); }, + StmtDebugInfo::InvalidAssign(local) => { + self.visit_local( + $(& $mutability)? *local, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location + ); + } } } diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs index 274c5943946c..0d25ce91c9a9 100644 --- a/compiler/rustc_mir_dataflow/src/debuginfo.rs +++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs @@ -5,16 +5,16 @@ use rustc_middle::mir::*; /// Return the set of locals that appear in debuginfo. pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet { let mut visitor = DebuginfoLocals(DenseBitSet::new_empty(body.local_decls.len())); - visitor.visit_body(body); + for debuginfo in body.var_debug_info.iter() { + visitor.visit_var_debug_info(debuginfo); + } visitor.0 } struct DebuginfoLocals(DenseBitSet); impl Visitor<'_> for DebuginfoLocals { - fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) { - if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { - self.0.insert(local); - } + fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) { + self.0.insert(local); } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 037e2720f365..f6aaa65ad9fd 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -287,9 +287,6 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { if let Some(destination) = Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals) && !state.contains(destination.local) - // FIXME: We can eliminate the statement, but we'll need the statements it depends on - // for debuginfos. We need a way to handle this. - && !self.debuginfo_locals.contains(destination.local) { // This store is dead return; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 0f23482ea8b1..8b5efb742058 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -657,6 +657,22 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } + fn visit_statement_debuginfo( + &mut self, + stmt_debuginfo: &mut StmtDebugInfo<'tcx>, + location: Location, + ) { + match stmt_debuginfo { + StmtDebugInfo::AssignRef(local, place) => { + if place.as_ref().accessed_locals().any(|local| self.map[local].is_none()) { + *stmt_debuginfo = StmtDebugInfo::InvalidAssign(*local); + } + } + StmtDebugInfo::InvalidAssign(_) => {} + } + self.super_statement_debuginfo(stmt_debuginfo, location); + } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs index 9ede8aa79c44..7fec25ccb521 100644 --- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs @@ -1,5 +1,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::debuginfo::debuginfo_locals; use rustc_session::config::MirStripDebugInfo; /// Conditionally remove some of the VarDebugInfo in MIR. @@ -30,6 +31,22 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo { if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE, ) }); + + let debuginfo_locals = debuginfo_locals(body); + for data in body.basic_blocks.as_mut_preserves_cfg() { + for stmt in data.statements.iter_mut() { + stmt.debuginfos.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { + debuginfo_locals.contains(*local) + } + }); + } + data.after_last_stmt_debuginfos.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { + debuginfo_locals.contains(*local) + } + }); + } } fn is_required(&self) -> bool { diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs index 1fcb5fcfc543..78e145a3cdf1 100644 --- a/tests/codegen-llvm/debuginfo-dse.rs +++ b/tests/codegen-llvm/debuginfo-dse.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir +//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled //@ revisions: CODEGEN OPTIMIZED //@[CODEGEN] compile-flags: -Cno-prepopulate-passes // ignore-tidy-linelength @@ -9,6 +9,13 @@ #[derive(Clone, Copy)] pub struct Foo(i32, i64, i32); +#[repr(C)] +pub struct Bar<'a> { + a: i32, + b: i64, + foo: &'a Foo, +} + #[no_mangle] fn r#ref(ref_foo: &Foo) -> i32 { // CHECK-LABEL: define{{.*}} i32 @ref @@ -78,11 +85,20 @@ pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { fragment_v2 } +#[no_mangle] +pub fn deref(bar: Bar) -> i32 { + // CHECK-LABEL: define {{.*}} i32 @deref + // We are unable to represent dereference within this expression. + // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression() + let deref_dead = &bar.foo.2; + bar.a +} + #[no_mangle] pub fn tuple(foo: (i32, &Foo)) -> i32 { // CHECK-LABEL: define{{.*}} i32 @tuple - // CHECK-SAME: (i32 {{.*}}, ptr {{.*}} [[ARG_tuple_foo_1:%.*]]) - // CHECK: #dbg_value(ptr [[ARG_tuple_foo_1]], [[VAR_tuple_dead:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + // Although there is no dereference here, there is a dereference in the MIR. + // CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression() let tuple_dead = &foo.1.2; foo.1.0 } @@ -148,6 +164,7 @@ pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 { // CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2" // CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" // CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" +// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" // CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" // CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo" // CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0" diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs index 18d9ea8b84d7..2d3200edab9f 100644 --- a/tests/mir-opt/dead-store-elimination/ref.rs +++ b/tests/mir-opt/dead-store-elimination/ref.rs @@ -11,9 +11,7 @@ pub fn tuple(v: (i32, &Foo)) -> i32 { // CHECK-LABEL: fn tuple // CHECK: debug _dead => [[dead:_[0-9]+]]; // CHECK: bb0: - // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo. - // CHECK: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo); - // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32) + // CHECK: DBG: [[dead]] = &((*_3).2: i32) let _dead = &v.1.c; v.1.a } diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff index af28c1b9aa87..0b96569cbe4b 100644 --- a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff @@ -13,7 +13,7 @@ bb0: { - StorageLive(_2); - _3 = deref_copy (_1.1: &Foo); +- _3 = deref_copy (_1.1: &Foo); - _2 = &((*_3).2: i32); + // DBG: _2 = &((*_3).2: i32); _4 = deref_copy (_1.1: &Foo); diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 7fa22524f008..9509739413b7 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -16,12 +16,10 @@ + let mut _9: *mut A; + let mut _10: usize; + scope 3 (inlined Vec::::as_mut_ptr) { -+ let mut _11: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { -+ let mut _12: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { -+ let mut _13: std::ptr::NonNull; ++ let mut _11: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + scope 8 (inlined NonNull::::cast::) { + scope 9 (inlined NonNull::::as_ptr) { @@ -41,15 +39,15 @@ + } + } + scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) { -+ let mut _14: usize; -+ let mut _15: *mut A; -+ let mut _16: bool; ++ let mut _12: usize; ++ let mut _13: *mut A; ++ let mut _14: bool; + } + } + } + scope 15 (inlined drop_in_place::> - shim(Some(Option))) { -+ let mut _17: isize; -+ let mut _18: isize; ++ let mut _15: isize; ++ let mut _16: isize; + } bb0: { @@ -64,20 +62,16 @@ + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); -+ StorageLive(_12); -+ StorageLive(_13); -+ _13 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); -+ _9 = copy _13 as *mut A (Transmute); -+ StorageDead(_13); -+ StorageDead(_12); ++ _11 = copy (((((*_6).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); ++ _9 = copy _11 as *mut A (Transmute); + StorageDead(_11); + _10 = copy ((*_6).1: usize); + _8 = *mut [A] from (copy _9, copy _10); + StorageDead(_9); ++ StorageLive(_12); ++ StorageLive(_13); + StorageLive(_14); -+ StorageLive(_15); -+ StorageLive(_16); -+ _14 = const 0_usize; ++ _12 = const 0_usize; + goto -> bb4; } @@ -89,33 +83,33 @@ StorageLive(_5); _5 = copy _2; - _0 = drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_17); -+ _17 = discriminant((*_5)); -+ switchInt(move _17) -> [0: bb5, otherwise: bb6]; ++ StorageLive(_15); ++ _15 = discriminant((*_5)); ++ switchInt(move _15) -> [0: bb5, otherwise: bb6]; } bb2: { -+ StorageDead(_16); -+ StorageDead(_15); + StorageDead(_14); ++ StorageDead(_13); ++ StorageDead(_12); + StorageDead(_8); + StorageDead(_10); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ _15 = &raw mut (*_8)[_14]; -+ _14 = Add(move _14, const 1_usize); -+ drop((*_15)) -> [return: bb4, unwind unreachable]; ++ _13 = &raw mut (*_8)[_12]; ++ _12 = Add(move _12, const 1_usize); ++ drop((*_13)) -> [return: bb4, unwind unreachable]; + } + + bb4: { -+ _16 = Eq(copy _14, copy _10); -+ switchInt(move _16) -> [0: bb3, otherwise: bb2]; ++ _14 = Eq(copy _12, copy _10); ++ switchInt(move _14) -> [0: bb3, otherwise: bb2]; + } + + bb5: { -+ StorageDead(_17); ++ StorageDead(_15); StorageDead(_5); return; + } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index bb81cb4e2600..0acb33febe52 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -220,16 +220,12 @@ + StorageLive(_49); + StorageLive(_41); + StorageLive(_42); -+ StorageLive(_43); -+ StorageLive(_46); + _44 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_46); + StorageLive(_47); + _47 = Option::<()>::None; + _42 = copy ((*_44).0: std::option::Option<()>); + ((*_44).0: std::option::Option<()>) = copy _47; + StorageDead(_47); -+ StorageDead(_43); + StorageLive(_48); + _48 = discriminant(_42); + switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5]; diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 520c54824e15..98ee46c29b1b 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -237,16 +237,12 @@ + StorageLive(_51); + StorageLive(_43); + StorageLive(_44); -+ StorageLive(_45); -+ StorageLive(_48); + _46 = copy (_19.0: &mut std::future::Ready<()>); -+ StorageDead(_48); + StorageLive(_49); + _49 = Option::<()>::None; + _44 = copy ((*_46).0: std::option::Option<()>); + ((*_46).0: std::option::Option<()>) = copy _49; + StorageDead(_49); -+ StorageDead(_45); + StorageLive(_50); + _50 = discriminant(_44); + switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7]; diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir new file mode 100644 index 000000000000..4a2127178fb0 --- /dev/null +++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir @@ -0,0 +1,13 @@ +// MIR for `invalid_place` after PreCodegen + +fn invalid_place(_1: bool) -> bool { + debug c1_ref => _2; + let mut _0: bool; + let mut _2: &bool; + + bb0: { + // DBG: _2 = &?; + _0 = copy _1; + return; + } +} diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs new file mode 100644 index 000000000000..5abe9fa43a5d --- /dev/null +++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs @@ -0,0 +1,27 @@ +#![feature(core_intrinsics, custom_mir)] +#![crate_type = "lib"] + +use std::intrinsics::mir::*; + +// EMIT_MIR dead_on_invalid_place.invalid_place.PreCodegen.after.mir +#[custom_mir(dialect = "runtime")] +pub fn invalid_place(c: bool) -> bool { + // CHECK-LABEL: fn invalid_place + // CHECK: debug c1_ref => [[c1_ref:_[0-9]+]]; + // CHECK: bb0: { + // We cannot read the reference, since `c1` is dead. + // CHECK-NEXT: DBG: [[c1_ref]] = &? + // CHECK-NEXT: _0 = copy _1; + // CHECK-NEXT: return; + mir! { + let _c1_ref: &bool; + let c1: bool; + debug c1_ref => _c1_ref; + { + c1 = c; + _c1_ref = &c1; + RET = c; + Return() + } + } +} diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir index f453741dc6c7..66eb1bcfaa66 100644 --- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir @@ -56,11 +56,11 @@ fn vec_move(_1: Vec) -> () { scope 40 (inlined alloc::raw_vec::RawVec::::capacity) { debug self => _37; let mut _19: usize; - let mut _42: &alloc::raw_vec::RawVecInner; + let mut _39: &alloc::raw_vec::RawVecInner; scope 41 (inlined std::mem::size_of::) { } scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) { - debug self => _42; + debug self => _39; debug elem_size => _19; let mut _21: core::num::niche_types::UsizeNoHighBit; scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) { @@ -130,7 +130,6 @@ fn vec_move(_1: Vec) -> () { } scope 18 (inlined alloc::raw_vec::RawVec::::non_null) { debug self => _31; - let mut _41: &alloc::raw_vec::RawVecInner; scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _4: std::ptr::NonNull; scope 20 (inlined Unique::::cast::) { @@ -150,9 +149,7 @@ fn vec_move(_1: Vec) -> () { } scope 12 (inlined Vec::::allocator) { debug self => _29; - let mut _39: &alloc::raw_vec::RawVec; scope 13 (inlined alloc::raw_vec::RawVec::::allocator) { - let mut _40: &alloc::raw_vec::RawVecInner; scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) { } } @@ -183,13 +180,10 @@ fn vec_move(_1: Vec) -> () { StorageLive(_3); // DBG: _30 = &_2; // DBG: _29 = &(_2.0: std::vec::Vec); - // DBG: _39 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - // DBG: _40 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _3 = &raw const ((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global); StorageDead(_3); // DBG: _32 = &_2; // DBG: _31 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - // DBG: _41 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _4 = copy (((((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _5 = copy _4 as *const impl Sized (Transmute); _6 = NonNull:: { pointer: copy _5 }; @@ -247,7 +241,7 @@ fn vec_move(_1: Vec) -> () { bb4: { // DBG: _38 = &_2; // DBG: _37 = &((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec); - // DBG: _42 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); + // DBG: _39 = &(((_2.0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); StorageLive(_19); _19 = SizeOf(impl Sized); switchInt(move _19) -> [0: bb5, otherwise: bb6]; diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir index 86c729b3e95e..2cab88182962 100644 --- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir @@ -71,21 +71,17 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 // DBG: _16 = &((*_3).3: usize); StorageLive(_6); // DBG: _17 = &_13; - // DBG: _18 = &_15; + // DBG: _18 = &?; _4 = copy ((*_3).0: usize); _5 = copy ((*_3).2: usize); _6 = Le(copy _4, copy _5); - switchInt(move _6) -> [0: bb1, otherwise: bb2]; + switchInt(move _6) -> [0: bb2, otherwise: bb1]; } bb1: { - goto -> bb4; - } - - bb2: { StorageLive(_9); // DBG: _19 = &_16; - // DBG: _20 = &_14; + // DBG: _20 = &?; StorageLive(_7); _7 = copy ((*_3).3: usize); StorageLive(_8); @@ -93,29 +89,25 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _9 = Le(move _7, move _8); StorageDead(_8); StorageDead(_7); - switchInt(move _9) -> [0: bb3, otherwise: bb8]; + switchInt(move _9) -> [0: bb2, otherwise: bb6]; + } + + bb2: { + StorageLive(_10); + // DBG: _21 = &_15; + // DBG: _22 = &?; + _10 = Le(copy _5, copy _4); + switchInt(move _10) -> [0: bb3, otherwise: bb4]; } bb3: { - goto -> bb4; + _0 = const false; + goto -> bb5; } bb4: { - StorageLive(_10); - // DBG: _21 = &_15; - // DBG: _22 = &_13; - _10 = Le(copy _5, copy _4); - switchInt(move _10) -> [0: bb5, otherwise: bb6]; - } - - bb5: { - _0 = const false; - goto -> bb7; - } - - bb6: { // DBG: _23 = &_14; - // DBG: _24 = &_16; + // DBG: _24 = &?; StorageLive(_11); _11 = copy ((*_3).1: usize); StorageLive(_12); @@ -123,20 +115,20 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2 _0 = Le(move _11, move _12); StorageDead(_12); StorageDead(_11); + goto -> bb5; + } + + bb5: { + StorageDead(_10); + goto -> bb7; + } + + bb6: { + _0 = const true; goto -> bb7; } bb7: { - StorageDead(_10); - goto -> bb9; - } - - bb8: { - _0 = const true; - goto -> bb9; - } - - bb9: { StorageDead(_9); StorageDead(_6); return; diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index eebd4a7eb50e..2eee8a97db0d 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -57,14 +55,8 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - StorageLive(_6); - // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec); - StorageLive(_7); - // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); - StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index eebd4a7eb50e..2eee8a97db0d 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _4: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _6: &alloc::raw_vec::RawVec; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - let mut _7: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _2: std::ptr::NonNull; @@ -57,14 +55,8 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { bb0: { StorageLive(_2); StorageLive(_3); - StorageLive(_6); - // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec); - StorageLive(_7); - // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageDead(_7); _3 = copy _2 as *const u8 (Transmute); - StorageDead(_6); StorageLive(_4); _4 = copy ((*_1).1: usize); StorageLive(_5); From ecb831dcf4c28d3b66c9bce7aa4c3a8eb221fa5e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 16:29:18 +1000 Subject: [PATCH 475/537] Extract helper method `set_metadata_node` --- compiler/rustc_codegen_llvm/src/asm.rs | 4 +- compiler/rustc_codegen_llvm/src/builder.rs | 54 +++++++--------------- compiler/rustc_codegen_llvm/src/context.rs | 19 ++++++++ 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index cc09fa5b69ba..93b1cf272ab7 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>( bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), ) })); - let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; - let md = bx.get_metadata_value(md); - llvm::LLVMSetMetadata(call, kind, md); + bx.cx.set_metadata_node(call, kind, &srcloc); Some(call) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5271d0b4bb8a..e7cb18ab22da 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1,12 +1,12 @@ use std::borrow::{Borrow, Cow}; +use std::iter; use std::ops::Deref; -use std::{iter, ptr}; use rustc_ast::expand::typetree::FncTree; pub(crate) mod autodiff; pub(crate) mod gpu_offload; -use libc::{c_char, c_uint, size_t}; +use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::{Align, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; @@ -396,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { md.push(weight(is_cold)); } - unsafe { - let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t); - self.cx.set_metadata(switch, llvm::MD_prof, md_node); - } + self.cx.set_metadata_node(switch, llvm::MD_prof, &md); } fn invoke( @@ -801,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - unsafe { - let llty = self.cx.val_ty(load); - let md = [ - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), - ]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_range, md); - } + let llty = self.cx.val_ty(load); + let md = [ + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), + ]; + self.set_metadata_node(load, llvm::MD_range, &md); } fn nonnull_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_nonnull, md); - } + self.set_metadata_node(load, llvm::MD_nonnull, &[]); } fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { @@ -865,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // // [1]: https://llvm.org/docs/LangRef.html#store-instruction let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1)); - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1); - self.set_metadata(store, llvm::MD_nontemporal, md); + self.set_metadata_node(store, llvm::MD_nontemporal, &[one]); } } store @@ -1381,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn set_invariant_load(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_invariant_load, md); - } + self.set_metadata_node(load, llvm::MD_invariant_load, &[]); } fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { @@ -1528,25 +1515,16 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn align_metadata(&mut self, load: &'ll Value, align: Align) { - unsafe { - let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_align, md); - } + let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; + self.set_metadata_node(load, llvm::MD_align, &md); } fn noundef_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_noundef, md); - } + self.set_metadata_node(load, llvm::MD_noundef, &[]); } pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(inst, llvm::MD_unpredictable, md); - } + self.set_metadata_node(inst, llvm::MD_unpredictable, &[]); } } impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b1da6f7c7406..03d9daeea360 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1002,6 +1002,11 @@ impl CodegenCx<'_, '_> { } impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { + /// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`. + pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata { + unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) } + } + /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. pub(crate) fn set_metadata<'a>( &self, @@ -1012,6 +1017,20 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { let node = self.get_metadata_value(md); llvm::LLVMSetMetadata(val, kind_id, node); } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`) + pub(crate) fn set_metadata_node( + &self, + instruction: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + self.set_metadata(instruction, kind_id, md); + } } impl HasDataLayout for CodegenCx<'_, '_> { From ffeed2b94ed432c959e3d9cf9bd5f7016f9577d3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 16:39:58 +1000 Subject: [PATCH 476/537] Extract helper method `module_add_named_metadata_node` --- compiler/rustc_codegen_llvm/src/consts.rs | 11 +-------- compiler/rustc_codegen_llvm/src/context.rs | 26 ++++++++++++++-------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 40375ef65109..b4ca85a26c8b 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> { let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = self.create_metadata(bytes); let data = [section, alloc]; - let meta = - unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; - let val = self.get_metadata_value(meta); - unsafe { - llvm::LLVMAddNamedMetadataOperand( - self.llmod, - c"wasm.custom_sections".as_ptr(), - val, - ) - }; + self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data); } } else { base::set_link_section(g, attrs); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 03d9daeea360..f1f3d6a8b62c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::{Metadata, MetadataKindId}; +use crate::llvm::{Metadata, MetadataKindId, Module}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util}; @@ -495,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>( format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); - - unsafe { - llvm::LLVMAddNamedMetadataOperand( - llmod, - c"llvm.ident".as_ptr(), - &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), - ); - } + cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]); // Emit RISC-V specific target-abi metadata // to workaround lld as the LTO plugin not @@ -1031,6 +1024,21 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { let md = self.md_node_in_context(md_list); self.set_metadata(instruction, kind_id, md); } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`) + pub(crate) fn module_add_named_metadata_node( + &self, + module: &'ll Module, + kind_name: &CStr, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + let md_as_val = self.get_metadata_value(md); + unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) }; + } } impl HasDataLayout for CodegenCx<'_, '_> { From 6a58f80a3c4cf53f8092e75c07cebd5e913cccf0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 17:19:30 +1000 Subject: [PATCH 477/537] Extract helper method `global_add_metadata_node` --- compiler/rustc_codegen_llvm/src/context.rs | 13 ++++++++++ .../src/debuginfo/metadata.rs | 9 +++---- compiler/rustc_codegen_llvm/src/type_.rs | 24 ++++--------------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f1f3d6a8b62c..d09121016d05 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1039,6 +1039,19 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { let md_as_val = self.get_metadata_value(md); unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) }; } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_add_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) }; + } } impl HasDataLayout for CodegenCx<'_, '_> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bc20c7594134..6b2fe27425e9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1607,13 +1607,10 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); + let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; + cx.global_add_metadata_node(vtable, llvm::MD_type, &type_); + unsafe { - let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; - llvm::LLVMRustGlobalAddMetadata( - vtable, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()), - ); let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5b97898a4b88..9f8b7d2efdb5 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -302,14 +302,8 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_add_metadata_node(function, llvm::MD_type, &v); } fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { @@ -329,18 +323,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_kcfi_type, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { From 8ef9821bf2e27bf7ab4f9a0e3d0975dc59d3d932 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 17:33:28 +1000 Subject: [PATCH 478/537] Extract helper method `global_set_metadata_node` --- compiler/rustc_codegen_llvm/src/context.rs | 13 ++++++++++ .../src/debuginfo/metadata.rs | 7 ++---- compiler/rustc_codegen_llvm/src/type_.rs | 24 ++++--------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d09121016d05..922575dd63cf 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1052,6 +1052,19 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { let md = self.md_node_in_context(md_list); unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) }; } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_set_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) }; + } } impl HasDataLayout for CodegenCx<'_, '_> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 6b2fe27425e9..2f9e7cae54f2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1610,11 +1610,8 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; cx.global_add_metadata_node(vtable, llvm::MD_type, &type_); - unsafe { - let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); - let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); - llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata); - } + let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))]; + cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility); } /// Creates debug information for the given vtable, which is for the diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 9f8b7d2efdb5..1e5cf8374e37 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -308,14 +308,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_set_metadata_node(function, llvm::MD_type, &v); } fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { @@ -328,17 +322,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_kcfi_type, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } } From 16cfde9703f74cfc96c0c0bd51958a2627dfb5ea Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 2 Oct 2025 16:44:40 +0800 Subject: [PATCH 479/537] triagebot: disable auto stable-regression compiler backport nominations No prejudice against re-enabling them if the nominations include a bit more context on _why_ it's automatically nominated and _which_ regression(s) are being addressed. Or as proposed, it could also simply become a reminder-to-nominate _comment_. --- triagebot.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index a04f8d280723..79b5c2d1b723 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -61,10 +61,6 @@ required-issue-label = "regression-from-stable-to-beta" # if the above conditions matches, the PR will receive these labels add-labels = ["beta-nominated"] -[backport.t-compiler-stable-backport] -required-pr-labels = ["T-compiler"] -required-issue-label = "regression-from-stable-to-stable" -add-labels = ["stable-nominated"] # ------------------------------------------------------------------------------ # Ping groups From 5bf5e7116099d85a99d047cfa43db155074e594a Mon Sep 17 00:00:00 2001 From: Reuben Cruise Date: Thu, 25 Sep 2025 16:11:34 +0100 Subject: [PATCH 480/537] Extends `rustc_force_inline` to inherent methods - Changes parser to allow application to inherent methods. - Adds tests to confirm extended functionality works just as the existing. --- .../src/attributes/inline.rs | 6 ++- ...r-{closure#0}.ForceInline.panic-abort.diff | 21 ++++++++++ ...-{closure#0}.ForceInline.panic-unwind.diff | 21 ++++++++++ .../mir-opt/inline/forced_closure_inherent.rs | 19 ++++++++++ ...herent.caller.ForceInline.panic-abort.diff | 21 ++++++++++ ...erent.caller.ForceInline.panic-unwind.diff | 21 ++++++++++ tests/mir-opt/inline/forced_inherent.rs | 17 +++++++++ ...iguous.caller.ForceInline.panic-abort.diff | 21 ++++++++++ ...guous.caller.ForceInline.panic-unwind.diff | 21 ++++++++++ .../inline/forced_inherent_ambiguous.rs | 25 ++++++++++++ ..._async.caller.ForceInline.panic-abort.diff | 12 ++++++ ...async.caller.ForceInline.panic-unwind.diff | 12 ++++++ tests/mir-opt/inline/forced_inherent_async.rs | 18 +++++++++ ...d_code.caller.ForceInline.panic-abort.diff | 21 ++++++++++ ..._code.caller.ForceInline.panic-unwind.diff | 21 ++++++++++ .../inline/forced_inherent_dead_code.rs | 21 ++++++++++ tests/ui/force-inlining/inherent.rs | 21 ++++++++++ tests/ui/force-inlining/inherent.stderr | 13 +++++++ tests/ui/force-inlining/invalid.rs | 1 - tests/ui/force-inlining/invalid.stderr | 38 ++++++++----------- 20 files changed, 346 insertions(+), 25 deletions(-) create mode 100644 tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_closure_inherent.rs create mode 100644 tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_inherent.rs create mode 100644 tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_inherent_ambiguous.rs create mode 100644 tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_inherent_async.rs create mode 100644 tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff create mode 100644 tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff create mode 100644 tests/mir-opt/inline/forced_inherent_dead_code.rs create mode 100644 tests/ui/force-inlining/inherent.rs create mode 100644 tests/ui/force-inlining/inherent.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index a73430c9d009..a10ad27fcc68 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -72,7 +72,11 @@ impl SingleAttributeParser for RustcForceInlineParser { const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + ]); + const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { diff --git a/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff new file mode 100644 index 000000000000..8e03432c2af2 --- /dev/null +++ b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller::{closure#0}` before ForceInline ++ // MIR for `caller::{closure#0}` after ForceInline + + fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () { + let mut _0: (); + let _2: (); ++ scope 1 (inlined Foo::callee_forced) { ++ } + + bb0: { + StorageLive(_2); +- _2 = Foo::callee_forced() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_2); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff new file mode 100644 index 000000000000..0e41fd89dacf --- /dev/null +++ b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller::{closure#0}` before ForceInline ++ // MIR for `caller::{closure#0}` after ForceInline + + fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () { + let mut _0: (); + let _2: (); ++ scope 1 (inlined Foo::callee_forced) { ++ } + + bb0: { + StorageLive(_2); +- _2 = Foo::callee_forced() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_2); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_closure_inherent.rs b/tests/mir-opt/inline/forced_closure_inherent.rs new file mode 100644 index 000000000000..949c7d6ecbf2 --- /dev/null +++ b/tests/mir-opt/inline/forced_closure_inherent.rs @@ -0,0 +1,19 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +#![feature(rustc_attrs)] + +struct Foo {} + +impl Foo { + #[rustc_force_inline] + pub fn callee_forced() {} +} + +// EMIT_MIR forced_closure_inherent.caller-{closure#0}.ForceInline.diff +pub fn caller() { + (|| { + Foo::callee_forced(); + // CHECK-LABEL: fn caller::{closure#0}( + // CHECK: (inlined Foo::callee_forced) + })(); +} diff --git a/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff new file mode 100644 index 000000000000..6ea1894af989 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::bar) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::bar() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff new file mode 100644 index 000000000000..dd91c3387723 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::bar) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::bar() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent.rs b/tests/mir-opt/inline/forced_inherent.rs new file mode 100644 index 000000000000..24bf8daa6445 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent.rs @@ -0,0 +1,17 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +#![feature(rustc_attrs)] + +struct Foo; + +impl Foo { + #[rustc_force_inline] + fn bar() {} +} + +// EMIT_MIR forced_inherent.caller.ForceInline.diff +fn caller() { + Foo::bar(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined Foo::bar) +} diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff new file mode 100644 index 000000000000..6ea1894af989 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::bar) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::bar() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff new file mode 100644 index 000000000000..dd91c3387723 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::bar) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::bar() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.rs b/tests/mir-opt/inline/forced_inherent_ambiguous.rs new file mode 100644 index 000000000000..e3c5d3e4f9e8 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_ambiguous.rs @@ -0,0 +1,25 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +#![feature(rustc_attrs)] + +struct Foo; + +impl Foo { + #[rustc_force_inline] + fn bar() {} +} + +trait Tr { + fn bar(); +} + +impl Tr for Foo { + fn bar() {} +} + +// EMIT_MIR forced_inherent_ambiguous.caller.ForceInline.diff +fn caller() { + Foo::bar(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined Foo::bar) +} diff --git a/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff new file mode 100644 index 000000000000..6495ddbafba4 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff @@ -0,0 +1,12 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> {async fn body of caller()} { + let mut _0: {async fn body of caller()}; + + bb0: { + _0 = {coroutine@$DIR/forced_inherent_async.rs:14:19: 18:2 (#0)}; + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff new file mode 100644 index 000000000000..6495ddbafba4 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,12 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> {async fn body of caller()} { + let mut _0: {async fn body of caller()}; + + bb0: { + _0 = {coroutine@$DIR/forced_inherent_async.rs:14:19: 18:2 (#0)}; + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_async.rs b/tests/mir-opt/inline/forced_inherent_async.rs new file mode 100644 index 000000000000..ce58a0ac48f4 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_async.rs @@ -0,0 +1,18 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 --crate-type=lib +//@ edition: 2021 +#![feature(rustc_attrs)] + +struct Foo {} + +impl Foo { + #[rustc_force_inline] + pub fn callee_forced() {} +} + +// EMIT_MIR forced_inherent_async.caller.ForceInline.diff +async fn caller() { + Foo::callee_forced(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined Foo::callee_forced) +} diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff new file mode 100644 index 000000000000..edaf2820d85c --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::callee_forced() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff new file mode 100644 index 000000000000..22f8b14a724b --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `caller` before ForceInline ++ // MIR for `caller` after ForceInline + + fn caller() -> () { + let mut _0: (); + let _1: (); ++ scope 1 (inlined Foo::callee_forced) { ++ } + + bb0: { + StorageLive(_1); +- _1 = Foo::callee_forced() -> [return: bb1, unwind continue]; +- } +- +- bb1: { + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.rs b/tests/mir-opt/inline/forced_inherent_dead_code.rs new file mode 100644 index 000000000000..057a4cac5287 --- /dev/null +++ b/tests/mir-opt/inline/forced_inherent_dead_code.rs @@ -0,0 +1,21 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Copt-level=0 -Clink-dead-code +#![feature(rustc_attrs)] + +struct Foo {} + +impl Foo { + #[rustc_force_inline] + pub fn callee_forced() {} +} + +// EMIT_MIR forced_inherent_dead_code.caller.ForceInline.diff +pub fn caller() { + Foo::callee_forced(); + // CHECK-LABEL: fn caller( + // CHECK: (inlined Foo::callee_forced) +} + +fn main() { + caller(); +} diff --git a/tests/ui/force-inlining/inherent.rs b/tests/ui/force-inlining/inherent.rs new file mode 100644 index 000000000000..25c76eaf37a9 --- /dev/null +++ b/tests/ui/force-inlining/inherent.rs @@ -0,0 +1,21 @@ +//@ check-fail +#![feature(rustc_attrs)] + +struct Foo; + +impl Foo { + #[rustc_force_inline] + //~^ ERROR: `Foo::bar` is incompatible with `#[rustc_force_inline]` + #[rustc_no_mir_inline] + fn bar() {} +} + +fn bar_caller() { + unsafe { + Foo::bar(); + } +} + +fn main() { + bar_caller(); +} diff --git a/tests/ui/force-inlining/inherent.stderr b/tests/ui/force-inlining/inherent.stderr new file mode 100644 index 000000000000..1ffc78848fea --- /dev/null +++ b/tests/ui/force-inlining/inherent.stderr @@ -0,0 +1,13 @@ +error: `Foo::bar` is incompatible with `#[rustc_force_inline]` + --> $DIR/inherent.rs:7:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn bar() {} + | -------- `Foo::bar` defined here + | + = note: incompatible due to: #[rustc_no_mir_inline] + +error: aborting due to 1 previous error + diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs index 6047739992f1..eaacbb502090 100644 --- a/tests/ui/force-inlining/invalid.rs +++ b/tests/ui/force-inlining/invalid.rs @@ -114,7 +114,6 @@ trait FooQux = FooBaz; //~^ ERROR attribute cannot be used on impl Bar { #[rustc_force_inline] -//~^ ERROR attribute cannot be used on fn foo() {} } diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 299a3ed4a462..df3b646b6cec 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -1,5 +1,5 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - --> $DIR/invalid.rs:132:11 + --> $DIR/invalid.rs:131:11 | LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ error: `#[rustc_force_inline]` attribute cannot be used on foreign functions LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[rustc_force_inline]` can only be applied to functions + = help: `#[rustc_force_inline]` can be applied to functions and inherent methods error: `#[rustc_force_inline]` attribute cannot be used on type aliases --> $DIR/invalid.rs:66:1 @@ -222,7 +222,7 @@ error: `#[rustc_force_inline]` attribute cannot be used on provided trait method LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[rustc_force_inline]` can only be applied to functions + = help: `#[rustc_force_inline]` can be applied to functions and inherent methods error: `#[rustc_force_inline]` attribute cannot be used on trait aliases --> $DIR/invalid.rs:109:1 @@ -240,16 +240,8 @@ LL | #[rustc_force_inline] | = help: `#[rustc_force_inline]` can only be applied to functions -error: `#[rustc_force_inline]` attribute cannot be used on inherent methods - --> $DIR/invalid.rs:116:5 - | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: `#[rustc_force_inline]` can only be applied to functions - error: `#[rustc_force_inline]` attribute cannot be used on trait impl blocks - --> $DIR/invalid.rs:121:1 + --> $DIR/invalid.rs:120:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -257,7 +249,7 @@ LL | #[rustc_force_inline] = help: `#[rustc_force_inline]` can only be applied to functions error: `#[rustc_force_inline]` attribute cannot be used on macro defs - --> $DIR/invalid.rs:128:1 + --> $DIR/invalid.rs:127:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +257,7 @@ LL | #[rustc_force_inline] = help: `#[rustc_force_inline]` can only be applied to functions error: `#[rustc_force_inline]` attribute cannot be used on function params - --> $DIR/invalid.rs:132:11 + --> $DIR/invalid.rs:131:11 | LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -273,15 +265,15 @@ LL | fn barqux(#[rustc_force_inline] _x: u32) {} = help: `#[rustc_force_inline]` can only be applied to functions error: `#[rustc_force_inline]` attribute cannot be used on closures - --> $DIR/invalid.rs:149:14 + --> $DIR/invalid.rs:148:14 | LL | let _x = #[rustc_force_inline] || { }; | ^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[rustc_force_inline]` can only be applied to functions + = help: `#[rustc_force_inline]` can be applied to functions and inherent methods error: `#[rustc_force_inline]` attribute cannot be used on expressions - --> $DIR/invalid.rs:151:14 + --> $DIR/invalid.rs:150:14 | LL | let _y = #[rustc_force_inline] 3 + 4; | ^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +281,7 @@ LL | let _y = #[rustc_force_inline] 3 + 4; = help: `#[rustc_force_inline]` can only be applied to functions error: `#[rustc_force_inline]` attribute cannot be used on statements - --> $DIR/invalid.rs:153:5 + --> $DIR/invalid.rs:152:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -297,7 +289,7 @@ LL | #[rustc_force_inline] = help: `#[rustc_force_inline]` can only be applied to functions error: `#[rustc_force_inline]` attribute cannot be used on match arms - --> $DIR/invalid.rs:158:9 + --> $DIR/invalid.rs:157:9 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -305,7 +297,7 @@ LL | #[rustc_force_inline] = help: `#[rustc_force_inline]` can only be applied to functions error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:136:1 + --> $DIR/invalid.rs:135:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -314,7 +306,7 @@ LL | async fn async_foo() {} | -------------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:140:1 + --> $DIR/invalid.rs:139:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -323,7 +315,7 @@ LL | gen fn gen_foo() {} | ---------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:144:1 + --> $DIR/invalid.rs:143:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -331,7 +323,7 @@ LL | LL | async gen fn async_gen_foo() {} | ---------------------------- `async`, `gen` or `async gen` function -error: aborting due to 37 previous errors +error: aborting due to 36 previous errors Some errors have detailed explanations: E0539, E0805. For more information about an error, try `rustc --explain E0539`. From 6275a19255afb2a09b932986928e81cf431a7358 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 2 Oct 2025 15:24:04 +0200 Subject: [PATCH 481/537] Move doc_cfg-specific code into `cfg.rs` --- src/librustdoc/clean/cfg.rs | 267 +++++++++++++++++++++++++++++++++- src/librustdoc/clean/mod.rs | 1 + src/librustdoc/clean/types.rs | 264 +-------------------------------- 3 files changed, 268 insertions(+), 264 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index aa614b73dea7..881a81b22f0f 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -3,14 +3,18 @@ // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619), // switch to use those structures instead. +use std::sync::Arc; use std::{fmt, mem, ops}; use itertools::Either; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::attrs::AttributeKind; +use rustc_middle::ty::TyCtxt; use rustc_session::parse::ParseSess; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; +use {rustc_ast as ast, rustc_hir as hir}; use crate::display::{Joined as _, MaybeDisplay, Wrapped}; use crate::html::escape::Escape; @@ -600,3 +604,264 @@ impl fmt::Display for Display<'_> { } } } + +/// This type keeps track of (doc) cfg information as we go down the item tree. +#[derive(Clone, Debug)] +pub(crate) struct CfgInfo { + /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active + /// `doc(auto_cfg(show(...)))` cfgs. + hidden_cfg: FxHashSet, + /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while + /// taking into account the `hidden_cfg` information. + current_cfg: Cfg, + /// Whether the `doc(auto_cfg())` feature is enabled or not at this point. + auto_cfg_active: bool, + /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`, + /// instead we will concatenate with it. However, if it's not the case, we need to overwrite + /// `current_cfg`. + parent_is_doc_cfg: bool, +} + +impl Default for CfgInfo { + fn default() -> Self { + Self { + hidden_cfg: FxHashSet::from_iter([ + Cfg::Cfg(sym::test, None), + Cfg::Cfg(sym::doc, None), + Cfg::Cfg(sym::doctest, None), + ]), + current_cfg: Cfg::True, + auto_cfg_active: true, + parent_is_doc_cfg: false, + } + } +} + +fn show_hide_show_conflict_error( + tcx: TyCtxt<'_>, + item_span: rustc_span::Span, + previous: rustc_span::Span, +) { + let mut diag = tcx.sess.dcx().struct_span_err( + item_span, + format!( + "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item" + ), + ); + diag.span_note(previous, "first change was here"); + diag.emit(); +} + +/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument. +/// +/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and +/// `auto_cfg(show(...))` on the same item and emits an error if it's the case. +/// +/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs` +/// and in `new_hide_attrs` arguments. +fn handle_auto_cfg_hide_show( + tcx: TyCtxt<'_>, + cfg_info: &mut CfgInfo, + sub_attr: &MetaItemInner, + is_show: bool, + new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, + new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, +) { + if let MetaItemInner::MetaItem(item) = sub_attr + && let MetaItemKind::List(items) = &item.kind + { + for item in items { + // FIXME: Report in case `Cfg::parse` reports an error? + if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) { + if is_show { + if let Some(span) = new_hide_attrs.get(&(key, value)) { + show_hide_show_conflict_error(tcx, item.span(), *span); + } else { + new_show_attrs.insert((key, value), item.span()); + } + cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value)); + } else { + if let Some(span) = new_show_attrs.get(&(key, value)) { + show_hide_show_conflict_error(tcx, item.span(), *span); + } else { + new_hide_attrs.insert((key, value), item.span()); + } + cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value)); + } + } + } + } +} + +pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator + Clone>( + attrs: I, + tcx: TyCtxt<'_>, + cfg_info: &mut CfgInfo, +) -> Option> { + fn single(it: T) -> Option { + let mut iter = it.into_iter(); + let item = iter.next()?; + if iter.next().is_some() { + return None; + } + Some(item) + } + + fn check_changed_auto_active_status( + changed_auto_active_status: &mut Option, + attr: &ast::MetaItem, + cfg_info: &mut CfgInfo, + tcx: TyCtxt<'_>, + new_value: bool, + ) -> bool { + if let Some(first_change) = changed_auto_active_status { + if cfg_info.auto_cfg_active != new_value { + tcx.sess + .dcx() + .struct_span_err( + vec![*first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ) + .emit(); + return true; + } + } else { + *changed_auto_active_status = Some(attr.span); + } + cfg_info.auto_cfg_active = new_value; + false + } + + let mut new_show_attrs = FxHashMap::default(); + let mut new_hide_attrs = FxHashMap::default(); + + let mut doc_cfg = attrs + .clone() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes. + if doc_cfg.peek().is_some() { + let sess = tcx.sess; + // We overwrite existing `cfg`. + if !cfg_info.parent_is_doc_cfg { + cfg_info.current_cfg = Cfg::True; + cfg_info.parent_is_doc_cfg = true; + } + for attr in doc_cfg { + if let Some(cfg_mi) = + attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess)) + { + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg_info.current_cfg &= new_cfg, + Err(e) => { + sess.dcx().span_err(e.span, e.msg); + } + } + } + } + } else { + cfg_info.parent_is_doc_cfg = false; + } + + let mut changed_auto_active_status = None; + + // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes. + for attr in attrs { + if let Some(ident) = attr.ident() + && ident.name == sym::doc + && let Some(attrs) = attr.meta_item_list() + { + for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) { + let MetaItemInner::MetaItem(attr) = attr else { + continue; + }; + match &attr.kind { + MetaItemKind::Word => { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; + } + } + MetaItemKind::NameValue(lit) => { + if let LitKind::Bool(value) = lit.kind { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + value, + ) { + return None; + } + } + } + MetaItemKind::List(sub_attrs) => { + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; + } + for sub_attr in sub_attrs.iter() { + if let Some(ident) = sub_attr.ident() + && (ident.name == sym::show || ident.name == sym::hide) + { + handle_auto_cfg_hide_show( + tcx, + cfg_info, + &sub_attr, + ident.name == sym::show, + &mut new_show_attrs, + &mut new_hide_attrs, + ); + } + } + } + } + } + } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { + // Treat `#[target_feature(enable = "feat")]` attributes as if they were + // `#[doc(cfg(target_feature = "feat"))]` attributes as well. + for (feature, _) in features { + cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); + } + continue; + } else if !cfg_info.parent_is_doc_cfg + && let Some(ident) = attr.ident() + && matches!(ident.name, sym::cfg | sym::cfg_trace) + && let Some(attr) = single(attr.meta_item_list()?) + && let Ok(new_cfg) = Cfg::parse(&attr) + { + cfg_info.current_cfg &= new_cfg; + } + } + + // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing + // to be done here. + if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg { + None + } else if cfg_info.parent_is_doc_cfg { + if cfg_info.current_cfg == Cfg::True { + None + } else { + Some(Arc::new(cfg_info.current_cfg.clone())) + } + } else { + // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the + // hidden ones afterward. + match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) { + None | Some(Cfg::True) => None, + Some(cfg) => Some(Arc::new(cfg)), + } + } +} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c6339dd47559..4fd8d245089e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -58,6 +58,7 @@ use tracing::{debug, instrument}; use utils::*; use {rustc_ast as ast, rustc_hir as hir}; +pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs}; pub(crate) use self::types::*; pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls}; use crate::core::DocContext; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6e3dfa0ac221..f3662a67bbea 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,8 +6,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_ast::ast::{LitKind, MetaItemInner, MetaItemKind}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -922,267 +921,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( .flatten() } -/// This type keeps track of (doc) cfg information as we go down the item tree. -#[derive(Clone, Debug)] -pub(crate) struct CfgInfo { - /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active - /// `doc(auto_cfg(show(...)))` cfgs. - hidden_cfg: FxHashSet, - /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while - /// taking into account the `hidden_cfg` information. - current_cfg: Cfg, - /// Whether the `doc(auto_cfg())` feature is enabled or not at this point. - auto_cfg_active: bool, - /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`, - /// instead we will concatenate with it. However, if it's not the case, we need to overwrite - /// `current_cfg`. - parent_is_doc_cfg: bool, -} - -impl Default for CfgInfo { - fn default() -> Self { - Self { - hidden_cfg: FxHashSet::from_iter([ - Cfg::Cfg(sym::test, None), - Cfg::Cfg(sym::doc, None), - Cfg::Cfg(sym::doctest, None), - ]), - current_cfg: Cfg::True, - auto_cfg_active: true, - parent_is_doc_cfg: false, - } - } -} - -fn show_hide_show_conflict_error( - tcx: TyCtxt<'_>, - item_span: rustc_span::Span, - previous: rustc_span::Span, -) { - let mut diag = tcx.sess.dcx().struct_span_err( - item_span, - format!( - "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item" - ), - ); - diag.span_note(previous, "first change was here"); - diag.emit(); -} - -/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument. -/// -/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and -/// `auto_cfg(show(...))` on the same item and emits an error if it's the case. -/// -/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs` -/// and in `new_hide_attrs` arguments. -fn handle_auto_cfg_hide_show( - tcx: TyCtxt<'_>, - cfg_info: &mut CfgInfo, - sub_attr: &MetaItemInner, - is_show: bool, - new_show_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, - new_hide_attrs: &mut FxHashMap<(Symbol, Option), rustc_span::Span>, -) { - if let MetaItemInner::MetaItem(item) = sub_attr - && let MetaItemKind::List(items) = &item.kind - { - for item in items { - // FIXME: Report in case `Cfg::parse` reports an error? - if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) { - if is_show { - if let Some(span) = new_hide_attrs.get(&(key, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_show_attrs.insert((key, value), item.span()); - } - cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value)); - } else { - if let Some(span) = new_show_attrs.get(&(key, value)) { - show_hide_show_conflict_error(tcx, item.span(), *span); - } else { - new_hide_attrs.insert((key, value), item.span()); - } - cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value)); - } - } - } - } -} - -pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator + Clone>( - attrs: I, - tcx: TyCtxt<'_>, - cfg_info: &mut CfgInfo, -) -> Option> { - fn single(it: T) -> Option { - let mut iter = it.into_iter(); - let item = iter.next()?; - if iter.next().is_some() { - return None; - } - Some(item) - } - - fn check_changed_auto_active_status( - changed_auto_active_status: &mut Option, - attr: &ast::MetaItem, - cfg_info: &mut CfgInfo, - tcx: TyCtxt<'_>, - new_value: bool, - ) -> bool { - if let Some(first_change) = changed_auto_active_status { - if cfg_info.auto_cfg_active != new_value { - tcx.sess - .dcx() - .struct_span_err( - vec![*first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ) - .emit(); - return true; - } - } else { - *changed_auto_active_status = Some(attr.span); - } - cfg_info.auto_cfg_active = new_value; - false - } - - let mut new_show_attrs = FxHashMap::default(); - let mut new_hide_attrs = FxHashMap::default(); - - let mut doc_cfg = attrs - .clone() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|attr| attr.has_name(sym::cfg)) - .peekable(); - // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes. - if doc_cfg.peek().is_some() { - let sess = tcx.sess; - // We overwrite existing `cfg`. - if !cfg_info.parent_is_doc_cfg { - cfg_info.current_cfg = Cfg::True; - cfg_info.parent_is_doc_cfg = true; - } - for attr in doc_cfg { - if let Some(cfg_mi) = - attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess)) - { - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg_info.current_cfg &= new_cfg, - Err(e) => { - sess.dcx().span_err(e.span, e.msg); - } - } - } - } - } else { - cfg_info.parent_is_doc_cfg = false; - } - - let mut changed_auto_active_status = None; - - // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes. - for attr in attrs { - if let Some(ident) = attr.ident() - && ident.name == sym::doc - && let Some(attrs) = attr.meta_item_list() - { - for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) { - let MetaItemInner::MetaItem(attr) = attr else { - continue; - }; - match &attr.kind { - MetaItemKind::Word => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - } - MetaItemKind::NameValue(lit) => { - if let LitKind::Bool(value) = lit.kind { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - value, - ) { - return None; - } - } - } - MetaItemKind::List(sub_attrs) => { - if check_changed_auto_active_status( - &mut changed_auto_active_status, - attr, - cfg_info, - tcx, - true, - ) { - return None; - } - for sub_attr in sub_attrs.iter() { - if let Some(ident) = sub_attr.ident() - && (ident.name == sym::show || ident.name == sym::hide) - { - handle_auto_cfg_hide_show( - tcx, - cfg_info, - &sub_attr, - ident.name == sym::show, - &mut new_show_attrs, - &mut new_hide_attrs, - ); - } - } - } - } - } - } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr { - // Treat `#[target_feature(enable = "feat")]` attributes as if they were - // `#[doc(cfg(target_feature = "feat"))]` attributes as well. - for (feature, _) in features { - cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); - } - continue; - } else if !cfg_info.parent_is_doc_cfg - && let Some(ident) = attr.ident() - && matches!(ident.name, sym::cfg | sym::cfg_trace) - && let Some(attr) = single(attr.meta_item_list()?) - && let Ok(new_cfg) = Cfg::parse(&attr) - { - cfg_info.current_cfg &= new_cfg; - } - } - - // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing - // to be done here. - if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg { - None - } else if cfg_info.parent_is_doc_cfg { - if cfg_info.current_cfg == Cfg::True { - None - } else { - Some(Arc::new(cfg_info.current_cfg.clone())) - } - } else { - // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the - // hidden ones afterward. - match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) { - None | Some(Cfg::True) => None, - Some(cfg) => Some(Arc::new(cfg)), - } - } -} - pub(crate) trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `word` fn has_word(self, word: Symbol) -> bool From 7715c0d648cade90c172ee73ca26c8d80ff752f0 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 2 Oct 2025 11:47:14 +0100 Subject: [PATCH 482/537] add arm-maintainers to various targets --- src/doc/rustc/src/SUMMARY.md | 2 + src/doc/rustc/src/platform-support.md | 6 +-- .../aarch64-unknown-linux-gnu.md | 50 ++++++++++++++++++ .../platform-support/aarch64-unknown-none.md | 5 +- .../rustc/src/platform-support/arm-linux.md | 4 +- .../armv7-unknown-linux-gnueabi.md | 51 +++++++++++++++++++ .../src/platform-support/armv7a-none-eabi.md | 5 +- .../src/platform-support/armv7r-none-eabi.md | 7 ++- .../platform-support/armv8r-none-eabihf.md | 7 ++- .../platform-support/thumbv7em-none-eabi.md | 6 ++- .../platform-support/thumbv7m-none-eabi.md | 6 ++- .../thumbv8m.base-none-eabi.md | 6 ++- .../thumbv8m.main-none-eabi.md | 6 ++- .../src/platform-support/unknown-uefi.md | 8 ++- 14 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md create mode 100644 src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 67882bb38132..a9ce738a0138 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -47,6 +47,7 @@ - [\*-apple-watchos](platform-support/apple-watchos.md) - [\*-apple-visionos](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) + - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md) - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) @@ -67,6 +68,7 @@ - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [armv7-unknown-linux-gnueabi](platform-support/armv7-unknown-linux-gnueabi.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d0b6ed51bc16..263ea1ddb425 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -34,7 +34,7 @@ target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) [`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC -`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) +[`aarch64-unknown-linux-gnu`](platform-support/aarch64-unknown-linux-gnu.md) | ARM64 Linux (kernel 4.1+, glibc 2.17+) [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) @@ -93,7 +93,7 @@ target | notes [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) +[`armv7-unknown-linux-gnueabihf`](platform-support/armv7-unknown-linux-gnueabi.md) | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required @@ -159,7 +159,7 @@ target | std | notes [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android -`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) +[`armv7-unknown-linux-gnueabi`](platform-support/armv7-unknown-linux-gnueabi.md) | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md new file mode 100644 index 000000000000..2003a3cb9eaa --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md @@ -0,0 +1,50 @@ +# `aarch64-unknown-linux-gnu` + +**Tier: 1 (with Host Tools)** + +Target for 64-bit little endian ARMv8-A Linux 4.1+ programs using glibc 2.17+. + +## Target maintainers + +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com + +## Requirements + +Building the target itself requires a 64-bit little endian ARMv8-A compiler that is supported by +`cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build: + +```toml +[build] +target = ["aarch64-unknown-linux-gnu"] +``` + +If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.aarch64-unknown-linux-musl] +cc = "aarch64-linux-gnu-gcc" +cxx = "aarch64-linux-gnu-g++" +ar = "aarch64-linux-gnu-ar" +linker = "aarch64-linux-gnu-gcc" +``` + +## Building Rust programs + +This target is distributed through `rustup`, and otherwise requires no special configuration. + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit little endian ARMv8-A host or via QEMU +emulation. diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md index 7e18e8c157f7..3d776677d23e 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -14,9 +14,12 @@ Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus ## Target maintainers -[Rust Embedded Devices Working Group Arm Team] +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md index 5f40743f3d07..c461a1a3403d 100644 --- a/src/doc/rustc/src/platform-support/arm-linux.md +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -14,8 +14,8 @@ Linux (but not Android). Those targets are: * [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md) * `armv5te-unknown-linux-musleabi` * `armv5te-unknown-linux-uclibceabi` -* `armv7-unknown-linux-gnueabi` -* `armv7-unknown-linux-gnueabihf` +* [`armv7-unknown-linux-gnueabi`](armv7-unknown-linux-gnueabi.md) +* [`armv7-unknown-linux-gnueabihf`](armv7-unknown-linux-gnueabi.md) * `armv7-unknown-linux-musleabi` * `armv7-unknown-linux-musleabihf` * `armv7-unknown-linux-ohos` diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md new file mode 100644 index 000000000000..c2fe63a49087 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md @@ -0,0 +1,51 @@ +# `armv7-unknown-linux-gnueabi` and `armv7-unknown-linux-gnueabihf` + +* **Tier: 2 (with Host Tools)** for `armv7-unknown-linux-gnueabihf` +* **Tier: 2** for `armv7-unknown-linux-gnueabi` + +Target for 32-bit little endian ARMv7-A Linux 3.2+ programs using glibc 2.17+. + +## Target maintainers + +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com + +## Requirements + +Building the targets themselves requires a 32-bit little endian ARMv7-A compiler that is supported +by `cc-rs`. + +## Building the target + +These targets can be built by enabling it for a `rustc` build: + +```toml +[build] +target = ["armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabi"] +``` + +If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.aarch64-unknown-linux-musl] +cc = "arm-linux-gnu-gcc" +cxx = "arm-linux-gnu-g++" +ar = "arm-linux-gnu-ar" +linker = "arm-linux-gnu-gcc" +``` + +## Building Rust programs + +These targets is distributed through `rustup`, and otherwise requires no special configuration. + +## Cross-compilation + +These targets can be cross-compiled from any host. + +## Testing + +These targets can be tested as normal with `x.py` on a 32-bit little endian ARMv7-A host or via +QEMU emulation. diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index 3dadda86a5f5..22278a0a7dc7 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -19,9 +19,12 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team] +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index c1252b4a4bf5..9429eb6ab8ae 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -15,10 +15,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[@chrisnc](https://github.com/chrisnc) -[Rust Embedded Devices Working Group Arm Team] +- [@chrisnc](https://github.com/chrisnc) +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 0d5a36c3ee2d..e465eb79f49d 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -17,10 +17,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[@chrisnc](https://github.com/chrisnc) -[Rust Embedded Devices Working Group Arm Team] +- [@chrisnc](https://github.com/chrisnc) +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index 98dcf9bd3968..192e013d3a43 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -22,7 +22,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md index d8f3970c8bfa..b04cb7bfacfa 100644 --- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv7-M]. ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md index b16d450275df..104520854b49 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv8-M] Baseline. ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index a2d515d07ea0..5cc535ce376b 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -26,7 +26,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index 9587590d12d1..e8989616b844 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -13,8 +13,12 @@ Available targets: ## Target maintainers -[@dvdhrm](https://github.com/dvdhrm) -[@nicholasbishop](https://github.com/nicholasbishop) +- [@dvdhrm](https://github.com/dvdhrm) +- [@nicholasbishop](https://github.com/nicholasbishop) +- (for `aarch64-unknown-uefi` only) [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements From c61ec946d24c559708d4d57fbe860817e854c610 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 22 Apr 2025 14:39:59 +0200 Subject: [PATCH 483/537] implement range support in `//@ edition` --- src/tools/compiletest/src/common.rs | 6 +- src/tools/compiletest/src/directives.rs | 97 +++++++++++- src/tools/compiletest/src/directives/tests.rs | 142 +++++++++++++++++- src/tools/compiletest/src/edition.rs | 35 +++++ src/tools/compiletest/src/lib.rs | 4 +- 5 files changed, 270 insertions(+), 14 deletions(-) create mode 100644 src/tools/compiletest/src/edition.rs diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6d9599489180..65db816ad1a8 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -7,6 +7,7 @@ use build_helper::git::GitConfig; use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; +use crate::edition::Edition; use crate::executor::ColorConfig; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -612,10 +613,7 @@ pub struct Config { pub git_hash: bool, /// The default Rust edition. - /// - /// FIXME: perform stronger validation for this. There are editions that *definitely* exists, - /// but there might also be "future" edition. - pub edition: Option, + pub edition: Option, // Configuration for various run-make tests frobbing things like C compilers or querying about // various LLVM component information. diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 0d85e76c2cc0..a79978d036ce 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -16,10 +16,11 @@ use crate::directives::directive_names::{ KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES, }; use crate::directives::needs::CachedNeedsConditions; +use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; -use crate::help; use crate::util::static_regex; +use crate::{fatal, help}; pub(crate) mod auxiliary; mod cfg; @@ -437,10 +438,13 @@ impl TestProps { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } - if let Some(edition) = config.parse_edition(ln, testfile) { + if let Some(range) = parse_edition_range(config, ln, testfile) { // The edition is added at the start, since flags from //@compile-flags must // be passed to rustc last. - self.compile_flags.insert(0, format!("--edition={}", edition.trim())); + self.compile_flags.insert( + 0, + format!("--edition={}", range.edition_to_test(config.edition)), + ); has_edition = true; } @@ -1124,10 +1128,6 @@ impl Config { } } - fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option { - self.parse_name_value_directive(line, "edition", testfile) - } - fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) { // If the flag is already true, don't bother looking at the directive. *value = *value || self.parse_name_directive(line, directive); @@ -1769,3 +1769,86 @@ enum IgnoreDecision { Continue, Error { message: String }, } + +fn parse_edition_range( + config: &Config, + line: &DirectiveLine<'_>, + testfile: &Utf8Path, +) -> Option { + let raw = config.parse_name_value_directive(line, "edition", testfile)?; + let line_number = line.line_number; + + // Edition range is half-open: `[lower_bound, upper_bound)` + if let Some((lower_bound, upper_bound)) = raw.split_once("..") { + Some(match (maybe_parse_edition(lower_bound), maybe_parse_edition(upper_bound)) { + (Some(lower_bound), Some(upper_bound)) if upper_bound <= lower_bound => { + fatal!( + "{testfile}:{line_number}: the left side of `//@ edition` cannot be greater than or equal to the right side" + ); + } + (Some(lower_bound), Some(upper_bound)) => { + EditionRange::Range { lower_bound, upper_bound } + } + (Some(lower_bound), None) => EditionRange::RangeFrom(lower_bound), + (None, Some(_)) => { + fatal!( + "{testfile}:{line_number}: `..edition` is not a supported range in `//@ edition`" + ); + } + (None, None) => { + fatal!("{testfile}:{line_number}: `..` is not a supported range in `//@ edition`"); + } + }) + } else { + match maybe_parse_edition(&raw) { + Some(edition) => Some(EditionRange::Exact(edition)), + None => { + fatal!("{testfile}:{line_number}: empty value for `//@ edition`"); + } + } + } +} + +fn maybe_parse_edition(mut input: &str) -> Option { + input = input.trim(); + if input.is_empty() { + return None; + } + Some(parse_edition(input)) +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum EditionRange { + Exact(Edition), + RangeFrom(Edition), + /// Half-open range: `[lower_bound, upper_bound)` + Range { + lower_bound: Edition, + upper_bound: Edition, + }, +} + +impl EditionRange { + fn edition_to_test(&self, requested: impl Into>) -> Edition { + let min_edition = Edition::Year(2015); + let requested = requested.into().unwrap_or(min_edition); + + match *self { + EditionRange::Exact(exact) => exact, + EditionRange::RangeFrom(lower_bound) => { + if requested >= lower_bound { + requested + } else { + lower_bound + } + } + EditionRange::Range { lower_bound, upper_bound } => { + if requested >= lower_bound && requested < upper_bound { + requested + } else { + lower_bound + } + } + } + } +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 16cf76be9a53..93621192d4bd 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -4,10 +4,11 @@ use camino::Utf8Path; use semver::Version; use super::{ - DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives, - parse_normalize_rule, + DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version, + extract_version_range, iter_directives, parse_normalize_rule, }; use crate::common::{Config, Debugger, TestMode}; +use crate::directives::parse_edition; use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description( @@ -73,6 +74,7 @@ fn test_parse_normalize_rule() { struct ConfigBuilder { mode: Option, channel: Option, + edition: Option, host: Option, target: Option, stage: Option, @@ -96,6 +98,11 @@ impl ConfigBuilder { self } + fn edition(&mut self, e: Edition) -> &mut Self { + self.edition = Some(e); + self + } + fn host(&mut self, s: &str) -> &mut Self { self.host = Some(s.to_owned()); self @@ -183,6 +190,10 @@ impl ConfigBuilder { ]; let mut args: Vec = args.iter().map(ToString::to_string).collect(); + if let Some(edition) = &self.edition { + args.push(format!("--edition={edition}")); + } + if let Some(ref llvm_version) = self.llvm_version { args.push("--llvm-version".to_owned()); args.push(llvm_version.clone()); @@ -941,3 +952,130 @@ fn test_needs_target_std() { let config = cfg().target("x86_64-unknown-linux-gnu").build(); assert!(!check_ignore(&config, "//@ needs-target-std")); } + +fn parse_edition_range(line: &str) -> Option { + let config = cfg().build(); + let line = super::DirectiveLine { line_number: 0, revision: None, raw_directive: line }; + + super::parse_edition_range(&config, &line, "tmp.rs".into()) +} + +#[test] +fn test_parse_edition_range() { + assert_eq!(None, parse_edition_range("hello-world")); + assert_eq!(None, parse_edition_range("edition")); + + assert_eq!(Some(EditionRange::Exact(2018.into())), parse_edition_range("edition: 2018")); + assert_eq!(Some(EditionRange::Exact(2021.into())), parse_edition_range("edition:2021")); + assert_eq!(Some(EditionRange::Exact(2024.into())), parse_edition_range("edition: 2024 ")); + assert_eq!(Some(EditionRange::Exact(Edition::Future)), parse_edition_range("edition: future")); + + assert_eq!(Some(EditionRange::RangeFrom(2018.into())), parse_edition_range("edition: 2018..")); + assert_eq!(Some(EditionRange::RangeFrom(2021.into())), parse_edition_range("edition:2021 ..")); + assert_eq!( + Some(EditionRange::RangeFrom(2024.into())), + parse_edition_range("edition: 2024 .. ") + ); + assert_eq!( + Some(EditionRange::RangeFrom(Edition::Future)), + parse_edition_range("edition: future.. ") + ); + + assert_eq!( + Some(EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }), + parse_edition_range("edition: 2018..2024") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2015.into(), upper_bound: 2021.into() }), + parse_edition_range("edition:2015 .. 2021 ") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: 2027.into() }), + parse_edition_range("edition: 2021 .. 2027 ") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: Edition::Future }), + parse_edition_range("edition: 2021..future") + ); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_empty() { + parse_edition_range("edition:"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_invalid_edition() { + parse_edition_range("edition: hello"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_double_dots() { + parse_edition_range("edition: .."); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_inverted_range() { + parse_edition_range("edition: 2021..2015"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_inverted_range_future() { + parse_edition_range("edition: future..2015"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_empty_range() { + parse_edition_range("edition: 2021..2021"); +} + +#[track_caller] +fn assert_edition_to_test( + expected: impl Into, + range: EditionRange, + default: Option, +) { + let mut cfg = cfg(); + if let Some(default) = default { + cfg.edition(default); + } + assert_eq!(expected.into(), range.edition_to_test(cfg.build().edition)); +} + +#[test] +fn test_edition_range_edition_to_test() { + let e2015 = parse_edition("2015"); + let e2018 = parse_edition("2018"); + let e2021 = parse_edition("2021"); + let e2024 = parse_edition("2024"); + let efuture = parse_edition("future"); + + let exact = EditionRange::Exact(2021.into()); + assert_edition_to_test(2021, exact, None); + assert_edition_to_test(2021, exact, Some(e2018)); + assert_edition_to_test(2021, exact, Some(efuture)); + + assert_edition_to_test(Edition::Future, EditionRange::Exact(Edition::Future), None); + + let greater_equal_than = EditionRange::RangeFrom(2021.into()); + assert_edition_to_test(2021, greater_equal_than, None); + assert_edition_to_test(2021, greater_equal_than, Some(e2015)); + assert_edition_to_test(2021, greater_equal_than, Some(e2018)); + assert_edition_to_test(2021, greater_equal_than, Some(e2021)); + assert_edition_to_test(2024, greater_equal_than, Some(e2024)); + assert_edition_to_test(Edition::Future, greater_equal_than, Some(efuture)); + + let range = EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }; + assert_edition_to_test(2018, range, None); + assert_edition_to_test(2018, range, Some(e2015)); + assert_edition_to_test(2018, range, Some(e2018)); + assert_edition_to_test(2021, range, Some(e2021)); + assert_edition_to_test(2018, range, Some(e2024)); + assert_edition_to_test(2018, range, Some(efuture)); +} diff --git a/src/tools/compiletest/src/edition.rs b/src/tools/compiletest/src/edition.rs new file mode 100644 index 000000000000..36550cf5b2b9 --- /dev/null +++ b/src/tools/compiletest/src/edition.rs @@ -0,0 +1,35 @@ +use crate::fatal; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Edition { + // Note that the ordering here is load-bearing, as we want the future edition to be greater than + // any year-based edition. + Year(u32), + Future, +} + +impl std::fmt::Display for Edition { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Edition::Year(year) => write!(f, "{year}"), + Edition::Future => f.write_str("future"), + } + } +} + +impl From for Edition { + fn from(value: u32) -> Self { + Edition::Year(value) + } +} + +pub fn parse_edition(mut input: &str) -> Edition { + input = input.trim(); + if input == "future" { + Edition::Future + } else { + Edition::Year(input.parse().unwrap_or_else(|_| { + fatal!("`{input}` doesn't look like an edition"); + })) + } +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 15e31dadf971..2d759279f34b 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -7,6 +7,7 @@ pub mod common; mod debuggers; pub mod diagnostics; pub mod directives; +pub mod edition; pub mod errors; mod executor; mod json; @@ -39,6 +40,7 @@ use crate::common::{ expected_output_path, output_base_dir, output_relative_path, }; use crate::directives::DirectivesCache; +use crate::edition::parse_edition; use crate::executor::{CollectedTest, ColorConfig}; /// Creates the `Config` instance for this invocation of compiletest. @@ -449,7 +451,7 @@ pub fn parse_config(args: Vec) -> Config { has_enzyme, channel: matches.opt_str("channel").unwrap(), git_hash: matches.opt_present("git-hash"), - edition: matches.opt_str("edition"), + edition: matches.opt_str("edition").as_deref().map(parse_edition), cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), From 6631c8ef5569920daba2e4ac46ac783b3a7c9c47 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 21 Sep 2025 16:56:04 -0500 Subject: [PATCH 484/537] Document range syntax on the rustc dev guide --- src/doc/rustc-dev-guide/src/tests/directives.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4be78fac4ec7..3b6c89174645 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -262,6 +262,20 @@ Consider writing the test as a proper incremental test instead. +#### The edition directive + +The `//@ edition` directive can take an exact edition, a bounded half-open range of editions or a left-bounded half-open range of editions, this affects which edition is used by `./x test` to run the test. For example: + +- A test with the `//@ edition: 2018` directive will only run under the 2018 edition. +- A test with the `//@ edition: 2015..2021` directive can be run under both the 2015 and 2018 editions. However, CI will only run the test with the lowest edition possible (2015 in this case). +- A test with the `//@ edition: 2018..` directive will run under any edition greater or equal than 2018. However, CI will only run the test with the lowest edition possible (2018 in this case). + +You can also force `./x test` to use a specific edition by passing the `-- --edition=` argument. However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`: + +- A test with the `//@ edition: 2018` will run with the 2018 edition. +- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. +- A test with the `//@ edition: 2018..` will run with the 2018 edition. + ### Rustdoc | Directive | Explanation | Supported test suites | Possible values | From fe66eaa67acc47525db6f13cf97d54780d87b805 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 7 Jul 2025 22:36:23 +0200 Subject: [PATCH 485/537] Fix backtraces with `-C panic=abort` on linux; emit unwind tables by default The linux backtrace unwinder relies on unwind tables to work properly, and generating and printing a backtrace is done by for example the default panic hook. Begin emitting unwind tables by default again with `-C panic=abort` (see history below) so that backtraces work. History ======= Backtraces with `-C panic=abort` used to work in Rust 1.22 but broke in Rust 1.23, because in 1.23 we stopped emitting unwind tables with `-C panic=abort` (see 24cc38e3b00). In 1.45 (see cda994633ee) a workaround in the form of `-C force-unwind-tables=yes` was added. `-C panic=abort` was added in [Rust 1.10](https://blog.rust-lang.org/2016/07/07/Rust-1.10/#what-s-in-1-10-stable) and the motivation was binary size and compile time. But given how confusing that behavior has turned out to be, it is better to make binary size optimization opt-in with `-C force-unwind-tables=no` rather than default since the current default breaks backtraces. Besides, if binary size is a primary concern, there are many other tricks that can be used that has a higher impact. --- compiler/rustc_session/src/session.rs | 3 +- .../rustc_target/src/spec/base/android.rs | 4 -- compiler/rustc_target/src/spec/base/linux.rs | 3 + .../targets/arm_unknown_linux_gnueabihf.rs | 5 ++ tests/run-make/panic-abort-eh_frame/rmake.rs | 11 ++-- ...panic-abort-backtrace-without-debuginfo.rs | 57 +++++++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 25b46241c52d..172672a80fbd 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -758,7 +758,8 @@ impl Session { // ELF x86-64 abi, but it can be disabled for some compilation units. // // Typically when we're compiling with `-C panic=abort` we don't need - // `uwtable` because we can't generate any exceptions! + // `uwtable` because we can't generate any exceptions! But note that + // some targets require unwind tables to generate backtraces. // Unwind tables are needed when compiling with `-C panic=unwind`, but // LLVM won't omit unwind tables unless the function is also marked as // `nounwind`, so users are allowed to disable `uwtable` emission. diff --git a/compiler/rustc_target/src/spec/base/android.rs b/compiler/rustc_target/src/spec/base/android.rs index 0426ea44c6a2..df2757aaabf6 100644 --- a/compiler/rustc_target/src/spec/base/android.rs +++ b/compiler/rustc_target/src/spec/base/android.rs @@ -8,10 +8,6 @@ pub(crate) fn opts() -> TargetOptions { base.tls_model = TlsModel::Emulated; base.has_thread_local = false; base.supported_sanitizers = SanitizerSet::ADDRESS; - // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867 - // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution - // was to always emit `uwtable`). - base.default_uwtable = true; base.crt_static_respected = true; base } diff --git a/compiler/rustc_target/src/spec/base/linux.rs b/compiler/rustc_target/src/spec/base/linux.rs index 9982c254eca5..26e4590cf5e6 100644 --- a/compiler/rustc_target/src/spec/base/linux.rs +++ b/compiler/rustc_target/src/spec/base/linux.rs @@ -12,6 +12,9 @@ pub(crate) fn opts() -> TargetOptions { relro_level: RelroLevel::Full, has_thread_local: true, crt_static_respected: true, + // We want backtraces to work by default and they rely on unwind tables + // (regardless of `-C panic` strategy). + default_uwtable: true, supported_split_debuginfo: Cow::Borrowed(&[ SplitDebuginfo::Packed, SplitDebuginfo::Unpacked, diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index a3f5389f0aa7..0c711d5e71ab 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -19,6 +19,11 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), + // The default on linux is to have `default_uwtable=true`, but on + // this target we get an "`__aeabi_unwind_cpp_pr0` not defined" + // linker error, so set it to `true` here. + // FIXME(#146996): Remove this override once #146996 has been fixed. + default_uwtable: false, ..base::linux_gnu::opts() }, } diff --git a/tests/run-make/panic-abort-eh_frame/rmake.rs b/tests/run-make/panic-abort-eh_frame/rmake.rs index 23d95dc57749..2eccde627955 100644 --- a/tests/run-make/panic-abort-eh_frame/rmake.rs +++ b/tests/run-make/panic-abort-eh_frame/rmake.rs @@ -1,9 +1,11 @@ // An `.eh_frame` section in an object file is a symptom of an UnwindAction::Terminate // being inserted, useful for determining whether or not unwinding is necessary. -// This is useless when panics would NEVER unwind due to -C panic=abort. This section should -// therefore never appear in the emit file of a -C panic=abort compilation, and this test -// checks that this is respected. -// See https://github.com/rust-lang/rust/pull/112403 +// This is useless when panics would NEVER unwind due to -C panic=abort and when we don't need +// being able to generate backtraces (which depend on unwind tables on linux). This section should +// therefore never appear in the emit file of a -C panic=abort compilation +// with -C force-unwind-tables=no, and this test checks that this is respected. +// See https://github.com/rust-lang/rust/pull/112403 and +// https://github.com/rust-lang/rust/pull/143613. //@ only-linux // FIXME(Oneirical): the DW_CFA symbol appears on Windows-gnu, because uwtable @@ -19,6 +21,7 @@ fn main() { .panic("abort") .edition("2021") .arg("-Zvalidate-mir") + .arg("-Cforce-unwind-tables=no") .run(); llvm_objdump().arg("--dwarf=frames").input("foo.o").run().assert_stdout_not_contains("DW_CFA"); } diff --git a/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs b/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs new file mode 100644 index 000000000000..a29afd68523b --- /dev/null +++ b/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs @@ -0,0 +1,57 @@ +//! Test that with `-C panic=abort` the backtrace is not cut off by default +//! (i.e. without using `-C force-unwind-tables=yes`) by ensuring that our own +//! functions are in the backtrace. If we just check one function it might be +//! the last function, so make sure the backtrace can continue by checking for +//! two functions. Regression test for +//! . + +//@ run-pass +//@ needs-subprocess +// We want to test if unwind tables are emitted by default. We must make sure +// to disable debuginfo to test that, because enabling debuginfo also means that +// unwind tables are emitted, which prevents us from testing what we want. +// We also need to set opt-level=0 to avoid optimizing away our functions. +//@ compile-flags: -C panic=abort -C opt-level=0 -C debuginfo=0 +//@ no-prefer-dynamic +//@ ignore-apple +//@ ignore-arm-unknown-linux-gnueabihf FIXME(#146996) Try removing this once #146996 has been fixed. +//@ ignore-msvc Backtraces on Windows requires debuginfo which we can't use here + +static FN_1: &str = "this_function_must_be_in_the_backtrace"; +fn this_function_must_be_in_the_backtrace() { + and_this_function_too(); +} + +static FN_2: &str = "and_this_function_too"; +fn and_this_function_too() { + panic!("generate panic backtrace"); +} + +fn run_test() { + let output = std::process::Command::new(std::env::current_exe().unwrap()) + .arg("whatever") + .env("RUST_BACKTRACE", "full") + .output() + .unwrap(); + let backtrace = std::str::from_utf8(&output.stderr).unwrap(); + + fn assert(function_name: &str, backtrace: &str) { + assert!( + backtrace.contains(function_name), + "ERROR: no `{}` in stderr! actual stderr: {}", + function_name, + backtrace + ); + } + assert(FN_1, backtrace); + assert(FN_2, backtrace); +} + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() == 1 { + run_test(); + } else { + this_function_must_be_in_the_backtrace(); + } +} From 5a8f963426c72c5bd306b2620a6c148b720217d0 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Thu, 2 Oct 2025 20:13:18 +0200 Subject: [PATCH 486/537] fix wording; we're replacing coma with a bar --- ...ixed => only-replace-intended-coma-not-all-in-pattern.fixed} | 2 +- ...tern.rs => only-replace-intended-coma-not-all-in-pattern.rs} | 2 +- ...err => only-replace-intended-coma-not-all-in-pattern.stderr} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/ui/suggestions/{only-replace-intended-bar-not-all-in-pattern.fixed => only-replace-intended-coma-not-all-in-pattern.fixed} (84%) rename tests/ui/suggestions/{only-replace-intended-bar-not-all-in-pattern.rs => only-replace-intended-coma-not-all-in-pattern.rs} (84%) rename tests/ui/suggestions/{only-replace-intended-bar-not-all-in-pattern.stderr => only-replace-intended-coma-not-all-in-pattern.stderr} (89%) diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed similarity index 84% rename from tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed rename to tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed index 5abc1edd381b..0258f868f007 100644 --- a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.fixed +++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed @@ -1,7 +1,7 @@ //@ run-rustfix // Regression test for issue #143330. -// Ensure we suggest to replace only the intended bar with a comma, not all bars in the pattern. +// Ensure we suggest to replace only the intended coma with a bar, not all commas in the pattern. fn main() { struct Foo { x: i32, ch: char } diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs similarity index 84% rename from tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs rename to tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs index 5bd267c3bc40..7d5087fa0ffa 100644 --- a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.rs +++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs @@ -1,7 +1,7 @@ //@ run-rustfix // Regression test for issue #143330. -// Ensure we suggest to replace only the intended bar with a comma, not all bars in the pattern. +// Ensure we suggest to replace only the intended coma with a bar, not all commas in the pattern. fn main() { struct Foo { x: i32, ch: char } diff --git a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr similarity index 89% rename from tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr rename to tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr index db0bb8c50e86..050f1b8a2b33 100644 --- a/tests/ui/suggestions/only-replace-intended-bar-not-all-in-pattern.stderr +++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr @@ -1,5 +1,5 @@ error: unexpected `,` in pattern - --> $DIR/only-replace-intended-bar-not-all-in-pattern.rs:12:30 + --> $DIR/only-replace-intended-coma-not-all-in-pattern.rs:12:30 | LL | Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (), | ^ From d1d7b9472a18780499162b4a91beea729bc2c13b Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Thu, 2 Oct 2025 20:24:34 +0200 Subject: [PATCH 487/537] bring back plural 'alternatives' in suggestion message --- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- .../issue-48492-tuple-destructure-missing-parens.stderr | 2 +- tests/ui/feature-gates/feature-gate-never_patterns.stderr | 2 +- tests/ui/parser/match-arm-without-body.stderr | 4 ++-- .../only-replace-intended-coma-not-all-in-pattern.stderr | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5d6da6093120..1cb1618e5844 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2961,7 +2961,7 @@ impl<'a> Parser<'a> { if let CommaRecoveryMode::EitherTupleOrPipe = rt { err.span_suggestion( comma_span, - "...or a vertical bar to match on alternative", + "...or a vertical bar to match on alternatives", " |", Applicability::MachineApplicable, ); diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index dc875ad27ea6..286d60213966 100644 --- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -32,7 +32,7 @@ help: try adding parentheses to match on a tuple... | LL | (Nucleotide::Adenine, Nucleotide::Cytosine, _) => true | + + -help: ...or a vertical bar to match on alternative +help: ...or a vertical bar to match on alternatives | LL - Nucleotide::Adenine, Nucleotide::Cytosine, _ => true LL + Nucleotide::Adenine | Nucleotide::Cytosine, _ => true diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr index 5e810249b906..e655209924a0 100644 --- a/tests/ui/feature-gates/feature-gate-never_patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr @@ -8,7 +8,7 @@ help: try adding parentheses to match on a tuple... | LL | (Some(_),) | + + -help: ...or a vertical bar to match on alternative +help: ...or a vertical bar to match on alternatives | LL - Some(_), LL + Some(_) | diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr index 85ff7db8d4aa..59a323f2cc1c 100644 --- a/tests/ui/parser/match-arm-without-body.stderr +++ b/tests/ui/parser/match-arm-without-body.stderr @@ -16,7 +16,7 @@ help: try adding parentheses to match on a tuple... | LL | (Some(_),) | + + -help: ...or a vertical bar to match on alternative +help: ...or a vertical bar to match on alternatives | LL - Some(_), LL + Some(_) | @@ -36,7 +36,7 @@ LL | LL | LL ~ _) => {} | -help: ...or a vertical bar to match on alternative +help: ...or a vertical bar to match on alternatives | LL - Some(_), LL + Some(_) | diff --git a/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr index 050f1b8a2b33..ee75e2db1334 100644 --- a/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr +++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr @@ -8,7 +8,7 @@ help: try adding parentheses to match on a tuple... | LL | (Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' }) => (), | + + -help: ...or a vertical bar to match on alternative +help: ...or a vertical bar to match on alternatives | LL - Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (), LL + Foo { x: 2, ch: ',' } | Foo { x: 3, ch: '@' } => (), From fab9906c21e8c751943760d44c4a12cac2bceb05 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 2 Oct 2025 22:15:37 +0900 Subject: [PATCH 488/537] test: Add regression test for ICE when projecting associated types through dyn traits --- .../projection-dyn-associated-type.rs | 28 ++++++++++ .../projection-dyn-associated-type.stderr | 52 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/ui/associated-types/projection-dyn-associated-type.rs create mode 100644 tests/ui/associated-types/projection-dyn-associated-type.stderr diff --git a/tests/ui/associated-types/projection-dyn-associated-type.rs b/tests/ui/associated-types/projection-dyn-associated-type.rs new file mode 100644 index 000000000000..3b981e7987e0 --- /dev/null +++ b/tests/ui/associated-types/projection-dyn-associated-type.rs @@ -0,0 +1,28 @@ +// Regression test for the projection bug in +// +//@ compile-flags: -Zincremental-verify-ich=yes +//@ incremental + +pub trait A {} +pub trait B: A {} + +pub trait Mirror { + type Assoc: ?Sized; +} + +impl Mirror for A { + //~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207] + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + type Assoc = T; +} + +pub fn foo<'a>( + x: &'a ::Assoc +) -> &'a ::Assoc { + //~^ ERROR the trait bound `(dyn B + 'static): Mirror` is not satisfied [E0277] + //~| ERROR the trait bound `(dyn B + 'static): Mirror` is not satisfied [E0277] + static +} //~ ERROR expected identifier, found `}` + +pub fn main() {} diff --git a/tests/ui/associated-types/projection-dyn-associated-type.stderr b/tests/ui/associated-types/projection-dyn-associated-type.stderr new file mode 100644 index 000000000000..1ac2beb0414e --- /dev/null +++ b/tests/ui/associated-types/projection-dyn-associated-type.stderr @@ -0,0 +1,52 @@ +error: expected identifier, found `}` + --> $DIR/projection-dyn-associated-type.rs:26:1 + | +LL | } + | ^ expected identifier + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/projection-dyn-associated-type.rs:13:28 + | +LL | impl Mirror for A { + | ^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl Mirror for dyn A { + | +++ +help: alternatively use a blanket implementation to implement `Mirror` for all types that also implement `A` + | +LL - impl Mirror for A { +LL + impl Mirror for U { + | + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/projection-dyn-associated-type.rs:13:6 + | +LL | impl Mirror for A { + | ^ unconstrained type parameter + +error[E0277]: the trait bound `(dyn B + 'static): Mirror` is not satisfied + --> $DIR/projection-dyn-associated-type.rs:22:6 + | +LL | ) -> &'a ::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Mirror` is not implemented for `(dyn B + 'static)` + | + = help: the trait `Mirror` is implemented for `dyn A` + +error[E0277]: the trait bound `(dyn B + 'static): Mirror` is not satisfied + --> $DIR/projection-dyn-associated-type.rs:22:6 + | +LL | ) -> &'a ::Assoc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Mirror` is not implemented for `(dyn B + 'static)` + | + = help: the trait `Mirror` is implemented for `dyn A` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0277. +For more information about an error, try `rustc --explain E0207`. From c407d340de1717a88537725c899c153c6fdda051 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 26 Aug 2025 13:41:33 -0500 Subject: [PATCH 489/537] if a trait item is shown in search results, hide the impl item for example, if we're showing `Iterator::next`, we don't need to also show `Range::next` in the results. Co-authored-by: Michael Howell --- src/librustdoc/formats/cache.rs | 31 ++++--- src/librustdoc/html/render/mod.rs | 2 + src/librustdoc/html/render/search_index.rs | 78 ++++++++++------ src/librustdoc/html/static/js/rustdoc.d.ts | 22 ++++- src/librustdoc/html/static/js/search.js | 102 +++++++++++++++++---- 5 files changed, 174 insertions(+), 61 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 29b4c4caaf86..75c848742ea5 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -148,6 +148,14 @@ impl Cache { Cache { document_private, document_hidden, ..Cache::default() } } + fn parent_stack_last_impl_and_trait_id(&self) -> (Option, Option) { + if let Some(ParentStackItem::Impl { item_id, trait_, .. }) = self.parent_stack.last() { + (item_id.as_def_id(), trait_.as_ref().map(|tr| tr.def_id())) + } else { + (None, None) + } + } + /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was /// in `krate` due to the data being moved into the `Cache`. pub(crate) fn populate(cx: &mut DocContext<'_>, mut krate: clean::Crate) -> clean::Crate { @@ -574,11 +582,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id), _ => item_def_id, }; - let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - item_id.as_def_id() - } else { - None - }; + let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id(); let search_type = get_function_type_for_search( item, tcx, @@ -596,12 +600,15 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It desc, parent: parent_did, parent_idx: None, + trait_parent, + trait_parent_idx: None, exact_module_path: None, impl_id, search_type, aliases, deprecation, }; + cache.search_index.push(index_item); } @@ -610,19 +617,21 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It /// See [`Cache::orphan_impl_items`]. fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) { let impl_generics = clean_impl_generics(cache.parent_stack.last()); - let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - item_id.as_def_id() - } else { - None + let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id(); + let orphan_item = OrphanImplItem { + parent: parent_did, + trait_parent, + item: item.clone(), + impl_generics, + impl_id, }; - let orphan_item = - OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; cache.orphan_impl_items.push(orphan_item); } pub(crate) struct OrphanImplItem { pub(crate) parent: DefId, pub(crate) impl_id: Option, + pub(crate) trait_parent: Option, pub(crate) item: clean::Item, pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>, } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6d684449b6d2..88184c9611ff 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -134,6 +134,8 @@ pub(crate) struct IndexItem { pub(crate) desc: String, pub(crate) parent: Option, pub(crate) parent_idx: Option, + pub(crate) trait_parent: Option, + pub(crate) trait_parent_idx: Option, pub(crate) exact_module_path: Option>, pub(crate) impl_id: Option, pub(crate) search_type: Option, diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 2984f3ab50ee..81b38d157a86 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -580,6 +580,7 @@ impl SerializedSearchIndex { module_path, exact_module_path, parent, + trait_parent, deprecated, associated_item_disambiguator, }| EntryData { @@ -589,6 +590,7 @@ impl SerializedSearchIndex { exact_module_path: exact_module_path .and_then(|path_id| map.get(&path_id).copied()), parent: parent.and_then(|path_id| map.get(&path_id).copied()), + trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()), deprecated: *deprecated, associated_item_disambiguator: associated_item_disambiguator.clone(), }, @@ -870,6 +872,7 @@ struct EntryData { module_path: Option, exact_module_path: Option, parent: Option, + trait_parent: Option, deprecated: bool, associated_item_disambiguator: Option, } @@ -885,6 +888,7 @@ impl Serialize for EntryData { seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?; + seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&if self.deprecated { 1 } else { 0 })?; if let Some(disambig) = &self.associated_item_disambiguator { seq.serialize_element(&disambig)?; @@ -916,6 +920,9 @@ impl<'de> Deserialize<'de> for EntryData { .ok_or_else(|| A::Error::missing_field("exact_module_path"))?; let parent: SerializedOptional32 = v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?; + let trait_parent: SerializedOptional32 = + v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?; + let deprecated: u32 = v.next_element()?.unwrap_or(0); let associated_item_disambiguator: Option = v.next_element()?; Ok(EntryData { @@ -925,6 +932,7 @@ impl<'de> Deserialize<'de> for EntryData { exact_module_path: Option::::from(exact_module_path) .map(|path| path as usize), parent: Option::::from(parent).map(|path| path as usize), + trait_parent: Option::::from(trait_parent).map(|path| path as usize), deprecated: deprecated != 0, associated_item_disambiguator, }) @@ -1275,7 +1283,8 @@ pub(crate) fn build_index( // Attach all orphan items to the type's definition if the type // has since been learned. - for &OrphanImplItem { impl_id, parent, ref item, ref impl_generics } in &cache.orphan_impl_items + for &OrphanImplItem { impl_id, parent, trait_parent, ref item, ref impl_generics } in + &cache.orphan_impl_items { if let Some((fqp, _)) = cache.paths.get(&parent) { let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); @@ -1287,6 +1296,8 @@ pub(crate) fn build_index( desc, parent: Some(parent), parent_idx: None, + trait_parent, + trait_parent_idx: None, exact_module_path: None, impl_id, search_type: get_function_type_for_search( @@ -1391,6 +1402,7 @@ pub(crate) fn build_index( module_path: None, exact_module_path: None, parent: None, + trait_parent: None, deprecated: false, associated_item_disambiguator: None, }), @@ -1404,39 +1416,46 @@ pub(crate) fn build_index( } }; - // First, populate associated item parents + // First, populate associated item parents and trait parents let crate_items: Vec<&mut IndexItem> = search_index .iter_mut() .map(|item| { - item.parent_idx = item.parent.and_then(|defid| { - cache.paths.get(&defid).map(|&(ref fqp, ty)| { - let pathid = serialized_index.names.len(); - match serialized_index.crate_paths_index.entry((ty, fqp.clone())) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - entry.insert(pathid); - let (name, path) = fqp.split_last().unwrap(); - serialized_index.push_path( - name.as_str().to_string(), - PathData { - ty, - module_path: path.to_vec(), - exact_module_path: if let Some(exact_path) = - cache.exact_paths.get(&defid) - && let Some((name2, exact_path)) = exact_path.split_last() - && name == name2 - { - Some(exact_path.to_vec()) - } else { - None + let mut defid_to_rowid = |defid, check_external: bool| { + cache + .paths + .get(&defid) + .or_else(|| check_external.then(|| cache.external_paths.get(&defid)).flatten()) + .map(|&(ref fqp, ty)| { + let pathid = serialized_index.names.len(); + match serialized_index.crate_paths_index.entry((ty, fqp.clone())) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + entry.insert(pathid); + let (name, path) = fqp.split_last().unwrap(); + serialized_index.push_path( + name.as_str().to_string(), + PathData { + ty, + module_path: path.to_vec(), + exact_module_path: if let Some(exact_path) = + cache.exact_paths.get(&defid) + && let Some((name2, exact_path)) = + exact_path.split_last() + && name == name2 + { + Some(exact_path.to_vec()) + } else { + None + }, }, - }, - ); - usize::try_from(pathid).unwrap() + ); + usize::try_from(pathid).unwrap() + } } - } - }) - }); + }) + }; + item.parent_idx = item.parent.and_then(|p| defid_to_rowid(p, false)); + item.trait_parent_idx = item.trait_parent.and_then(|p| defid_to_rowid(p, true)); if let Some(defid) = item.defid && item.parent_idx.is_none() @@ -1519,6 +1538,7 @@ pub(crate) fn build_index( Some(EntryData { ty: item.ty, parent: item.parent_idx, + trait_parent: item.trait_parent_idx, module_path, exact_module_path, deprecated: item.deprecation.is_some(), diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 951eb2291b89..e206d6633e63 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -241,6 +241,7 @@ declare namespace rustdoc { modulePath: number?, exactModulePath: number?, parent: number?, + traitParent: number?, deprecated: boolean, associatedItemDisambiguator: string?, } @@ -291,9 +292,12 @@ declare namespace rustdoc { path: PathData?, functionData: FunctionData?, deprecated: boolean, - parent: { path: PathData, name: string}?, + parent: RowParent, + traitParent: RowParent, } + type RowParent = { path: PathData, name: string } | null; + type ItemType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26; @@ -316,7 +320,23 @@ declare namespace rustdoc { interface ResultObject { desc: Promise, displayPath: string, + /** + * path to where the item was defined (not inlined), + * then `|`, then the `ItemType` of the item. + * + * This is often a private path, so it should not be displayed, + * but this allows us to use it to reliably deduplicate reexported and inlined items + */ fullPath: string, + /** + * The `fullPath` of the corresponding item within a trait. + * For example, for `File::read`, this would be `std::io::Read::read|12` + * + * This is used to hide items from trait impls when the trait itself is in the search results. + * + * `null` if the item is not from a trait impl block. + */ + traitPath: string | null, href: string, id: number, dist: number, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 482134933a61..71bad967026e 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1598,6 +1598,7 @@ class DocSearch { * module_path, * exact_module_path, * parent, + * trait_parent, * deprecated, * associated_item_disambiguator * @type {rustdoc.ArrayWithOptionals<[ @@ -1607,6 +1608,7 @@ class DocSearch { * number, * number, * number, + * number, * ], [string]>} */ const raw = JSON.parse(encoded); @@ -1616,8 +1618,9 @@ class DocSearch { modulePath: raw[2] === 0 ? null : raw[2] - 1, exactModulePath: raw[3] === 0 ? null : raw[3] - 1, parent: raw[4] === 0 ? null : raw[4] - 1, - deprecated: raw[5] === 1 ? true : false, - associatedItemDisambiguator: raw.length === 6 ? null : raw[6], + traitParent: raw[5] === 0 ? null : raw[5] - 1, + deprecated: raw[6] === 1 ? true : false, + associatedItemDisambiguator: raw.length === 7 ? null : raw[7], }; } @@ -1853,14 +1856,25 @@ class DocSearch { if (!entry && !path) { return null; } + /** @type {function("parent" | "traitParent"): Promise} */ + const buildParentLike = async field => { + const [name, path] = entry !== null && entry[field] !== null ? + await Promise.all([this.getName(entry[field]), this.getPathData(entry[field])]) : + [null, null]; + if (name !== null && path !== null) { + return { name, path }; + } + return null; + }; + const [ moduleName, modulePathData, exactModuleName, exactModulePathData, - parentName, - parentPath, - crate, + parent, + traitParent, + crateOrNull, ] = await Promise.all([ entry && entry.modulePath !== null ? this.getName(entry.modulePath) : null, entry && entry.modulePath !== null ? this.getPathData(entry.modulePath) : null, @@ -1870,14 +1884,11 @@ class DocSearch { entry && entry.exactModulePath !== null ? this.getPathData(entry.exactModulePath) : null, - entry && entry.parent !== null ? - this.getName(entry.parent) : - null, - entry && entry.parent !== null ? - this.getPathData(entry.parent) : - null, - entry ? nonnull(await this.getName(entry.krate)) : "", + buildParentLike("parent"), + buildParentLike("traitParent"), + entry ? this.getName(entry.krate) : "", ]); + const crate = crateOrNull === null ? "" : crateOrNull; const name = name_ === null ? "" : name_; const normalizedName = (name.indexOf("_") === -1 ? name : @@ -1886,6 +1897,7 @@ class DocSearch { (modulePathData.modulePath === "" ? moduleName : `${modulePathData.modulePath}::${moduleName}`); + return { id, crate, @@ -1901,9 +1913,8 @@ class DocSearch { path, functionData, deprecated: entry ? entry.deprecated : false, - parent: parentName !== null && parentPath !== null ? - { name: parentName, path: parentPath } : - null, + parent, + traitParent, }; } @@ -2101,11 +2112,12 @@ class DocSearch { /** * @param {rustdoc.Row} item - * @returns {[string, string, string]} + * @returns {[string, string, string, string|null]} */ const buildHrefAndPath = item => { let displayPath; let href; + let traitPath = null; const type = itemTypes[item.ty]; const name = item.name; let path = item.modulePath; @@ -2163,7 +2175,11 @@ class DocSearch { href = this.rootPath + item.modulePath.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } - return [displayPath, href, `${exactPath}::${name}`]; + if (item.traitParent) { + const tparent = item.traitParent; + traitPath = `${tparent.path.exactModulePath}::${tparent.name}::${name}`; + } + return [displayPath, href, `${exactPath}::${name}`, traitPath]; }; /** @@ -2598,7 +2614,13 @@ class DocSearch { * @returns {rustdoc.ResultObject[]} */ const transformResults = (results, typeInfo, duplicates) => { - const out = []; + /** @type {rustdoc.ResultObject[]} */ + let out = []; + + // if we match a trait-associated item, we want to go back and + // remove all the items that are their equivalent but in an impl block. + /** @type {Map} */ + const traitImplIdxMap = new Map(); for (const result of results) { const item = result.item; @@ -2630,17 +2652,35 @@ class DocSearch { item, displayPath: pathSplitter(res[0]), fullPath: "", + traitPath: null, href: "", displayTypeSignature: null, }, result); + // unlike other items, methods have a different ty when they are + // in an impl block vs a trait. want to normalize this away. + let ty = obj.item.ty; + if (ty === TY_TYMETHOD) { + ty = TY_METHOD; + } // To be sure than it some items aren't considered as duplicate. - obj.fullPath = res[2] + "|" + obj.item.ty; + obj.fullPath = res[2] + "|" + ty; + if (res[3]) { + // "tymethod" is never used on impl blocks + // (this is the reason we need to normalize tymethod away). + obj.traitPath = res[3] + "|" + obj.item.ty; + } if (duplicates.has(obj.fullPath)) { continue; } + // If we're showing something like `Iterator::next`, + // we don't want to also show a bunch of `::next` + if (obj.traitPath && duplicates.has(obj.traitPath)) { + continue; + } + // Exports are specifically not shown if the items they point at // are already in the results. if (obj.item.ty === TY_IMPORT && duplicates.has(res[2])) { @@ -2661,14 +2701,36 @@ class DocSearch { ); } + // FIXME: if the trait item matches but is cut off due to MAX_RESULTS, + // this deduplication will not happen. obj.href = res[1]; + if (obj.traitPath) { + let list = traitImplIdxMap.get(obj.traitPath); + if (list === undefined) { + list = []; + } + list.push(out.length); + traitImplIdxMap.set(obj.traitPath, list); + } else { + // FIXME: this is `O(n*m)` because we're repeatedly + // shifting with Array.splice, but could be `O(n+m)` if + // we did the shifting manually in a more clever way. + const toRemoveList = traitImplIdxMap.get(obj.fullPath); + if (toRemoveList) { + // iterate in reverse order so we don't shift the indexes + for (let i = toRemoveList.length - 1; i >= 0; i--) { + const rmIdx = toRemoveList[i]; + out = out.splice(rmIdx, 1); + } + } + traitImplIdxMap.delete(obj.fullPath); + } out.push(obj); if (out.length >= MAX_RESULTS) { break; } } } - return out; }; From 2dd00d3391b82dd0928f50589eb37f6fbbe32980 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 2 Sep 2025 11:41:21 -0500 Subject: [PATCH 490/537] fix rustdoc tests broke by trait item filtering --- tests/rustdoc-gui/search-result-color.goml | 45 +++++++++++-------- tests/rustdoc-gui/search-tab.goml | 2 +- tests/rustdoc-gui/sidebar.goml | 2 + tests/rustdoc-js-std/asrawfd.js | 4 +- tests/rustdoc-js-std/quoted.js | 18 ++++---- .../{bufread-fill-buf.js => trait-unbox.js} | 6 +-- 6 files changed, 42 insertions(+), 35 deletions(-) rename tests/rustdoc-js-std/{bufread-fill-buf.js => trait-unbox.js} (58%) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index fe0f64010895..e5c11651bd27 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -5,7 +5,7 @@ include: "utils.goml" define-function: ( "check-search-color", [ - theme, count_color, desc_color, path_color, bottom_border_color, keyword_color, + theme, count_color, path_color, bottom_border_color, keyword_color, struct_color, associatedtype_color, tymethod_color, method_color, structfield_color, structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, attribute_color, grey @@ -21,10 +21,6 @@ define-function: ( {"color": |count_color|}, ALL, ) - assert-css: ( - "//*[@class='desc'][normalize-space()='Just a normal struct.']", - {"color": |desc_color|}, - ) assert-css: ( "//*[@class='result-name']//*[normalize-space()='test_docs::']", {"color": |path_color|}, @@ -97,16 +93,6 @@ define-function: ( ALL, ) - // Checking color and background on hover. - move-cursor-to: "//*[@class='desc'][normalize-space()='Just a normal struct.']" - assert-css: ( - "//*[@class='result-name']//*[normalize-space()='test_docs::']", - {"color": |hover_path_color|}, - ) - assert-css: ( - "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a", - {"color": |hover_path_color|, "background-color": |hover_background|}, - ) } ) @@ -157,7 +143,6 @@ show-text: true call-function: ("check-search-color", { "theme": "ayu", "count_color": "#888", - "desc_color": "#c5c5c5", "path_color": "#0096cf", "bottom_border_color": "#aaa3", "keyword_color": "#39afd7", @@ -179,7 +164,6 @@ call-function: ("check-search-color", { call-function: ("check-search-color", { "theme": "dark", "count_color": "#888", - "desc_color": "#ddd", "path_color": "#ddd", "bottom_border_color": "#aaa3", "keyword_color": "#d2991d", @@ -201,7 +185,6 @@ call-function: ("check-search-color", { call-function: ("check-search-color", { "theme": "light", "count_color": "#888", - "desc_color": "#000", "path_color": "#000", "bottom_border_color": "#aaa3", "keyword_color": "#3873ad", @@ -226,12 +209,27 @@ call-function: ("perform-search", {"query": "thisisanalias"}) define-function: ( "check-alias", - [theme, alias, grey], + [theme, alias, grey, desc_color, hover_path_color, hover_background], block { call-function: ("switch-theme", {"theme": |theme|}) // Checking that the colors for the alias element are the ones expected. assert-css: (".result-name .path .alias", {"color": |alias|}) assert-css: (".result-name .path .alias > .grey", {"color": |grey|}) + assert-css: ( + "//*[@class='desc'][normalize-space()='Just a normal enum.']", + {"color": |desc_color|}, + ) + // Checking color and background on hover. + move-cursor-to: "//*[@class='desc'][normalize-space()='Just a normal enum.']" + assert-css: ( + "//*[@class='result-name']//*[normalize-space()='test_docs::']", + {"color": |hover_path_color|}, + ) + assert-css: ( + "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a", + {"color": |hover_path_color|, "background-color": |hover_background|}, + ) + }, ) @@ -239,14 +237,23 @@ call-function: ("check-alias", { "theme": "ayu", "alias": "#c5c5c5", "grey": "#999", + "desc_color": "#c5c5c5", + "hover_path_color": "#fff", + "hover_background": "#3c3c3c", }) call-function: ("check-alias", { "theme": "dark", "alias": "#fff", "grey": "#ccc", + "desc_color": "#ddd", + "hover_path_color": "#ddd", + "hover_background": "#616161", }) call-function: ("check-alias", { "theme": "light", "alias": "#000", "grey": "#999", + "desc_color": "#000", + "hover_path_color": "#000", + "hover_background": "#ccc", }) diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml index 00ca952033dc..0a3cfc231e50 100644 --- a/tests/rustdoc-gui/search-tab.goml +++ b/tests/rustdoc-gui/search-tab.goml @@ -79,7 +79,7 @@ call-function: ("check-colors", { set-window-size: (851, 600) // Check the size and count in tabs -assert-text: ("#search-tabs > button:nth-child(1) > .count", " (27) ") +assert-text: ("#search-tabs > button:nth-child(1) > .count", " (25) ") assert-text: ("#search-tabs > button:nth-child(2) > .count", " (7)  ") assert-text: ("#search-tabs > button:nth-child(3) > .count", " (0)  ") store-property: ("#search-tabs > button:nth-child(1)", {"offsetWidth": buttonWidth}) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 5ec0008ad8af..0d371c8c6a46 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -1,5 +1,7 @@ // Checks multiple things on the sidebar display (width of its elements, colors, etc). include: "utils.goml" +// Disable animations so they don't mess up color assertions later. +emulate-media-features: { "prefers-reduced-motion": "reduce" } go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "199"}) show-text: true diff --git a/tests/rustdoc-js-std/asrawfd.js b/tests/rustdoc-js-std/asrawfd.js index 5dbc4ba95d9a..da08eeb8a53c 100644 --- a/tests/rustdoc-js-std/asrawfd.js +++ b/tests/rustdoc-js-std/asrawfd.js @@ -1,12 +1,10 @@ // ignore-order const EXPECTED = { - 'query': 'RawFd::as_raw_fd', + 'query': 'method:RawFd::as_raw_fd', 'others': [ // Reproduction test for https://github.com/rust-lang/rust/issues/78724 // Validate that type alias methods get the correct path. - { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' }, - { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' }, { 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' }, ], }; diff --git a/tests/rustdoc-js-std/quoted.js b/tests/rustdoc-js-std/quoted.js index 8a9275019255..a8ca6521208e 100644 --- a/tests/rustdoc-js-std/quoted.js +++ b/tests/rustdoc-js-std/quoted.js @@ -1,21 +1,21 @@ +// make sure quoted search works both for items and and without generics // ignore-order const FILTER_CRATE = 'std'; const EXPECTED = { - 'query': '"error"', + 'query': '"result"', 'others': [ - { 'path': 'std', 'name': 'error' }, - { 'path': 'std::fmt', 'name': 'Error' }, - { 'path': 'std::io', 'name': 'Error' }, + { 'path': 'std', 'name': 'result' }, + { 'path': 'std::result', 'name': 'Result' }, + { 'path': 'std::fmt', 'name': 'Result' }, ], 'in_args': [ - { 'path': 'std::fmt::Error', 'name': 'eq' }, - { 'path': 'std::fmt::Error', 'name': 'cmp' }, - { 'path': 'std::fmt::Error', 'name': 'partial_cmp' }, - + { 'path': 'std::result::Result', 'name': 'branch' }, + { 'path': 'std::result::Result', 'name': 'ok' }, + { 'path': 'std::result::Result', 'name': 'unwrap' }, ], 'returned': [ - { 'path': 'std::fmt::LowerExp', 'name': 'fmt' }, + { 'path': 'std::bool', 'name': 'try_into' }, ], }; diff --git a/tests/rustdoc-js-std/bufread-fill-buf.js b/tests/rustdoc-js-std/trait-unbox.js similarity index 58% rename from tests/rustdoc-js-std/bufread-fill-buf.js rename to tests/rustdoc-js-std/trait-unbox.js index 6b9309f68640..44ddc0c1e75c 100644 --- a/tests/rustdoc-js-std/bufread-fill-buf.js +++ b/tests/rustdoc-js-std/trait-unbox.js @@ -1,10 +1,10 @@ -// ignore-order +// make sure type-based searches with traits get unboxed too const EXPECTED = [ { - 'query': 'bufread -> result<[u8]>', + 'query': 'any -> result', 'others': [ - { 'path': 'std::boxed::Box', 'name': 'fill_buf' }, + { 'path': 'std::boxed::Box', 'name': 'downcast' }, ], }, { From a145dfff03d562584a4a00552fb5df67cdd0d2b6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 21 Sep 2025 16:10:32 -0500 Subject: [PATCH 491/537] search.js: introduce optimized removeIdxListAsc routine --- src/librustdoc/html/static/js/search.js | 39 +++++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 71bad967026e..9a6d4c710ff5 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1076,6 +1076,34 @@ function isPathSeparator(c) { return c === ":" || c === " "; } +/** + * Given an array and an ascending list of indices, + * efficiently removes each index in the array. + * + * @template T + * @param {Array} a + * @param {Array} idxList + */ +function removeIdxListAsc(a, idxList) { + if (idxList.length === 0) { + return; + } + let removed = 0; + let i = idxList[0]; + let nextToRemove = idxList[0]; + while (i < a.length - idxList.length) { + while (i === nextToRemove && removed < idxList.length) { + removed++; + i++; + nextToRemove = idxList[removed]; + } + a[i] = a[i + removed]; + i++; + } + // truncate array + a.length -= idxList.length; +} + /** * @template T */ @@ -2615,7 +2643,7 @@ class DocSearch { */ const transformResults = (results, typeInfo, duplicates) => { /** @type {rustdoc.ResultObject[]} */ - let out = []; + const out = []; // if we match a trait-associated item, we want to go back and // remove all the items that are their equivalent but in an impl block. @@ -2712,16 +2740,9 @@ class DocSearch { list.push(out.length); traitImplIdxMap.set(obj.traitPath, list); } else { - // FIXME: this is `O(n*m)` because we're repeatedly - // shifting with Array.splice, but could be `O(n+m)` if - // we did the shifting manually in a more clever way. const toRemoveList = traitImplIdxMap.get(obj.fullPath); if (toRemoveList) { - // iterate in reverse order so we don't shift the indexes - for (let i = toRemoveList.length - 1; i >= 0; i--) { - const rmIdx = toRemoveList[i]; - out = out.splice(rmIdx, 1); - } + removeIdxListAsc(out, toRemoveList); } traitImplIdxMap.delete(obj.fullPath); } From d0dc603c3992cc4903bb77f949b0b9bebf1ea7a8 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 21 Sep 2025 16:42:12 -0500 Subject: [PATCH 492/537] rustdoc: add testcase for traitParent deduplication --- tests/rustdoc-js/trait-methods.js | 20 ++++++++++++++++++++ tests/rustdoc-js/trait-methods.rs | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/tests/rustdoc-js/trait-methods.js b/tests/rustdoc-js/trait-methods.js index dafad5e43784..083e52439f4a 100644 --- a/tests/rustdoc-js/trait-methods.js +++ b/tests/rustdoc-js/trait-methods.js @@ -9,4 +9,24 @@ const EXPECTED = [ { 'path': 'trait_methods::MyTrait', 'name': 'next' }, ], }, + // the traitParent deduplication pass should remove + // Empty::next, as it would be redundant + { + 'query': 'next', + 'correction': null, + 'in_args': [], + 'others': [ + { 'path': 'trait_methods::MyTrait', 'name': 'next' }, + ], + }, + // if the trait does not match, no deduplication happens + { + 'query': '-> option<()>', + 'correction': null, + 'in_args': [], + 'others': [ + { 'path': 'trait_methods::Empty', 'name': 'next' }, + { 'path': 'trait_methods::Void', 'name': 'next' }, + ], + }, ]; diff --git a/tests/rustdoc-js/trait-methods.rs b/tests/rustdoc-js/trait-methods.rs index c88f5edfd55b..a741b361a339 100644 --- a/tests/rustdoc-js/trait-methods.rs +++ b/tests/rustdoc-js/trait-methods.rs @@ -2,3 +2,21 @@ pub trait MyTrait { type Item; fn next(&mut self) -> Option; } + +pub struct Empty; + +impl MyTrait for Empty { + type Item = (); + fn next(&mut self) -> Option<()> { + None + } +} + +pub struct Void; + +impl MyTrait for Void { + type Item = (); + fn next(&mut self) -> Option<()> { + Some(()) + } +} From c7d6857f750a8c957ebca81340faa379cc3d110f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 2 Oct 2025 10:19:42 -0700 Subject: [PATCH 493/537] rustdoc: use same stage for all pr check docs --- src/ci/docker/host-x86_64/pr-check-2/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile index d6470e4deb8d..0a95f428f5bd 100644 --- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile @@ -32,7 +32,7 @@ ENV SCRIPT \ python3 ../x.py clippy ci --stage 2 && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ python3 ../x.py test --stage 1 src/tools/compiletest && \ - python3 ../x.py doc bootstrap && \ + python3 ../x.py doc bootstrap --stage 1 && \ # Build both public and internal documentation. RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 1 && \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 1 && \ From 99550fbc3ea172a3cf90d2776a217e1ba19a196f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 2 Oct 2025 14:36:57 -0700 Subject: [PATCH 494/537] Return to needs-llvm-components being info-only Partially revert a535042e80a38196a58c27a8c95552546affe5dc Even with non-LLVM codegen backends, we want to allow for annotations that express dependencies to LLVM-specific parts of the test suite. This includes `//@ needs-llvm-components`, which just allows checking that LLVM is built with relevant target support before the test is run. It does not assert the test cannot work with another codegen backend. --- src/tools/compiletest/src/directives/needs.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index c8a729d8aab6..9d72492e5b07 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -281,10 +281,7 @@ pub(super) fn handle_needs( // Handled elsewhere. if name == "needs-llvm-components" { - if config.default_codegen_backend.is_llvm() { - return IgnoreDecision::Continue; - } - return IgnoreDecision::Ignore { reason: "LLVM specific test".into() }; + return IgnoreDecision::Continue; } let mut found_valid = false; From a5c9030271d48456ffefca83a416f0ee863ba965 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 2 Oct 2025 20:54:47 +0000 Subject: [PATCH 495/537] Extract common logic for iterating over features Two places doing the same thing is enough to motivate me to extract this to a method :) --- compiler/rustc_ast_passes/src/feature_gate.rs | 6 +----- compiler/rustc_feature/src/unstable.rs | 10 ++++++++++ compiler/rustc_lint/src/builtin.rs | 8 ++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 608ccfefeb69..b8a29a9a08f4 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -622,11 +622,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) } fn check_incompatible_features(sess: &Session, features: &Features) { - let enabled_lang_features = - features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); - let enabled_lib_features = - features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); - let enabled_features = enabled_lang_features.chain(enabled_lib_features); + let enabled_features = features.enabled_features_iter_stable_order(); for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e63f29a9570d..8397cd294e0a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -93,6 +93,16 @@ impl Features { &self.enabled_features } + /// Returns a iterator of enabled features in stable order. + pub fn enabled_features_iter_stable_order( + &self, + ) -> impl Iterator + Clone { + self.enabled_lang_features + .iter() + .map(|feat| (feat.gate_name, feat.attr_sp)) + .chain(self.enabled_lib_features.iter().map(|feat| (feat.gate_name, feat.attr_sp))) + } + /// Is the given feature enabled (via `#[feature(...)]`)? pub fn enabled(&self, feature: Symbol) -> bool { self.enabled_features.contains(&feature) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 75a0f89321b9..8a525eb11f7b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2331,13 +2331,9 @@ declare_lint_pass!( impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.builder.features(); - let lang_features = - features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); - let lib_features = - features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); - lang_features - .chain(lib_features) + features + .enabled_features_iter_stable_order() .filter(|(name, _)| features.incomplete(*name) || features.internal(*name)) .for_each(|(name, span)| { if features.incomplete(name) { From c2a03cefd8899941032940df0c6be3b364de0ed0 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 21 Sep 2025 20:58:34 +0800 Subject: [PATCH 496/537] debuginfo: Use `LocalRef` to simplify reference debuginfos If the `LocalRef` is `LocalRef::Place`, we can refer to it directly, because the local of place is an indirect pointer. Such a statement is `_1 = &(_2.1)`. If the `LocalRef` is `LocalRef::Operand`, the `OperandRef` should provide the pointer of the reference. Such a statement is `_1 = &((*_2).1)`. But there is a special case that hasn't been handled, scalar pairs like `(&[i32; 16], i32)`. --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 9 +- .../rustc_codegen_ssa/src/mir/statement.rs | 61 +-- tests/codegen-llvm/debuginfo-dse.rs | 401 +++++++++++++----- 3 files changed, 316 insertions(+), 155 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 38bb6f24b1c3..0c9acf087f9f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -259,8 +259,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, bx: &mut Bx, local: mir::Local, - base: PlaceValue, - layout: TyAndLayout<'tcx>, + base: PlaceRef<'tcx, Bx::Value>, projection: &[mir::PlaceElem<'tcx>], ) { let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; @@ -274,7 +273,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, projection, layout); + calculate_debuginfo_offset(bx, projection, base.layout); for var in vars.iter() { let Some(dbg_var) = var.dbg_var else { continue; @@ -285,7 +284,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.dbg_var_value( dbg_var, dbg_loc, - base.llval, + base.val.llval, direct_offset, &indirect_offsets, &var.fragment, @@ -298,7 +297,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.cx().layout_of(ty); let to_backend_ty = bx.cx().immediate_backend_type(layout); let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout); - self.debug_new_val_to_local(bx, local, place_ref.val, layout, &[]); + self.debug_new_val_to_local(bx, local, place_ref, &[]); } /// Apply debuginfo and/or name, after creating the `alloca` for a local, diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 80f4f0fcda1c..88590b6271bc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,11 +1,8 @@ -use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo}; -use rustc_middle::{bug, span_bug}; -use rustc_target::callconv::PassMode; +use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo}; +use rustc_middle::span_bug; use tracing::instrument; use super::{FunctionCx, LocalRef}; -use crate::common::TypeKind; -use crate::mir::place::PlaceRef; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -110,48 +107,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match debuginfo { StmtDebugInfo::AssignRef(dest, place) => { let local_ref = match self.locals[place.local] { - LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { - Some(place_ref) + // For an rvalue like `&(_1.1)`, when `BackendRepr` is `BackendRepr::Memory`, we allocate a block of memory to this place. + // The place is an indirect pointer, we can refer to it directly. + LocalRef::Place(place_ref) => Some((place_ref, place.projection.as_slice())), + // For an rvalue like `&((*_1).1)`, we are calculating the address of `_1.1`. + // The deref projection is no-op here. + LocalRef::Operand(operand_ref) if place.is_indirect_first_projection() => { + Some((operand_ref.deref(bx.cx()), &place.projection[1..])) } - LocalRef::Operand(operand_ref) => operand_ref - .val - .try_pointer_parts() - .map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)), - LocalRef::PendingOperand => None, + // For an rvalue like `&1`, when `BackendRepr` is `BackendRepr::Scalar`, + // we cannot get the address. + // N.B. `non_ssa_locals` returns that this is an SSA local. + LocalRef::Operand(_) => None, + LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => None, } - .filter(|place_ref| { - // For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is - // llval. - let local_ref_pass_mode = place.as_local().and_then(|local| { - if local == RETURN_PLACE { - None - } else { - self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode) - } - }); - matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) && + .filter(|(_, projection)| { // Drop unsupported projections. - place.projection.iter().all(|p| p.can_use_in_debuginfo()) && - // Only pointers can be calculated addresses. - bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer + projection.iter().all(|p| p.can_use_in_debuginfo()) }); - if let Some(local_ref) = local_ref { - let (base_layout, projection) = if place.is_indirect_first_projection() { - // For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so - // we should drop the deref projection. - let projected_ty = local_ref - .layout - .ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref)); - let layout = bx.cx().layout_of(projected_ty); - (layout, &place.projection[1..]) - } else { - (local_ref.layout, place.projection.as_slice()) - }; - self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection); + if let Some((base, projection)) = local_ref { + self.debug_new_val_to_local(bx, *dest, base, projection); } else { - // If the address cannot be computed, use poison to indicate that the value has been optimized out. + // If the address cannot be calculated, use poison to indicate that the value has been optimized out. self.debug_poison_to_local(bx, *dest); } } diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs index 78e145a3cdf1..fd0c9f1c676f 100644 --- a/tests/codegen-llvm/debuginfo-dse.rs +++ b/tests/codegen-llvm/debuginfo-dse.rs @@ -1,9 +1,249 @@ //@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled //@ revisions: CODEGEN OPTIMIZED //@[CODEGEN] compile-flags: -Cno-prepopulate-passes +//@ only-64bit // ignore-tidy-linelength #![crate_type = "lib"] +#![feature(repr_simd, rustc_attrs)] + +// The pass mode is direct and the backend represent is scalar. +type Scalar = i32; // scalar(i32) +type Scalar_Ref = &'static i32; // scalar(ptr) + +// The pass modes are pair and the backend represents are scalar pair. +type Tuple_Scalar_Scalar = (i32, i32); +struct Tuple_Ref_Scalar(&'static i32, i32); +struct Tuple_ArrayRef_Scalar(&'static [i32; 16], i32); // pair(ptr, i32) +impl Default for Tuple_ArrayRef_Scalar { + fn default() -> Tuple_ArrayRef_Scalar { + Tuple_ArrayRef_Scalar(&[0; 16], 0) + } +} +struct Tuple_Scalar_ArrayRef(i32, &'static [i32; 16]); // pair(i32, ptr) +impl Default for Tuple_Scalar_ArrayRef { + fn default() -> Tuple_Scalar_ArrayRef { + Tuple_Scalar_ArrayRef(0, &[0; 16]) + } +} +// The pass mode is indirect and the backend represent is memory. +type Tuple_SliceRef_Scalar = (&'static [i32], i32); + +// The pass mode is pair and the backend represent is scalar pair. +type SliceRef = &'static [i32]; // pair(ptr, i32) +// The pass mode is indirect and the backend represent is memory. +type Array = [i32; 16]; +// The pass mode is direct and the backend represent is scalar. +type ArrayRef = &'static [i32; 16]; + +// The pass mode is indirect and the backend represent is memory. +type Typle_i32_i64_i8 = (i32, i64, i8); +// The pass mode is indirect and the backend represent is memory. +#[repr(C)] +struct Aggregate_i32_Array_i8(i32, &'static [i32; 16], i8); + +type ZST = (); + +impl Default for Aggregate_i32_Array_i8 { + fn default() -> Aggregate_i32_Array_i8 { + Aggregate_i32_Array_i8(0, &[0; 16], 0) + } +} +// The pass mode is cast and the backend represent is scalar. +#[derive(Default)] +struct Aggregate_4xi8(i8, i8, i8, i8); // scalar(i32) + +// The pass mode is indirect and the backend represent is simd vector. +#[repr(simd)] +struct Simd_i32x4([i32; 4]); + +unsafe extern "Rust" { + #[rustc_nounwind] + safe fn opaque_fn(); + #[rustc_nounwind] + safe fn opaque_ptr(_: *const core::ffi::c_void); +} + +#[inline(never)] +#[rustc_nounwind] +fn opaque_use(p: &T) { + opaque_ptr(&raw const p as *const _); +} + +#[inline(never)] +#[rustc_nounwind] +fn opaque_read() -> T { + core::hint::black_box(T::default()) +} + +#[unsafe(no_mangle)] +fn local_var() { + // CHECK-LABEL: define{{( dso_local)?}} void @local_var + let local_var_scalar: Scalar = opaque_read(); + opaque_use(&local_var_scalar); + let dead_local_var_scalar: Scalar = opaque_read(); + let local_var_aggregate_4xi8: Aggregate_4xi8 = opaque_read(); + opaque_use(&local_var_aggregate_4xi8); + let local_var_aggregate_i32_array_i8: Aggregate_i32_Array_i8 = opaque_read(); + opaque_use(&local_var_aggregate_i32_array_i8); + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr %local_var_scalar, [[ref_local_var_scalar:![0-9]+]], !DIExpression() + let ref_local_var_scalar = &local_var_scalar; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_dead_local_var_scalar:![0-9]+]], !DIExpression() + let ref_dead_local_var_scalar = &dead_local_var_scalar; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_local_var_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_0_local_var_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_0_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.0; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_2_local_var_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 2, DW_OP_stack_value) + let ref_2_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.2; + // This introduces an extra load instruction. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression() + let ref_1_1_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.1[1]; + // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_i32_array_i8, [[ref_2_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_2_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.2; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +#[unsafe(no_mangle)] +fn zst(zst: ZST, zst_ref: &ZST) { + // CHECK-LABEL: define{{( dso_local)?}} void @zst + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst:![0-9]+]], !DIExpression() + let ref_zst = &zst; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst_ref:![0-9]+]], !DIExpression() + let ref_zst_ref = &zst_ref; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// It only makes sense if the argument is a reference and it refer to projections. +#[unsafe(no_mangle)] +fn direct( + scalar: Scalar, + scalar_ref: Scalar_Ref, + array_ref: ArrayRef, + aggregate_4xi8_ref: &Aggregate_4xi8, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @direct + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar:![0-9]+]], !DIExpression() + let ref_scalar = &scalar; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar_ref:![0-9]+]], !DIExpression() + let ref_scalar_ref = &scalar_ref; + // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_0_array_ref:![0-9]+]], !DIExpression() + let ref_0_array_ref = &array_ref[0]; + // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_1_array_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_array_ref = &array_ref[1]; + // CHECK-NEXT: #dbg_value(ptr %aggregate_4xi8_ref, [[ref_1_aggregate_4xi8_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + let ref_1_aggregate_4xi8_ref = &aggregate_4xi8_ref.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// Arguments are passed through registers, the final values are poison. +#[unsafe(no_mangle)] +fn cast(aggregate_4xi8: Aggregate_4xi8) { + // CHECK-LABEL: define{{( dso_local)?}} void @cast(i32 %0) + // CHECK: call void @opaque_fn() + opaque_fn(); + // The temporary allocated variable is eliminated. + // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression() + // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression() + let ref_aggregate_4xi8 = &aggregate_4xi8; + // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value) + let ref_0_aggregate_4xi8 = &aggregate_4xi8.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// Arguments are passed indirectly via a pointer. +// The reference of argument is the pointer itself. +#[unsafe(no_mangle)] +fn indirect( + tuple_sliceref_scalar: Tuple_SliceRef_Scalar, + array: Array, + typle_i32_i64_i8: Typle_i32_i64_i8, + simd_i32x4: Simd_i32x4, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @indirect + // CHECK-SAME: (ptr{{.*}} %tuple_sliceref_scalar, ptr{{.*}} %array, ptr{{.*}} %typle_i32_i64_i8, ptr{{.*}} %simd_i32x4) + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_tuple_sliceref_scalar:![0-9]+]], !DIExpression() + let ref_tuple_sliceref_scalar = &tuple_sliceref_scalar; + // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_1_tuple_sliceref_scalar:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) + let ref_1_tuple_sliceref_scalar = &tuple_sliceref_scalar.1; + // CHECK-NEXT: #dbg_value(ptr %array, [[ref_1_array:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_array = &array[1]; + // CHECK-NEXT: #dbg_value(ptr %typle_i32_i64_i8, [[ref_1_typle_i32_i64_i8:![0-9]+]], !DIExpression() + let ref_1_typle_i32_i64_i8 = &typle_i32_i64_i8.1; + // CHECK-NEXT: #dbg_value(ptr %simd_i32x4, [[ref_simd_i32x4:![0-9]+]], !DIExpression() + let ref_simd_i32x4 = &simd_i32x4; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +// They are different MIR statements, but they have the same LLVM IR statement due to the ABI of arguments. +// Both `direct_ref` and `indirect_byval` are passed as a pointer here. +#[unsafe(no_mangle)] +fn direct_ref_and_indirect( + direct_ref: &Aggregate_i32_Array_i8, + indirect_byval: Aggregate_i32_Array_i8, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @direct_ref_and_indirect + // CHECK-SAME: (ptr{{.*}} %direct_ref, ptr{{.*}} %indirect_byval) + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_direct_ref:![0-9]+]], !DIExpression() + let ref_direct_ref: &&Aggregate_i32_Array_i8 = &direct_ref; + // CHECK-NEXT: #dbg_value(ptr %direct_ref, [[ref_1_direct_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + let ref_1_direct_ref = &direct_ref.1; + // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_indirect_byval:![0-9]+]], !DIExpression() + let ref_indirect_byval: &Aggregate_i32_Array_i8 = &indirect_byval; + // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_1_indirect_byval:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) + let ref_1_indirect_byval = &indirect_byval.1; + // CHECK: call void @opaque_fn() + opaque_fn(); +} + +#[unsafe(no_mangle)] +fn pair( + tuple_scalar_scalar: Tuple_Scalar_Scalar, + tuple_ref_scalar: Tuple_Ref_Scalar, + tuple_arrayref_scalar: Tuple_ArrayRef_Scalar, + tuple_scalar_arrayref: Tuple_Scalar_ArrayRef, + sliceref: SliceRef, +) { + // CHECK-LABEL: define{{( dso_local)?}} void @pair + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_scalar_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_scalar_scalar = &tuple_scalar_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_ref_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_ref_scalar = &tuple_ref_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_ref_scalar:![0-9]+]], !DIExpression() + let ref_1_tuple_ref_scalar = &tuple_ref_scalar.1; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_0_tuple_arrayref_scalar = &tuple_arrayref_scalar.0; + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.1; + // FIXME: This can be a valid value. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression() + let ref_0_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.0[1]; + // FIXME: This can be a valid value. + // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_tuple_scalar_arrayref:![0-9]+]], !DIExpression() + let ref_1_1_tuple_scalar_arrayref = &tuple_scalar_arrayref.1[1]; + // CHECK: #dbg_value(ptr %sliceref.0, [[ref_1_sliceref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value) + let ref_1_sliceref = &sliceref[1]; + // CHECK: call void @opaque_fn() + opaque_fn(); +} #[repr(C)] #[derive(Clone, Copy)] @@ -16,23 +256,7 @@ pub struct Bar<'a> { foo: &'a Foo, } -#[no_mangle] -fn r#ref(ref_foo: &Foo) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @ref - // CHECK-SAME: (ptr {{.*}} [[ARG_ref_foo:%.*]]) - // OPTIMIZED: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr poison, [[VAR_invalid_ref_of_ref_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v0:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) - // CHECK: #dbg_value(ptr [[ARG_ref_foo]], [[VAR_ref_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let invalid_ref_of_ref_foo = &ref_foo; - let ref_v0 = &ref_foo.0; - let ref_v1 = &ref_foo.1; - let ref_v2 = &ref_foo.2; - ref_foo.0 -} - -#[no_mangle] +#[unsafe(no_mangle)] pub fn dead_first(dead_first_foo: &Foo) -> &i32 { // CHECK-LABEL: def {{.*}} ptr @dead_first // CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]]) @@ -47,32 +271,9 @@ pub fn dead_first(dead_first_foo: &Foo) -> &i32 { dead_first_v0 } -#[no_mangle] -fn ptr(ptr_foo: Foo) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @ptr - // CHECK-SAME: (ptr {{.*}} [[ARG_ptr_foo:%.*]]) - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[ref_ptr_foo:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v0:![0-9]+]], !DIExpression() - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v1:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value) - // CHECK: #dbg_value(ptr [[ARG_ptr_foo]], [[VAR_ptr_v2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let ref_ptr_foo = &ptr_foo; - let ptr_v0 = &ptr_foo.0; - let ptr_v1 = &ptr_foo.1; - let ptr_v2 = &ptr_foo.2; - ptr_foo.2 -} - -#[no_mangle] -fn no_ptr(val: i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @no_ptr - // CODEGEN: #dbg_value(ptr poison, [[VAR_val_ref:![0-9]+]], !DIExpression() - let val_ref = &val; - val -} - -#[no_mangle] +#[unsafe(no_mangle)] pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { - // CHECK-LABEL: define void @fragment + // CHECK-LABEL: define{{( dso_local)?}} void @fragment // CHECK-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]]) // CHECK: #dbg_declare(ptr [[ARG_fragment_v1]] // CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]] @@ -85,93 +286,77 @@ pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo { fragment_v2 } -#[no_mangle] +#[unsafe(no_mangle)] pub fn deref(bar: Bar) -> i32 { - // CHECK-LABEL: define {{.*}} i32 @deref + // CHECK-LABEL: define{{.*}} i32 @deref // We are unable to represent dereference within this expression. // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression() let deref_dead = &bar.foo.2; bar.a } -#[no_mangle] -pub fn tuple(foo: (i32, &Foo)) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @tuple - // Although there is no dereference here, there is a dereference in the MIR. - // CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression() - let tuple_dead = &foo.1.2; - foo.1.0 -} - -pub struct ZST; - -#[no_mangle] -pub fn zst(zst: ZST, v: &i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @zst - // CHECK: #dbg_value(ptr poison, [[VAR_zst_ref:![0-9]+]], !DIExpression() - let zst_ref = &zst; - *v -} - -#[no_mangle] +#[unsafe(no_mangle)] fn index(slice: &[i32; 4], idx: usize) -> i32 { // CHECK-LABEL: define{{.*}} i32 @index - // CHECK: bb1: - // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression() - // CODEGEN: bb3: - // CHECK-NEXT: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression() + // CHECK: call void @opaque_fn() + opaque_fn(); + // CHECK: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression() let index_from_var = &slice[idx]; + // CHECK: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression() + // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression() let [ref const_index_from_start, .., ref const_index_from_end] = slice[..] else { return 0; }; slice[0] } -unsafe extern "Rust" { - safe fn opaque_inner(_: *const core::ffi::c_void); -} +// CHECK-DAG: [[ref_local_var_scalar]] = !DILocalVariable(name: "ref_local_var_scalar" +// CHECK-DAG: [[ref_dead_local_var_scalar]] = !DILocalVariable(name: "ref_dead_local_var_scalar" +// CHECK-DAG: [[ref_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_0_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_2_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_4xi8" +// CHECK-DAG: [[ref_1_1_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_1_1_local_var_aggregate_i32_array_i8" +// CHECK-DAG: [[ref_2_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_i32_array_i8" -#[inline(never)] -pub fn opaque_use(p: &T) { - opaque_inner(&raw const p as *const _); -} +// CHECK-DAG: [[ref_zst]] = !DILocalVariable(name: "ref_zst" +// CHECK-DAG: [[ref_zst_ref]] = !DILocalVariable(name: "ref_zst_ref" -#[no_mangle] -pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 { - // CHECK-LABEL: define{{.*}} i32 @non_arg_ref - // CHECK: #dbg_value(ptr %non_arg_ref_scalar, [[VAR_non_arg_ref_scalar_ref:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref:![0-9]+]], !DIExpression() - // CHECK-NEXT: #dbg_value(ptr %non_arg_ref_foo, [[VAR_non_arg_ref_foo_ref_2:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value) - let non_arg_ref_scalar = scalar; - let non_arg_ref_foo = foo; - opaque_use(&non_arg_ref_scalar); - opaque_use(&non_arg_ref_foo); - let non_arg_ref_scalar_ref = &non_arg_ref_scalar; - let non_arg_ref_foo_ref = &non_arg_ref_foo; - let non_arg_ref_foo_ref_2 = &non_arg_ref_foo.2; - *a -} +// CHECK-DAG: [[ref_scalar]] = !DILocalVariable(name: "ref_scalar" +// CHECK-DAG: [[ref_scalar_ref]] = !DILocalVariable(name: "ref_scalar_ref" +// CHECK-DAG: [[ref_0_array_ref]] = !DILocalVariable(name: "ref_0_array_ref" +// CHECK-DAG: [[ref_1_array_ref]] = !DILocalVariable(name: "ref_1_array_ref" +// CHECK-DAG: [[ref_1_aggregate_4xi8_ref]] = !DILocalVariable(name: "ref_1_aggregate_4xi8_ref" + +// CHECK-DAG: [[ref_aggregate_4xi8]] = !DILocalVariable(name: "ref_aggregate_4xi8" +// CHECK-DAG: [[ref_0_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_aggregate_4xi8" + +// CHECK-DAG: [[ref_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_tuple_sliceref_scalar" +// CHECK-DAG: [[ref_1_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_1_tuple_sliceref_scalar" +// CHECK-DAG: [[ref_1_array]] = !DILocalVariable(name: "ref_1_array" +// CHECK-DAG: [[ref_1_typle_i32_i64_i8]] = !DILocalVariable(name: "ref_1_typle_i32_i64_i8" +// CHECK-DAG: [[ref_simd_i32x4]] = !DILocalVariable(name: "ref_simd_i32x4" + +// CHECK-DAG: [[ref_direct_ref]] = !DILocalVariable(name: "ref_direct_ref" +// CHECK-DAG: [[ref_1_direct_ref]] = !DILocalVariable(name: "ref_1_direct_ref" +// CHECK-DAG: [[ref_indirect_byval]] = !DILocalVariable(name: "ref_indirect_byval" +// CHECK-DAG: [[ref_1_indirect_byval]] = !DILocalVariable(name: "ref_1_indirect_byval" + +// CHECK-DAG: [[ref_0_tuple_scalar_scalar]] = !DILocalVariable(name: "ref_0_tuple_scalar_scalar" +// CHECK-DAG: [[ref_0_tuple_ref_scalar]] = !DILocalVariable(name: "ref_0_tuple_ref_scalar" +// CHECK-DAG: [[ref_1_tuple_ref_scalar]] = !DILocalVariable(name: "ref_1_tuple_ref_scalar" +// CHECK-DAG: [[ref_0_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_1_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_0_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_1_tuple_arrayref_scalar" +// CHECK-DAG: [[ref_1_1_tuple_scalar_arrayref]] = !DILocalVariable(name: "ref_1_1_tuple_scalar_arrayref" +// CHECK-DAG: [[ref_1_sliceref]] = !DILocalVariable(name: "ref_1_sliceref" -// CHECK-DAG: [[VAR_invalid_ref_of_ref_foo]] = !DILocalVariable(name: "invalid_ref_of_ref_foo" -// OPTIMIZED-DAG: [[VAR_ref_foo]] = !DILocalVariable(name: "ref_foo" -// CHECK-DAG: [[VAR_ref_v0]] = !DILocalVariable(name: "ref_v0" -// CHECK-DAG: [[VAR_ref_v1]] = !DILocalVariable(name: "ref_v1" -// CHECK-DAG: [[VAR_ref_v2]] = !DILocalVariable(name: "ref_v2" -// CHECK-DAG: [[ref_ptr_foo]] = !DILocalVariable(name: "ref_ptr_foo" -// CHECK-DAG: [[VAR_ptr_v0]] = !DILocalVariable(name: "ptr_v0" -// CHECK-DAG: [[VAR_ptr_v1]] = !DILocalVariable(name: "ptr_v1" -// CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2" -// CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref" -// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" -// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" -// CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead" // CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo" // CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0" + +// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f" + +// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead" + // CHECK-DAG: [[VAR_index_from_var]] = !DILocalVariable(name: "index_from_var" // CHECK-DAG: [[VAR_const_index_from_start]] = !DILocalVariable(name: "const_index_from_start" // CHECK-DAG: [[VAR_const_index_from_end]] = !DILocalVariable(name: "const_index_from_end" -// CHECK-DAG: [[VAR_zst_ref]] = !DILocalVariable(name: "zst_ref" -// CHECK-DAG: [[VAR_non_arg_ref_scalar_ref]] = !DILocalVariable(name: "non_arg_ref_scalar_ref" -// CHECK-DAG: [[VAR_non_arg_ref_foo_ref]] = !DILocalVariable(name: "non_arg_ref_foo_ref" -// CHECK-DAG: [[VAR_non_arg_ref_foo_ref_2]] = !DILocalVariable(name: "non_arg_ref_foo_ref_2" From 3d5f54ad55a32c0f53271597145b5cd7bae9c3e2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 3 Oct 2025 11:27:57 +0200 Subject: [PATCH 497/537] Respect `-Z` unstable options in `rustdoc --test` --- src/librustdoc/doctest.rs | 1 + .../rustdoc-ui/doctest/check-attr-test.stderr | 164 +++++++++--------- ...led-doctest-extra-semicolon-on-item.stderr | 2 +- .../doctest/main-alongside-stmts.stderr | 4 +- .../doctest/standalone-warning-2024.stderr | 30 ++-- .../doctest/test-compile-fail1.stderr | 18 +- .../doctest/test-compile-fail2.stderr | 8 +- .../doctest/test-compile-fail3.stderr | 8 +- .../doctest/warn-main-not-called.stderr | 4 +- 9 files changed, 120 insertions(+), 119 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 95bd31729de1..38a0c925d2a4 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -173,6 +173,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions target_triple: options.target.clone(), crate_name: options.crate_name.clone(), remap_path_prefix: options.remap_path_prefix.clone(), + unstable_opts: options.unstable_opts.clone(), ..config::Options::default() }; diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr index 257136d1633d..4cf93033ae8a 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.stderr +++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr @@ -1,55 +1,55 @@ error: unknown attribute `compile-fail` - --> $DIR/check-attr-test.rs:5:1 - | -5 | / /// foo -6 | | /// -7 | | /// ```compile-fail,compilefail,comPile_fail -8 | | /// boo -9 | | /// ``` - | |_______^ - | - = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can - = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` + --> $DIR/check-attr-test.rs:5:1 + | +LL | / /// foo +LL | | /// +LL | | /// ```compile-fail,compilefail,comPile_fail +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here - --> $DIR/check-attr-test.rs:3:9 - | -3 | #![deny(rustdoc::invalid_codeblock_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/check-attr-test.rs:3:9 + | +LL | #![deny(rustdoc::invalid_codeblock_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unknown attribute `compilefail` - --> $DIR/check-attr-test.rs:5:1 - | -5 | / /// foo -6 | | /// -7 | | /// ```compile-fail,compilefail,comPile_fail -8 | | /// boo -9 | | /// ``` - | |_______^ - | - = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can - = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` + --> $DIR/check-attr-test.rs:5:1 + | +LL | / /// foo +LL | | /// +LL | | /// ```compile-fail,compilefail,comPile_fail +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` - --> $DIR/check-attr-test.rs:5:1 - | -5 | / /// foo -6 | | /// -7 | | /// ```compile-fail,compilefail,comPile_fail -8 | | /// boo -9 | | /// ``` - | |_______^ - | - = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can - = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` + --> $DIR/check-attr-test.rs:5:1 + | +LL | / /// foo +LL | | /// +LL | | /// ```compile-fail,compilefail,comPile_fail +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` --> $DIR/check-attr-test.rs:12:1 | -12 | / /// bar -13 | | /// -14 | | /// ```should-panic,shouldpanic,shOuld_panic -15 | | /// boo -16 | | /// ``` +LL | / /// bar +LL | | /// +LL | | /// ```should-panic,shouldpanic,shOuld_panic +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not @@ -58,11 +58,11 @@ error: unknown attribute `should-panic` error: unknown attribute `shouldpanic` --> $DIR/check-attr-test.rs:12:1 | -12 | / /// bar -13 | | /// -14 | | /// ```should-panic,shouldpanic,shOuld_panic -15 | | /// boo -16 | | /// ``` +LL | / /// bar +LL | | /// +LL | | /// ```should-panic,shouldpanic,shOuld_panic +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not @@ -71,11 +71,11 @@ error: unknown attribute `shouldpanic` error: unknown attribute `shOuld_panic` --> $DIR/check-attr-test.rs:12:1 | -12 | / /// bar -13 | | /// -14 | | /// ```should-panic,shouldpanic,shOuld_panic -15 | | /// boo -16 | | /// ``` +LL | / /// bar +LL | | /// +LL | | /// ```should-panic,shouldpanic,shOuld_panic +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not @@ -84,11 +84,11 @@ error: unknown attribute `shOuld_panic` error: unknown attribute `no-run` --> $DIR/check-attr-test.rs:19:1 | -19 | / /// foobar -20 | | /// -21 | | /// ```no-run,norun,nO_run -22 | | /// boo -23 | | /// ``` +LL | / /// foobar +LL | | /// +LL | | /// ```no-run,norun,nO_run +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `no_run` to compile, but not run, the code sample during testing @@ -97,11 +97,11 @@ error: unknown attribute `no-run` error: unknown attribute `norun` --> $DIR/check-attr-test.rs:19:1 | -19 | / /// foobar -20 | | /// -21 | | /// ```no-run,norun,nO_run -22 | | /// boo -23 | | /// ``` +LL | / /// foobar +LL | | /// +LL | | /// ```no-run,norun,nO_run +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `no_run` to compile, but not run, the code sample during testing @@ -110,11 +110,11 @@ error: unknown attribute `norun` error: unknown attribute `nO_run` --> $DIR/check-attr-test.rs:19:1 | -19 | / /// foobar -20 | | /// -21 | | /// ```no-run,norun,nO_run -22 | | /// boo -23 | | /// ``` +LL | / /// foobar +LL | | /// +LL | | /// ```no-run,norun,nO_run +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `no_run` to compile, but not run, the code sample during testing @@ -123,11 +123,11 @@ error: unknown attribute `nO_run` error: unknown attribute `test-harness` --> $DIR/check-attr-test.rs:26:1 | -26 | / /// b -27 | | /// -28 | | /// ```test-harness,testharness,tesT_harness -29 | | /// boo -30 | | /// ``` +LL | / /// b +LL | | /// +LL | | /// ```test-harness,testharness,tesT_harness +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function @@ -136,11 +136,11 @@ error: unknown attribute `test-harness` error: unknown attribute `testharness` --> $DIR/check-attr-test.rs:26:1 | -26 | / /// b -27 | | /// -28 | | /// ```test-harness,testharness,tesT_harness -29 | | /// boo -30 | | /// ``` +LL | / /// b +LL | | /// +LL | | /// ```test-harness,testharness,tesT_harness +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function @@ -149,11 +149,11 @@ error: unknown attribute `testharness` error: unknown attribute `tesT_harness` --> $DIR/check-attr-test.rs:26:1 | -26 | / /// b -27 | | /// -28 | | /// ```test-harness,testharness,tesT_harness -29 | | /// boo -30 | | /// ``` +LL | / /// b +LL | | /// +LL | | /// ```test-harness,testharness,tesT_harness +LL | | /// boo +LL | | /// ``` | |_______^ | = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr index 113fb7ccb60e..cffda43ba1c9 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr @@ -1,7 +1,7 @@ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/failed-doctest-extra-semicolon-on-item.rs:11:1 | -11 | /// ```rust +LL | /// ```rust | ^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr index d90a289ca698..3f347d96ab06 100644 --- a/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr @@ -1,13 +1,13 @@ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/main-alongside-stmts.rs:17:1 | -17 | //! ``` +LL | //! ``` | ^^^^^^^ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/main-alongside-stmts.rs:26:1 | -26 | //! ``` +LL | //! ``` | ^^^^^^^ warning: 2 warnings emitted diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr index ce65557c2c4a..1af2ded58e8b 100644 --- a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr @@ -1,13 +1,13 @@ error: unknown attribute `standalone` --> $DIR/standalone-warning-2024.rs:11:1 | -11 | / //! ```standalone -12 | | //! bla -13 | | //! ``` -14 | | //! -15 | | //! ```standalone-crate -16 | | //! bla -17 | | //! ``` +LL | / //! ```standalone +LL | | //! bla +LL | | //! ``` +LL | | //! +LL | | //! ```standalone-crate +LL | | //! bla +LL | | //! ``` | |_______^ | = help: use `standalone_crate` to compile this code block separately @@ -15,20 +15,20 @@ error: unknown attribute `standalone` note: the lint level is defined here --> $DIR/standalone-warning-2024.rs:9:9 | - 9 | #![deny(warnings)] +LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]` error: unknown attribute `standalone-crate` --> $DIR/standalone-warning-2024.rs:11:1 | -11 | / //! ```standalone -12 | | //! bla -13 | | //! ``` -14 | | //! -15 | | //! ```standalone-crate -16 | | //! bla -17 | | //! ``` +LL | / //! ```standalone +LL | | //! bla +LL | | //! ``` +LL | | //! +LL | | //! ```standalone-crate +LL | | //! bla +LL | | //! ``` | |_______^ | = help: use `standalone_crate` to compile this code block separately diff --git a/tests/rustdoc-ui/doctest/test-compile-fail1.stderr b/tests/rustdoc-ui/doctest/test-compile-fail1.stderr index 02f4d8d754f9..aa5cc2e14d6d 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail1.stderr +++ b/tests/rustdoc-ui/doctest/test-compile-fail1.stderr @@ -1,13 +1,13 @@ error[E0428]: the name `f` is defined multiple times - --> $DIR/test-compile-fail1.rs:8:1 - | -6 | pub fn f() {} - | ---------- previous definition of the value `f` here -7 | -8 | pub fn f() {} - | ^^^^^^^^^^ `f` redefined here - | - = note: `f` must be defined only once in the value namespace of this module + --> $DIR/test-compile-fail1.rs:8:1 + | +LL | pub fn f() {} + | ---------- previous definition of the value `f` here +LL | +LL | pub fn f() {} + | ^^^^^^^^^^ `f` redefined here + | + = note: `f` must be defined only once in the value namespace of this module error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doctest/test-compile-fail2.stderr b/tests/rustdoc-ui/doctest/test-compile-fail2.stderr index f0ad40eb6ca8..9f50c857275c 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail2.stderr +++ b/tests/rustdoc-ui/doctest/test-compile-fail2.stderr @@ -1,8 +1,8 @@ error: expected one of `!` or `::`, found `` - --> $DIR/test-compile-fail2.rs:3:1 - | -3 | fail - | ^^^^ expected one of `!` or `::` + --> $DIR/test-compile-fail2.rs:3:1 + | +LL | fail + | ^^^^ expected one of `!` or `::` error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doctest/test-compile-fail3.stderr b/tests/rustdoc-ui/doctest/test-compile-fail3.stderr index 09d78b2f3467..9f90a428d480 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail3.stderr +++ b/tests/rustdoc-ui/doctest/test-compile-fail3.stderr @@ -1,8 +1,8 @@ error[E0765]: unterminated double quote string - --> $DIR/test-compile-fail3.rs:3:1 - | -3 | "fail - | ^^^^^ + --> $DIR/test-compile-fail3.rs:3:1 + | +LL | "fail + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.stderr b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr index 3a079f47555b..b5b7bc57644a 100644 --- a/tests/rustdoc-ui/doctest/warn-main-not-called.stderr +++ b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr @@ -1,13 +1,13 @@ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/warn-main-not-called.rs:10:1 | -10 | //! ``` +LL | //! ``` | ^^^^^^^ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/warn-main-not-called.rs:19:1 | -19 | //! ``` +LL | //! ``` | ^^^^^^^ warning: 2 warnings emitted From cb0f969b623a7e12a0d8166c9a498e17a8b5a3c4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 3 Oct 2025 16:57:24 +1000 Subject: [PATCH 498/537] Avoid getting `dep_dep_node` unnecessarily. It's gotten on a hot path but only for use within `debug!`. --- compiler/rustc_query_system/src/dep_graph/graph.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7e258aaa54f7..eafb38bd25bb 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -876,14 +876,19 @@ impl DepGraphData { frame: Option<&MarkFrame<'_>>, ) -> Option<()> { let dep_dep_node_color = self.colors.get(parent_dep_node_index); - let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index); + + let get_dep_dep_node = || self.previous.index_to_node(parent_dep_node_index); match dep_dep_node_color { Some(DepNodeColor::Green(_)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. - debug!("dependency {dep_dep_node:?} was immediately green"); + // + // This path is extremely hot. We don't want to get the + // `dep_dep_node` unless it's necessary. Hence the + // `get_dep_dep_node` closure. + debug!("dependency {:?} was immediately green", get_dep_dep_node()); return Some(()); } Some(DepNodeColor::Red) => { @@ -891,12 +896,14 @@ impl DepGraphData { // compared to the previous compilation session. We cannot // mark the DepNode as green and also don't need to bother // with checking any of the other dependencies. - debug!("dependency {dep_dep_node:?} was immediately red"); + debug!("dependency {:?} was immediately red", get_dep_dep_node()); return None; } None => {} } + let dep_dep_node = &get_dep_dep_node(); + // We don't know the state of this dependency. If it isn't // an eval_always node, let's try to mark it green recursively. if !qcx.dep_context().is_eval_always(dep_dep_node.kind) { From 3a287e6034e1339198908cd7253fa414447c97d3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 3 Oct 2025 16:58:03 +1000 Subject: [PATCH 499/537] Remove some unnecessary locals. They both have a single use. (They can't be united, though, because `self.colors` might change between the two `get` calls.) --- compiler/rustc_query_system/src/dep_graph/graph.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index eafb38bd25bb..5e62dab0722c 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -875,11 +875,9 @@ impl DepGraphData { parent_dep_node_index: SerializedDepNodeIndex, frame: Option<&MarkFrame<'_>>, ) -> Option<()> { - let dep_dep_node_color = self.colors.get(parent_dep_node_index); - let get_dep_dep_node = || self.previous.index_to_node(parent_dep_node_index); - match dep_dep_node_color { + match self.colors.get(parent_dep_node_index) { Some(DepNodeColor::Green(_)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other @@ -929,9 +927,7 @@ impl DepGraphData { return None; } - let dep_dep_node_color = self.colors.get(parent_dep_node_index); - - match dep_dep_node_color { + match self.colors.get(parent_dep_node_index) { Some(DepNodeColor::Green(_)) => { debug!("managed to FORCE dependency {dep_dep_node:?} to green"); return Some(()); From 1485e7887b6407ce6326e044d9b3983364db52ad Mon Sep 17 00:00:00 2001 From: Fletcher Porter Date: Wed, 18 Jun 2025 15:04:54 +0300 Subject: [PATCH 500/537] Document fully-qualified syntax in `as`' keyword doc --- library/std/src/keyword_docs.rs | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 7ff4af8ede84..dc0d11b07a9f 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1,6 +1,8 @@ #[doc(keyword = "as")] // -/// Cast between types, or rename an import. +/// Cast between types, rename an import, or qualify paths to associated items. +/// +/// # Type casting /// /// `as` is most commonly used to turn primitive types into other primitive types, but it has other /// uses that include turning pointers into addresses, addresses into pointers, and pointers into @@ -30,6 +32,8 @@ /// `as *mut _` though the [`cast`][const-cast] method is recommended over `as *const _` and it is /// [the same][mut-cast] for `as *mut _`: those methods make the intent clearer. /// +/// # Renaming imports +/// /// `as` is also used to rename imports in [`use`] and [`extern crate`][`crate`] statements: /// /// ``` @@ -37,9 +41,34 @@ /// use std::{mem as memory, net as network}; /// // Now you can use the names `memory` and `network` to refer to `std::mem` and `std::net`. /// ``` -/// For more information on what `as` is capable of, see the [Reference]. /// -/// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions +/// # Qualifying paths +/// +/// You'll also find with `From` and `Into`, and indeed all traits, that `as` is used for the +/// _fully qualified path_, a means of disambiguating associated items, i.e. functions, +/// constants, and types. For example, if you have a type which implements two traits with identical +/// method names (e.g. `Into::::into` and `Into::::into`), you can clarify which method +/// you'll use with `>::into(my_thing)`[^as-use-from]. This is quite verbose, +/// but fortunately, Rust's type inference usually saves you from needing this, although it is +/// occasionally necessary, especially with methods that return a generic type like `Into::into` or +/// methods that don't take `self`. It's more common to use in macros where it can provide necessary +/// hygiene. +/// +/// [^as-use-from]: You should probably never use this syntax with `Into` and instead write +/// `T::from(my_thing)`. It just happens that there aren't any great examples for this syntax in +/// the standard library. Also, at time of writing, the compiler tends to suggest fully-qualified +/// paths to fix ambiguous `Into::into` calls, so the example should hopefully be familiar. +/// +/// # Further reading +/// +/// For more information on what `as` is capable of, see the Reference on [type cast expressions], +/// [renaming imported entities], [renaming `extern` crates] +/// and [qualified paths]. +/// +/// [type cast expressions]: ../reference/expressions/operator-expr.html#type-cast-expressions +/// [renaming imported entities]: https://doc.rust-lang.org/reference/items/use-declarations.html#as-renames +/// [renaming `extern` crates]: https://doc.rust-lang.org/reference/items/extern-crates.html#r-items.extern-crate.as +/// [qualified paths]: ../reference/paths.html#qualified-paths /// [`crate`]: keyword.crate.html /// [`use`]: keyword.use.html /// [const-cast]: pointer::cast From e3f104608c0ad26e80b1ebedef2ab8a748189e52 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Oct 2025 10:32:11 -0400 Subject: [PATCH 501/537] Don't normalize higher-ranked assumptions if they're not used --- .../src/traits/select/confirmation.rs | 31 ++++++----- .../higher-ranked-normalize-assumptions-2.rs | 38 ++++++++++++++ .../higher-ranked-normalize-assumptions.rs | 51 +++++++++++++++++++ 3 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 tests/ui/async-await/higher-ranked-normalize-assumptions-2.rs create mode 100644 tests/ui/async-await/higher-ranked-normalize-assumptions.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7ad65a1df8e9..708a53f6c650 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -423,19 +423,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { constituents.types, ); - // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` - // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really - // matter yet. - for assumption in constituents.assumptions { - let assumption = normalize_with_depth_to( - self, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - assumption, - &mut obligations, - ); - self.infcx.register_region_assumption(assumption); + // Only normalize these goals if `-Zhigher-ranked-assumptions` is enabled, since + // we don't want to cause ourselves to do extra work if we're not even able to + // take advantage of these assumption clauses. + if self.tcx().sess.opts.unstable_opts.higher_ranked_assumptions { + // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` + // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really + // matter yet. + for assumption in constituents.assumptions { + let assumption = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + assumption, + &mut obligations, + ); + self.infcx.register_region_assumption(assumption); + } } Ok(obligations) diff --git a/tests/ui/async-await/higher-ranked-normalize-assumptions-2.rs b/tests/ui/async-await/higher-ranked-normalize-assumptions-2.rs new file mode 100644 index 000000000000..410d4e503b7c --- /dev/null +++ b/tests/ui/async-await/higher-ranked-normalize-assumptions-2.rs @@ -0,0 +1,38 @@ +//@ revisions: stock hr +//@[hr] compile-flags: -Zhigher-ranked-assumptions +//@ edition: 2024 +//@ check-pass + +// Test that we don't normalize the higher-ranked assumptions of an auto trait goal +// unless we have `-Zhigher-ranked-assumptions`, since obligations that result from +// this normalization may lead to higher-ranked lifetime errors when the flag is not +// enabled. + +// Regression test for . + +pub fn a() -> impl Future + Send { + async { + let queries = core::iter::empty().map(Thing::f); + b(queries).await; + } +} + +async fn b(queries: impl IntoIterator) { + c(queries).await; +} + +fn c<'a, I>(_queries: I) -> impl Future +where + I: IntoIterator, + I::IntoIter: 'a, +{ + async {} +} + +pub struct Thing<'a>(pub &'a ()); + +impl Thing<'_> { + fn f(_: &Self) {} +} + +fn main() {} diff --git a/tests/ui/async-await/higher-ranked-normalize-assumptions.rs b/tests/ui/async-await/higher-ranked-normalize-assumptions.rs new file mode 100644 index 000000000000..ec9cf3a15221 --- /dev/null +++ b/tests/ui/async-await/higher-ranked-normalize-assumptions.rs @@ -0,0 +1,51 @@ +//@ revisions: stock hr +//@[hr] compile-flags: -Zhigher-ranked-assumptions +//@ edition: 2024 +//@ check-pass + +// Test that we don't normalize the higher-ranked assumptions of an auto trait goal +// unless we have `-Zhigher-ranked-assumptions`, since obligations that result from +// this normalization may lead to higher-ranked lifetime errors when the flag is not +// enabled. + +// Regression test for . + +pub trait Service { + type Response; +} + +impl Service for T +where + T: FnMut() -> R, + R: 'static, +{ + type Response = R; +} + +async fn serve(_: C) +where + C: Service, + C::Response: 'static, +{ + connect::().await; +} + +async fn connect() +where + C: Service, + C::Response: 'static, +{ +} + +fn repro() -> impl Send { + async { + let server = || do_something(); + serve(server).await; + } +} + +fn do_something() -> Box { + unimplemented!() +} + +fn main() {} From e914a1a6e026d2c9db43300735a75ba25746e14c Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 3 Oct 2025 11:57:04 +0200 Subject: [PATCH 502/537] Respect `--error-format` in `rustdoc --test` --- src/librustdoc/doctest.rs | 1 + tests/rustdoc-ui/doctest/check-attr-test.rs | 12 ++++++++++ .../rustdoc-ui/doctest/check-attr-test.stderr | 24 +++++++++---------- .../failed-doctest-extra-semicolon-on-item.rs | 1 + .../doctest/main-alongside-stmts.rs | 2 ++ .../doctest/main-alongside-stmts.stderr | 8 +++---- .../doctest/main-alongside-stmts.stdout | 4 ++-- .../doctest/standalone-warning-2024.rs | 2 ++ .../doctest/standalone-warning-2024.stderr | 12 +++++----- .../rustdoc-ui/doctest/test-compile-fail1.rs | 1 + .../rustdoc-ui/doctest/test-compile-fail2.rs | 1 + .../rustdoc-ui/doctest/test-compile-fail3.rs | 1 + .../doctest/test-compile-fail3.stderr | 5 ++-- .../doctest/warn-main-not-called.rs | 2 ++ .../doctest/warn-main-not-called.stderr | 4 ++-- 15 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 38a0c925d2a4..27761511038e 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -174,6 +174,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions crate_name: options.crate_name.clone(), remap_path_prefix: options.remap_path_prefix.clone(), unstable_opts: options.unstable_opts.clone(), + error_format: options.error_format.clone(), ..config::Options::default() }; diff --git a/tests/rustdoc-ui/doctest/check-attr-test.rs b/tests/rustdoc-ui/doctest/check-attr-test.rs index 81281db624b3..d69dae63860e 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.rs +++ b/tests/rustdoc-ui/doctest/check-attr-test.rs @@ -2,6 +2,9 @@ #![deny(rustdoc::invalid_codeblock_attributes)] +//~vvv ERROR unknown attribute `compile-fail` +//~| ERROR unknown attribute `compilefail` +//~| ERROR unknown attribute `comPile_fail` /// foo /// /// ```compile-fail,compilefail,comPile_fail @@ -9,6 +12,9 @@ /// ``` pub fn foo() {} +//~vvv ERROR unknown attribute `should-panic` +//~| ERROR unknown attribute `shouldpanic` +//~| ERROR unknown attribute `shOuld_panic` /// bar /// /// ```should-panic,shouldpanic,shOuld_panic @@ -16,6 +22,9 @@ pub fn foo() {} /// ``` pub fn bar() {} +//~vvv ERROR unknown attribute `no-run` +//~| ERROR unknown attribute `norun` +//~| ERROR unknown attribute `nO_run` /// foobar /// /// ```no-run,norun,nO_run @@ -23,6 +32,9 @@ pub fn bar() {} /// ``` pub fn foobar() {} +//~vvv ERROR unknown attribute `test-harness` +//~| ERROR unknown attribute `testharness` +//~| ERROR unknown attribute `tesT_harness` /// b /// /// ```test-harness,testharness,tesT_harness diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr index 4cf93033ae8a..1fc7ab592de0 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.stderr +++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr @@ -1,5 +1,5 @@ error: unknown attribute `compile-fail` - --> $DIR/check-attr-test.rs:5:1 + --> $DIR/check-attr-test.rs:8:1 | LL | / /// foo LL | | /// @@ -17,7 +17,7 @@ LL | #![deny(rustdoc::invalid_codeblock_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unknown attribute `compilefail` - --> $DIR/check-attr-test.rs:5:1 + --> $DIR/check-attr-test.rs:8:1 | LL | / /// foo LL | | /// @@ -30,7 +30,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` - --> $DIR/check-attr-test.rs:5:1 + --> $DIR/check-attr-test.rs:8:1 | LL | / /// foo LL | | /// @@ -43,7 +43,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` - --> $DIR/check-attr-test.rs:12:1 + --> $DIR/check-attr-test.rs:18:1 | LL | / /// bar LL | | /// @@ -56,7 +56,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shouldpanic` - --> $DIR/check-attr-test.rs:12:1 + --> $DIR/check-attr-test.rs:18:1 | LL | / /// bar LL | | /// @@ -69,7 +69,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shOuld_panic` - --> $DIR/check-attr-test.rs:12:1 + --> $DIR/check-attr-test.rs:18:1 | LL | / /// bar LL | | /// @@ -82,7 +82,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no-run` - --> $DIR/check-attr-test.rs:19:1 + --> $DIR/check-attr-test.rs:28:1 | LL | / /// foobar LL | | /// @@ -95,7 +95,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `norun` - --> $DIR/check-attr-test.rs:19:1 + --> $DIR/check-attr-test.rs:28:1 | LL | / /// foobar LL | | /// @@ -108,7 +108,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `nO_run` - --> $DIR/check-attr-test.rs:19:1 + --> $DIR/check-attr-test.rs:28:1 | LL | / /// foobar LL | | /// @@ -121,7 +121,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `test-harness` - --> $DIR/check-attr-test.rs:26:1 + --> $DIR/check-attr-test.rs:38:1 | LL | / /// b LL | | /// @@ -134,7 +134,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `testharness` - --> $DIR/check-attr-test.rs:26:1 + --> $DIR/check-attr-test.rs:38:1 | LL | / /// b LL | | /// @@ -147,7 +147,7 @@ LL | | /// ``` = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `tesT_harness` - --> $DIR/check-attr-test.rs:26:1 + --> $DIR/check-attr-test.rs:38:1 | LL | / /// b LL | | /// diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs index ca5dd7874678..05e4a348d119 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs @@ -9,6 +9,7 @@ /// /// /// ```rust +//~^ WARN the `main` function of this doctest won't be run /// struct S {}; /// /// fn main() { diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.rs b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs index 5965f928cdd1..595de1339329 100644 --- a/tests/rustdoc-ui/doctest/main-alongside-stmts.rs +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs @@ -14,6 +14,7 @@ //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ check-pass +//~v WARN the `main` function of this doctest won't be run //! ``` //! # if cfg!(miri) { return; } //! use std::ops::Deref; @@ -22,6 +23,7 @@ //! assert!(false); //! } //! ``` +//~v WARN the `main` function of this doctest won't be run //! //! ``` //! let x = 2; diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr index 3f347d96ab06..b7a5421f8f73 100644 --- a/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr @@ -1,14 +1,14 @@ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function - --> $DIR/main-alongside-stmts.rs:17:1 + --> $DIR/main-alongside-stmts.rs:18:1 | LL | //! ``` | ^^^^^^^ warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function - --> $DIR/main-alongside-stmts.rs:26:1 + --> $DIR/main-alongside-stmts.rs:27:1 | -LL | //! ``` - | ^^^^^^^ +LL | //! + | ^^^ warning: 2 warnings emitted diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout index 9b9a3fe8a68f..bebaeb49c5a9 100644 --- a/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout @@ -1,7 +1,7 @@ running 2 tests -test $DIR/main-alongside-stmts.rs - (line 17) ... ok -test $DIR/main-alongside-stmts.rs - (line 26) ... ok +test $DIR/main-alongside-stmts.rs - (line 18) ... ok +test $DIR/main-alongside-stmts.rs - (line 27) ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs index c53a8b48749c..3bb0083d849f 100644 --- a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs @@ -9,6 +9,8 @@ #![deny(warnings)] //! ```standalone +//~^ ERROR unknown attribute `standalone` +//~| ERROR unknown attribute `standalone-crate` //! bla //! ``` //! diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr index 1af2ded58e8b..db0d53a204ce 100644 --- a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr @@ -2,10 +2,10 @@ error: unknown attribute `standalone` --> $DIR/standalone-warning-2024.rs:11:1 | LL | / //! ```standalone +LL | | +LL | | LL | | //! bla -LL | | //! ``` -LL | | //! -LL | | //! ```standalone-crate +... | LL | | //! bla LL | | //! ``` | |_______^ @@ -23,10 +23,10 @@ error: unknown attribute `standalone-crate` --> $DIR/standalone-warning-2024.rs:11:1 | LL | / //! ```standalone +LL | | +LL | | LL | | //! bla -LL | | //! ``` -LL | | //! -LL | | //! ```standalone-crate +... | LL | | //! bla LL | | //! ``` | |_______^ diff --git a/tests/rustdoc-ui/doctest/test-compile-fail1.rs b/tests/rustdoc-ui/doctest/test-compile-fail1.rs index 278f01f4c838..c692c4c61bcc 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail1.rs +++ b/tests/rustdoc-ui/doctest/test-compile-fail1.rs @@ -6,3 +6,4 @@ pub fn f() {} pub fn f() {} +//~^ ERROR the name `f` is defined multiple times diff --git a/tests/rustdoc-ui/doctest/test-compile-fail2.rs b/tests/rustdoc-ui/doctest/test-compile-fail2.rs index 7432cc9f8263..8239440262d8 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail2.rs +++ b/tests/rustdoc-ui/doctest/test-compile-fail2.rs @@ -1,3 +1,4 @@ //@ compile-flags:--test fail +//~^ ERROR diff --git a/tests/rustdoc-ui/doctest/test-compile-fail3.rs b/tests/rustdoc-ui/doctest/test-compile-fail3.rs index a2486d9dc6f2..272ba95396c6 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail3.rs +++ b/tests/rustdoc-ui/doctest/test-compile-fail3.rs @@ -1,3 +1,4 @@ //@ compile-flags:--test "fail +//~^ ERROR diff --git a/tests/rustdoc-ui/doctest/test-compile-fail3.stderr b/tests/rustdoc-ui/doctest/test-compile-fail3.stderr index 9f90a428d480..8061097e73ac 100644 --- a/tests/rustdoc-ui/doctest/test-compile-fail3.stderr +++ b/tests/rustdoc-ui/doctest/test-compile-fail3.stderr @@ -1,8 +1,9 @@ error[E0765]: unterminated double quote string --> $DIR/test-compile-fail3.rs:3:1 | -LL | "fail - | ^^^^^ +LL | / "fail +LL | | + | |___________^ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.rs b/tests/rustdoc-ui/doctest/warn-main-not-called.rs index 25d92e9cee9f..ec762486d5d4 100644 --- a/tests/rustdoc-ui/doctest/warn-main-not-called.rs +++ b/tests/rustdoc-ui/doctest/warn-main-not-called.rs @@ -8,6 +8,7 @@ // won't be called. //! ``` +//~^ WARN the `main` function of this doctest won't be run //! macro_rules! bla { //! ($($x:tt)*) => {} //! } @@ -17,6 +18,7 @@ //! ``` //! //! ``` +//~^^ WARN the `main` function of this doctest won't be run //! let x = 12; //! fn main() {} //! ``` diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.stderr b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr index b5b7bc57644a..5feca6f9175f 100644 --- a/tests/rustdoc-ui/doctest/warn-main-not-called.stderr +++ b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr @@ -7,8 +7,8 @@ LL | //! ``` warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function --> $DIR/warn-main-not-called.rs:19:1 | -LL | //! ``` - | ^^^^^^^ +LL | //! + | ^^^ warning: 2 warnings emitted From c1443e2591c284f6ac8372d15c88f8d6c9470e4c Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 3 Oct 2025 12:02:35 +0200 Subject: [PATCH 503/537] Add regression test for `-Zcrate-attr` in `rustdoc --test` --- .../rustdoc-ui/doctest/unstable-opts-143930.rs | 14 ++++++++++++++ .../doctest/unstable-opts-143930.stdout | 5 +++++ .../unstable-opts-147276.crate_attr.stdout | 5 +++++ .../doctest/unstable-opts-147276.normal.stderr | 13 +++++++++++++ .../rustdoc-ui/doctest/unstable-opts-147276.rs | 17 +++++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/unstable-opts-143930.rs create mode 100644 tests/rustdoc-ui/doctest/unstable-opts-143930.stdout create mode 100644 tests/rustdoc-ui/doctest/unstable-opts-147276.crate_attr.stdout create mode 100644 tests/rustdoc-ui/doctest/unstable-opts-147276.normal.stderr create mode 100644 tests/rustdoc-ui/doctest/unstable-opts-147276.rs diff --git a/tests/rustdoc-ui/doctest/unstable-opts-143930.rs b/tests/rustdoc-ui/doctest/unstable-opts-143930.rs new file mode 100644 index 000000000000..30c47f5b7e9e --- /dev/null +++ b/tests/rustdoc-ui/doctest/unstable-opts-143930.rs @@ -0,0 +1,14 @@ +// This test verifies that unstable options like `-Zcrate-attr` are respected when `--test` is +// passed. +// +// +// +// NOTE: If any of these command line arguments or features get stabilized, please replace with +// another unstable one. + +//@ check-pass +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ compile-flags: --test -Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(rapx) + +#[rapx::tag] +fn f() {} diff --git a/tests/rustdoc-ui/doctest/unstable-opts-143930.stdout b/tests/rustdoc-ui/doctest/unstable-opts-143930.stdout new file mode 100644 index 000000000000..7326c0a25a06 --- /dev/null +++ b/tests/rustdoc-ui/doctest/unstable-opts-143930.stdout @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/unstable-opts-147276.crate_attr.stdout b/tests/rustdoc-ui/doctest/unstable-opts-147276.crate_attr.stdout new file mode 100644 index 000000000000..7326c0a25a06 --- /dev/null +++ b/tests/rustdoc-ui/doctest/unstable-opts-147276.crate_attr.stdout @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/unstable-opts-147276.normal.stderr b/tests/rustdoc-ui/doctest/unstable-opts-147276.normal.stderr new file mode 100644 index 000000000000..eebf4f307f12 --- /dev/null +++ b/tests/rustdoc-ui/doctest/unstable-opts-147276.normal.stderr @@ -0,0 +1,13 @@ +error[E0658]: `#[used(linker)]` is currently unstable + --> $DIR/unstable-opts-147276.rs:15:1 + | +LL | #[used(linker)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #93798 for more information + = help: add `#![feature(used_with_arg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/rustdoc-ui/doctest/unstable-opts-147276.rs b/tests/rustdoc-ui/doctest/unstable-opts-147276.rs new file mode 100644 index 000000000000..64cafcaaff4e --- /dev/null +++ b/tests/rustdoc-ui/doctest/unstable-opts-147276.rs @@ -0,0 +1,17 @@ +// This test verifies that unstable options like `-Zcrate-attr` are respected when `--test` is +// passed. +// +// +// +// NOTE: If any of these command line arguments or features get stabilized, please replace with +// another unstable one. + +//@ revisions: normal crate_attr +//@ compile-flags: --test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@[crate_attr] check-pass +//@[crate_attr] compile-flags: -Zcrate-attr=feature(used_with_arg) + +#[used(linker)] +//[normal]~^ ERROR `#[used(linker)]` is currently unstable +static REPRO: isize = 1; From 3f9c493da1fa46ff0ef6d23e60a37c89ef3f5933 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 3 Oct 2025 16:10:26 +0100 Subject: [PATCH 504/537] Add xtensa arch to object file creation --- compiler/rustc_target/src/spec/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4a82a8bd888e..2f7109de804a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3182,6 +3182,7 @@ impl Target { "avr" => (Architecture::Avr, None), "msp430" => (Architecture::Msp430, None), "hexagon" => (Architecture::Hexagon, None), + "xtensa" => (Architecture::Xtensa, None), "bpf" => (Architecture::Bpf, None), "loongarch32" => (Architecture::LoongArch32, None), "loongarch64" => (Architecture::LoongArch64, None), From e43a0b6bdbdf5a4bab5be6b925698971c55dae1a Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 3 Oct 2025 11:58:30 -0400 Subject: [PATCH 505/537] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index f2932725b045..2394ea6cea8b 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit f2932725b045d361ff5f18ba02b1409dd1f44e71 +Subproject commit 2394ea6cea8b26d717aa67eb1663a2dbf2d26078 From 58889457cac8225e6bae4855ca1911dd0a378f65 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Aug 2025 16:08:14 +0200 Subject: [PATCH 506/537] Display merged doctests times as expected depending on the format specified --- src/librustdoc/doctest.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9499258f983a..5ea3ede78bc4 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -12,7 +12,7 @@ use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use std::{fmt, panic, str}; +use std::{panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; @@ -60,24 +60,15 @@ impl MergedDoctestTimes { self.added_compilation_times += 1; } - fn display_times(&self) { + /// Returns `(total_time, compilation_time)`. + fn times_in_secs(&self) -> Option<(f64, f64)> { // If no merged doctest was compiled, then there is nothing to display since the numbers // displayed by `libtest` for standalone tests are already accurate (they include both // compilation and runtime). - if self.added_compilation_times > 0 { - println!("{self}"); + if self.added_compilation_times == 0 { + return None; } - } -} - -impl fmt::Display for MergedDoctestTimes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "all doctests ran in {:.2}s; merged doctests compilation took {:.2}s", - self.total_time.elapsed().as_secs_f64(), - self.compilation_time.as_secs_f64(), - ) + Some((self.total_time.elapsed().as_secs_f64(), self.compilation_time.as_secs_f64())) } } @@ -400,15 +391,20 @@ pub(crate) fn run_tests( if ran_edition_tests == 0 || !standalone_tests.is_empty() { standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice())); test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { + let times = times.times_in_secs(); // We ensure temp dir destructor is called. std::mem::drop(temp_dir.take()); - times.display_times(); + if let Some((total_time, compilation_time)) = times { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } }); } else { // If the first condition branch exited successfully, `test_main_with_exit_callback` will // not exit the process. So to prevent displaying the times twice, we put it behind an // `else` condition. - times.display_times(); + if let Some((total_time, compilation_time)) = times.times_in_secs() { + test::print_merged_doctests_times(&test_args, total_time, compilation_time); + } } // We ensure temp dir destructor is called. std::mem::drop(temp_dir); From a9ab29cdb45005d69738c3a7cbec4c5cd0fceb73 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Fri, 12 Sep 2025 13:10:01 -0400 Subject: [PATCH 507/537] add mem::conjure_zst --- library/core/src/mem/mod.rs | 58 ++++++++++++++++++++++++++ tests/ui/consts/std/conjure_zst.rs | 10 +++++ tests/ui/consts/std/conjure_zst.stderr | 12 ++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/ui/consts/std/conjure_zst.rs create mode 100644 tests/ui/consts/std/conjure_zst.stderr diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index db4c8e9e5515..c484551187cc 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -7,6 +7,7 @@ use crate::alloc::Layout; use crate::marker::DiscriminantKind; +use crate::panic::const_assert; use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; mod manually_drop; @@ -1407,3 +1408,60 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { // The `{}` is for better error messages {builtin # offset_of($Container, $($fields)+)} } + +/// Create a fresh instance of the inhabited ZST type `T`. +/// +/// Prefer this to [`zeroed`] or [`uninitialized`] or [`transmute_copy`] +/// in places where you know that `T` is zero-sized, but don't have a bound +/// (such as [`Default`]) that would allow you to instantiate it using safe code. +/// +/// If you're not sure whether `T` is an inhabited ZST, then you should be +/// using [`MaybeUninit`], not this function. +/// +/// # Panics +/// +/// If `size_of::() != 0`. +/// +/// # Safety +/// +/// - `T` must be *[inhabited]*, i.e. possible to construct. This means that types +/// like zero-variant enums and [`!`] are unsound to conjure. +/// - You must use the value only in ways which do not violate any *safety* +/// invariants of the type. +/// +/// While it's easy to create a *valid* instance of an inhabited ZST, since having +/// no bits in its representation means there's only one possible value, that +/// doesn't mean that it's always *sound* to do so. +/// +/// For example, a library could design zero-sized tokens that are `!Default + !Clone`, limiting +/// their creation to functions that initialize some state or establish a scope. Conjuring such a +/// token could break invariants and lead to unsoundness. +/// +/// # Examples +/// +/// ``` +/// #![feature(mem_conjure_zst)] +/// use std::mem::conjure_zst; +/// +/// assert_eq!(unsafe { conjure_zst::<()>() }, ()); +/// assert_eq!(unsafe { conjure_zst::<[i32; 0]>() }, []); +/// ``` +/// +/// [inhabited]: https://doc.rust-lang.org/reference/glossary.html#inhabited +#[unstable(feature = "mem_conjure_zst", issue = "95383")] +pub const unsafe fn conjure_zst() -> T { + const_assert!( + size_of::() == 0, + "mem::conjure_zst invoked on a nonzero-sized type", + "mem::conjure_zst invoked on type {t}, which is not zero-sized", + t: &str = stringify!(T) + ); + + // SAFETY: because the caller must guarantee that it's inhabited and zero-sized, + // there's nothing in the representation that needs to be set. + // `assume_init` calls `assert_inhabited`, so we don't need to here. + unsafe { + #[allow(clippy::uninit_assumed_init)] + MaybeUninit::uninit().assume_init() + } +} diff --git a/tests/ui/consts/std/conjure_zst.rs b/tests/ui/consts/std/conjure_zst.rs new file mode 100644 index 000000000000..c04deae502b0 --- /dev/null +++ b/tests/ui/consts/std/conjure_zst.rs @@ -0,0 +1,10 @@ +#![feature(mem_conjure_zst)] + +use std::{convert::Infallible, mem}; + +const INVALID: Infallible = unsafe { mem::conjure_zst() }; +//~^ ERROR attempted to instantiate uninhabited type + +const VALID: () = unsafe { mem::conjure_zst() }; + +fn main() {} diff --git a/tests/ui/consts/std/conjure_zst.stderr b/tests/ui/consts/std/conjure_zst.stderr new file mode 100644 index 000000000000..0c4a978b81ee --- /dev/null +++ b/tests/ui/consts/std/conjure_zst.stderr @@ -0,0 +1,12 @@ +error[E0080]: evaluation panicked: aborted execution: attempted to instantiate uninhabited type `Infallible` + --> $DIR/conjure_zst.rs:5:38 + | +LL | const INVALID: Infallible = unsafe { mem::conjure_zst() }; + | ^^^^^^^^^^^^^^^^^^ evaluation of `INVALID` failed inside this call + | +note: inside `conjure_zst::` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From d5ba5c1c925f82de2efbfbbe92ffee56a6a6a334 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 3 Oct 2025 16:00:15 -0400 Subject: [PATCH 508/537] Mark `PatternTypo` suggestion as maybe incorrect --- compiler/rustc_passes/src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f0726014e0af..e01e9e384c03 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1365,7 +1365,7 @@ pub(crate) struct UnusedVarAssignedOnly { #[multipart_suggestion( passes_unused_var_typo, style = "verbose", - applicability = "machine-applicable" + applicability = "maybe-incorrect" )] pub(crate) struct PatternTypo { #[suggestion_part(code = "{code}")] From fd96a78092e77be45d5b60cedea0806b70d751fd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 3 Oct 2025 12:14:41 -0700 Subject: [PATCH 509/537] Add documentation about unwinding to wasm targets This commit adds some documentation about the state of `-Cpanic=unwind` for the following wasm targets: * `wasm32-unknown-unknown` * `wasm32-wasip1` * `wasm32-wasip2` * `wasm32v1-none` Notably it's possible to use `-Cpanic=unwind` with `-Zbuild-std` and it's also mentioned that there are no concrete proposals at this time to adding a new set of targets which support unwinding. My hunch is that in a few years' time it would make sense to enable it by default on these targets (except for `wasm32v1-none`) but that's a problem for future folks to debate. For now this is an attempt to document the status quo. --- .../wasm32-unknown-unknown.md | 62 ++++++++++++++++++- .../src/platform-support/wasm32-wasip1.md | 6 ++ .../src/platform-support/wasm32-wasip2.md | 6 ++ .../src/platform-support/wasm32v1-none.md | 11 ++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index 1e74c47221c7..ec20672f6540 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -157,7 +157,7 @@ $ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unkno ``` Here the `mvp` "cpu" is a placeholder in LLVM for disabling all supported -features by default. Cargo's `-Zbuild-std` feature, a Nightly Rust feature, is +features by default. Cargo's [`-Zbuild-std`] feature, a Nightly Rust feature, is then used to recompile the standard library in addition to your own code. This will produce a binary that uses only the original WebAssembly features by default and no proposals since its inception. @@ -207,3 +207,63 @@ conditionally compile code instead. This is notably different to the way native platforms such as x86\_64 work, and this is due to the fact that WebAssembly binaries must only contain code the engine understands. Native binaries work so long as the CPU doesn't execute unknown code dynamically at runtime. + +## Unwinding + +By default the `wasm32-unknown-unknown` target is compiled with `-Cpanic=abort`. +Historically this was due to the fact that there was no way to catch panics in +wasm, but since mid-2025 the WebAssembly [`exception-handling` +proposal](https://github.com/WebAssembly/exception-handling) reached +stabilization. LLVM has support for this proposal as well and when this is all +combined together it's possible to enable `-Cpanic=unwind` on wasm targets. + +Compiling wasm targets with `-Cpanic=unwind` is not as easy as just passing +`-Cpanic=unwind`, however: + +```sh +$ rustc foo.rs -Cpanic=unwind --target wasm32-unknown-unknown +error: the crate `panic_unwind` does not have the panic strategy `unwind` +``` + +Notably the precompiled standard library that is shipped through Rustup is +compiled with `-Cpanic=abort`, not `-Cpanic=unwind`. While this is the case +you're going to be required to use Cargo's [`-Zbuild-std`] feature to build with +unwinding support: + +```sh +$ RUSTFLAGS='-Cpanic=unwind' cargo +nightly build --target wasm32-unknown-unknown -Zbuild-std +``` + +Note, however, that as of 2025-10-03 LLVM is still using the "legacy exception +instructions" by default, not the officially standard version of the +exception-handling proposal: + +```sh +$ wasm-tools validate target/wasm32-unknown-unknown/debug/foo.wasm +error: /library/std/src/sys/backtrace.rs:161:5 +function `std::sys::backtrace::__rust_begin_short_backtrace` failed to validate + +Caused by: + 0: func 2 failed to validate + 1: legacy_exceptions feature required for try instruction (at offset 0x880) +``` + +Fixing this requires passing `-Cllvm-args=-wasm-use-legacy-eh=false` to the Rust +compiler as well: + +```sh +$ RUSTFLAGS='-Cpanic=unwind -Cllvm-args=-wasm-use-legacy-eh=false' cargo +nightly build --target wasm32-unknown-unknown -Zbuild-std +$ wasm-tools validate target/wasm32-unknown-unknown/debug/foo.wasm +``` + +At this time there are no concrete plans for adding new targets to the Rust +compiler which have `-Cpanic=unwind` enabled-by-default. The most likely route +to having this enabled is that in a few years when the `exception-handling` +target feature is enabled by default in LLVM (due to browsers/runtime support +propagating widely enough) the targets will switch to using `-Cpanic=unwind` by +default. This is not for certain, however, and will likely be accompanied with +either an MCP or an RFC about changing all wasm targets in the same manner. In +the meantime using `-Cpanic=unwind` will require using [`-Zbuild-std`] and +passing the appropriate flags to rustc. + +[`-Zbuild-std`]: ../../cargo/reference/unstable.html#build-std diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index a8a9e5505810..958a34a86928 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -133,3 +133,9 @@ to Rust 1.80 the `target_env` condition was not set. The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. + +## Unwinding + +This target is compiled with `-Cpanic=abort` by default. For information on +using `-Cpanic=unwind` see the [documentation about unwinding for +`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding). diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index dea33e62f2b4..861083ad4a61 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -67,3 +67,9 @@ It's recommended to conditionally compile code for this target with: The default set of WebAssembly features enabled for compilation is currently the same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the documentation there for more information. + +## Unwinding + +This target is compiled with `-Cpanic=abort` by default. For information on +using `-Cpanic=unwind` see the [documentation about unwinding for +`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding). diff --git a/src/doc/rustc/src/platform-support/wasm32v1-none.md b/src/doc/rustc/src/platform-support/wasm32v1-none.md index 51b00de5e578..d2f9b3a1f976 100644 --- a/src/doc/rustc/src/platform-support/wasm32v1-none.md +++ b/src/doc/rustc/src/platform-support/wasm32v1-none.md @@ -107,3 +107,14 @@ $ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unkno Which not only rebuilds `std`, `core` and `alloc` (which is somewhat costly and annoying) but more importantly requires the use of nightly Rust toolchains (for the `-Zbuild-std` flag). This is very undesirable for the target audience, which consists of people targeting WebAssembly implementations that prioritize stability, simplicity and/or security over feature support. This `wasm32v1-none` target exists as an alternative option that works on stable Rust toolchains, without rebuilding the stdlib. + +## Unwinding + +This target is compiled with `-Cpanic=abort` by default. Using `-Cpanic=unwind` +would require using the WebAssembly exception-handling proposal stabilized +mid-2025, and if that's desired then you most likely don't want to use this +target and instead want to use `wasm32-unknown-unknown` instead. It's unlikely +that this target will ever support unwinding with the precompiled artifacts +shipped through rustup. For documentation about using `-Zbuild-std` to enable +using `-Cpanic=unwind` see the [documentation of +`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding). From 55aeb1747d97b70c75220ade6cdc53523886defd Mon Sep 17 00:00:00 2001 From: jackh726 Date: Thu, 2 Oct 2025 00:51:44 +0000 Subject: [PATCH 510/537] Do not assert that a change in global cache only happens when concurrent --- compiler/rustc_middle/src/ty/context.rs | 5 +- compiler/rustc_type_ir/src/interner.rs | 8 +-- .../src/search_graph/global_cache.rs | 4 +- .../rustc_type_ir/src/search_graph/mod.rs | 2 +- ...rted.stderr => unsupported.current.stderr} | 28 +++++----- tests/ui/delegation/unsupported.next.stderr | 51 +++++++++++++++++++ tests/ui/delegation/unsupported.rs | 8 +++ 7 files changed, 84 insertions(+), 22 deletions(-) rename tests/ui/delegation/{unsupported.stderr => unsupported.current.stderr} (76%) create mode 100644 tests/ui/delegation/unsupported.next.stderr diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7d3e2c9965da..9a0d2602a5f1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -207,8 +207,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { from_entry(entry) } - fn evaluation_is_concurrent(&self) -> bool { - self.sess.threads() > 1 + fn assert_evaluation_is_concurrent(&self) { + // Turns out, the assumption for this function isn't perfect. + // See trait-system-refactor-initiative#234. } fn expand_abstract_consts>>(self, t: T) -> T { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cf58aec14a68..f12dcbfef98b 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -185,7 +185,9 @@ pub trait Interner: from_entry: impl FnOnce(&CanonicalParamEnvCacheEntry) -> R, ) -> R; - fn evaluation_is_concurrent(&self) -> bool; + /// Useful for testing. If a cache entry is replaced, this should + /// (in theory) only happen when concurrent. + fn assert_evaluation_is_concurrent(&self); fn expand_abstract_consts>(self, t: T) -> T; @@ -569,7 +571,7 @@ impl search_graph::Cx for I { fn with_global_cache(self, f: impl FnOnce(&mut search_graph::GlobalCache) -> R) -> R { I::with_global_cache(self, f) } - fn evaluation_is_concurrent(&self) -> bool { - self.evaluation_is_concurrent() + fn assert_evaluation_is_concurrent(&self) { + self.assert_evaluation_is_concurrent() } } diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index eb56c1af408b..7e438fefffca 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -56,13 +56,13 @@ impl GlobalCache { let with_overflow = WithOverflow { nested_goals, result }; let prev = entry.with_overflow.insert(required_depth, with_overflow); if let Some(prev) = &prev { - assert!(cx.evaluation_is_concurrent()); + cx.assert_evaluation_is_concurrent(); assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result); } } else { let prev = entry.success.replace(Success { required_depth, nested_goals, result }); if let Some(prev) = &prev { - assert!(cx.evaluation_is_concurrent()); + cx.assert_evaluation_is_concurrent(); assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result); } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8f8f019510fe..d7f91ef692c5 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -53,7 +53,7 @@ pub trait Cx: Copy { fn with_global_cache(self, f: impl FnOnce(&mut GlobalCache) -> R) -> R; - fn evaluation_is_concurrent(&self) -> bool; + fn assert_evaluation_is_concurrent(&self); } pub trait Delegate: Sized { diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.current.stderr similarity index 76% rename from tests/ui/delegation/unsupported.stderr rename to tests/ui/delegation/unsupported.current.stderr index f69be60133e2..55564e8f231f 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -1,43 +1,43 @@ -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:22:25 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:22:25 + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:22:25 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:25:24 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:25:24 + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:25:24 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/unsupported.rs:38:22 + --> $DIR/unsupported.rs:46:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -46,7 +46,7 @@ LL | reuse to_reuse1::foo; | ^^^ error[E0283]: type annotations needed - --> $DIR/unsupported.rs:48:18 + --> $DIR/unsupported.rs:56:18 | LL | reuse Trait::foo; | ^^^ cannot infer type diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr new file mode 100644 index 000000000000..606a25d4269a --- /dev/null +++ b/tests/ui/delegation/unsupported.next.stderr @@ -0,0 +1,51 @@ +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:30:25 + | +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle + = note: cycle used when computing implied outlives bounds for `::opaque_ret::{anon_assoc#0}` (hack disabled = false) + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/unsupported.rs:33:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle + = note: cycle used when computing implied outlives bounds for `::opaque_ret::{anon_assoc#0}` (hack disabled = false) + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: recursive delegation is not supported yet + --> $DIR/unsupported.rs:46:22 + | +LL | pub reuse to_reuse2::foo; + | --- callee defined here +... +LL | reuse to_reuse1::foo; + | ^^^ + +error[E0283]: type annotations needed + --> $DIR/unsupported.rs:56:18 + | +LL | reuse Trait::foo; + | ^^^ cannot infer type + | + = note: cannot satisfy `_: effects::Trait` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0283, E0391. +For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index af1c20976d7a..79bab342da09 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -1,3 +1,11 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-fail + +// Next solver revision included because of trait-system-refactor-initiative#234. +// If we end up in a query cycle, it should be okay as long as results are the same. + #![feature(const_trait_impl)] #![feature(c_variadic)] #![feature(fn_delegation)] From c721fa243825255c0f195d4282021e7c263c3e7f Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 28 Sep 2025 03:21:45 +0000 Subject: [PATCH 511/537] interpret #[used] as #[used(compiler)] on illumos illumos' `ld` does not support a flag like either SHF_GNU_RETAIN or SHF_SUNW_NODISCARD, so there is no way to communicate `#[used(linker)]` for that target. Setting `USED_LINKER` to try results in LLVM setting SHF_SUNW_NODISCARD for Solaris-like targets, which is an unknown section header flag for illumos `ld` and prevents sections from being merged that otherwise would. As a motivating example, the `inventory` crate produces `#[used]` items to merge into `.init_array`. Because those items have an unknown section header flag they are not merged with the default `.init_array` with `frame_dummy`, and end up never executed. Downgrading `#[used]` to `#[used(compiler)]` on illumos keeps so-attributed items as preserved as they had been before https://github.com/rust-lang/rust/pull/140872. As was the case before that change, because rustc passes `-z ignore` to illumos `ld`, it's possible that `used` sections are GC'd at link time. https://github.com/rust-lang/rust/issues/146169 describes this unfortunate circumstance. --- .../src/attributes/codegen_attrs.rs | 36 ++++++++++++++----- .../rustc_codegen_ssa/src/codegen_attrs.rs | 13 +++++++ .../rustc_hir/src/attrs/data_structures.rs | 3 +- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 262b8213977b..7978bf28214c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -370,6 +370,7 @@ impl NoArgsAttributeParser for NoMangleParser { pub(crate) struct UsedParser { first_compiler: Option, first_linker: Option, + first_default: Option, } // A custom `AttributeParser` is used rather than a Simple attribute parser because @@ -382,7 +383,7 @@ impl AttributeParser for UsedParser { template!(Word, List: &["compiler", "linker"]), |group: &mut Self, cx, args| { let used_by = match args { - ArgParser::NoArgs => UsedBy::Linker, + ArgParser::NoArgs => UsedBy::Default, ArgParser::List(list) => { let Some(l) = list.single() else { cx.expected_single_argument(list.span); @@ -423,12 +424,29 @@ impl AttributeParser for UsedParser { ArgParser::NameValue(_) => return, }; + let attr_span = cx.attr_span; + + // `#[used]` is interpreted as `#[used(linker)]` (though depending on target OS the + // circumstances are more complicated). While we're checking `used_by`, also report + // these cross-`UsedBy` duplicates to warn. let target = match used_by { UsedBy::Compiler => &mut group.first_compiler, - UsedBy::Linker => &mut group.first_linker, + UsedBy::Linker => { + if let Some(prev) = group.first_default { + cx.warn_unused_duplicate(prev, attr_span); + return; + } + &mut group.first_linker + } + UsedBy::Default => { + if let Some(prev) = group.first_linker { + cx.warn_unused_duplicate(prev, attr_span); + return; + } + &mut group.first_default + } }; - let attr_span = cx.attr_span; if let Some(prev) = *target { cx.warn_unused_duplicate(prev, attr_span); } else { @@ -440,11 +458,13 @@ impl AttributeParser for UsedParser { AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { - // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` - Some(match (self.first_compiler, self.first_linker) { - (_, Some(span)) => AttributeKind::Used { used_by: UsedBy::Linker, span }, - (Some(span), _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, - (None, None) => return None, + // If a specific form of `used` is specified, it takes precedence over generic `#[used]`. + // If both `linker` and `compiler` are specified, use `linker`. + Some(match (self.first_compiler, self.first_linker, self.first_default) { + (_, Some(span), _) => AttributeKind::Used { used_by: UsedBy::Linker, span }, + (Some(span), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler, span }, + (_, _, Some(span)) => AttributeKind::Used { used_by: UsedBy::Default, span }, + (None, None, None) => return None, }) } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 32ae810ecc89..2c7643e46cea 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -263,6 +263,19 @@ fn process_builtin_attrs( AttributeKind::Used { used_by, .. } => match used_by { UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, + UsedBy::Default => { + let used_form = if tcx.sess.target.os == "illumos" { + // illumos' `ld` doesn't support a section header that would represent + // `#[used(linker)]`, see + // https://github.com/rust-lang/rust/issues/146169. For that target, + // downgrade as if `#[used(compiler)]` was requested and hope for the + // best. + CodegenFnAttrFlags::USED_COMPILER + } else { + CodegenFnAttrFlags::USED_LINKER + }; + codegen_fn_attrs.flags |= used_form; + } }, AttributeKind::FfiConst(_) => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index ddcbaeaad880..beeca7332cb1 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -146,12 +146,13 @@ impl Deprecation { } /// There are three valid forms of the attribute: -/// `#[used]`, which is semantically equivalent to `#[used(linker)]` except that the latter is currently unstable. +/// `#[used]`, which is equivalent to `#[used(linker)]` on targets that support it, but `#[used(compiler)]` if not. /// `#[used(compiler)]` /// `#[used(linker)]` #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable_Generic, PrintAttribute)] pub enum UsedBy { + Default, Compiler, Linker, } From 12cfad9a8b6aeed10ddc240b4923913246353ebb Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 3 Oct 2025 18:12:22 -0400 Subject: [PATCH 512/537] update autodiff batching test --- tests/codegen-llvm/autodiff/batched.rs | 74 +++++++++++++++----------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs index dc82403212fb..0ff6134bc07d 100644 --- a/tests/codegen-llvm/autodiff/batched.rs +++ b/tests/codegen-llvm/autodiff/batched.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme // @@ -23,7 +23,7 @@ fn square(x: &f32) -> f32 { } // d_square2 -// CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'") +// CHECK: define internal [4 x float] @fwddiffe4square(ptr noalias noundef readonly align 4 captures(none) dereferenceable(4) %x, [4 x ptr] %"x'") // CHECK-NEXT: start: // CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 // CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 @@ -33,23 +33,28 @@ fn square(x: &f32) -> f32 { // CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 // CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 // CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 -// CHECK-NEXT: %4 = fmul float %"_2'ipl", 2.000000e+00 -// CHECK-NEXT: %5 = fmul fast float %4, %x.0.val -// CHECK-NEXT: %6 = insertvalue [4 x float] undef, float %5, 0 -// CHECK-NEXT: %7 = fmul float %"_2'ipl1", 2.000000e+00 -// CHECK-NEXT: %8 = fmul fast float %7, %x.0.val -// CHECK-NEXT: %9 = insertvalue [4 x float] %6, float %8, 1 -// CHECK-NEXT: %10 = fmul float %"_2'ipl2", 2.000000e+00 -// CHECK-NEXT: %11 = fmul fast float %10, %x.0.val -// CHECK-NEXT: %12 = insertvalue [4 x float] %9, float %11, 2 -// CHECK-NEXT: %13 = fmul float %"_2'ipl3", 2.000000e+00 -// CHECK-NEXT: %14 = fmul fast float %13, %x.0.val -// CHECK-NEXT: %15 = insertvalue [4 x float] %12, float %14, 3 -// CHECK-NEXT: ret [4 x float] %15 +// CHECK-NEXT: %_2 = load float, ptr %x, align 4 +// CHECK-NEXT: %4 = fmul fast float %"_2'ipl", %_2 +// CHECK-NEXT: %5 = fmul fast float %"_2'ipl1", %_2 +// CHECK-NEXT: %6 = fmul fast float %"_2'ipl2", %_2 +// CHECK-NEXT: %7 = fmul fast float %"_2'ipl3", %_2 +// CHECK-NEXT: %8 = fmul fast float %"_2'ipl", %_2 +// CHECK-NEXT: %9 = fmul fast float %"_2'ipl1", %_2 +// CHECK-NEXT: %10 = fmul fast float %"_2'ipl2", %_2 +// CHECK-NEXT: %11 = fmul fast float %"_2'ipl3", %_2 +// CHECK-NEXT: %12 = fadd fast float %4, %8 +// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 +// CHECK-NEXT: %14 = fadd fast float %5, %9 +// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 +// CHECK-NEXT: %16 = fadd fast float %6, %10 +// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 +// CHECK-NEXT: %18 = fadd fast float %7, %11 +// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 +// CHECK-NEXT: ret [4 x float] %19 // CHECK-NEXT: } // d_square3, the extra float is the original return value (x * x) -// CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.1(float %x.0.val, [4 x ptr] %"x'") +// CHECK: define internal { float, [4 x float] } @fwddiffe4square.1(ptr noalias noundef readonly align 4 captures(none) dereferenceable(4) %x, [4 x ptr] %"x'") // CHECK-NEXT: start: // CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 // CHECK-NEXT: %"_2'ipl" = load float, ptr %0, align 4 @@ -59,22 +64,27 @@ fn square(x: &f32) -> f32 { // CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 // CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 // CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 -// CHECK-NEXT: %_0 = fmul float %x.0.val, %x.0.val -// CHECK-NEXT: %4 = fmul float %"_2'ipl", 2.000000e+00 -// CHECK-NEXT: %5 = fmul fast float %4, %x.0.val -// CHECK-NEXT: %6 = insertvalue [4 x float] undef, float %5, 0 -// CHECK-NEXT: %7 = fmul float %"_2'ipl1", 2.000000e+00 -// CHECK-NEXT: %8 = fmul fast float %7, %x.0.val -// CHECK-NEXT: %9 = insertvalue [4 x float] %6, float %8, 1 -// CHECK-NEXT: %10 = fmul float %"_2'ipl2", 2.000000e+00 -// CHECK-NEXT: %11 = fmul fast float %10, %x.0.val -// CHECK-NEXT: %12 = insertvalue [4 x float] %9, float %11, 2 -// CHECK-NEXT: %13 = fmul float %"_2'ipl3", 2.000000e+00 -// CHECK-NEXT: %14 = fmul fast float %13, %x.0.val -// CHECK-NEXT: %15 = insertvalue [4 x float] %12, float %14, 3 -// CHECK-NEXT: %16 = insertvalue { float, [4 x float] } undef, float %_0, 0 -// CHECK-NEXT: %17 = insertvalue { float, [4 x float] } %16, [4 x float] %15, 1 -// CHECK-NEXT: ret { float, [4 x float] } %17 +// CHECK-NEXT: %_2 = load float, ptr %x, align 4 +// CHECK-NEXT: %_0 = fmul float %_2, %_2 +// CHECK-NEXT: %4 = fmul fast float %"_2'ipl", %_2 +// CHECK-NEXT: %5 = fmul fast float %"_2'ipl1", %_2 +// CHECK-NEXT: %6 = fmul fast float %"_2'ipl2", %_2 +// CHECK-NEXT: %7 = fmul fast float %"_2'ipl3", %_2 +// CHECK-NEXT: %8 = fmul fast float %"_2'ipl", %_2 +// CHECK-NEXT: %9 = fmul fast float %"_2'ipl1", %_2 +// CHECK-NEXT: %10 = fmul fast float %"_2'ipl2", %_2 +// CHECK-NEXT: %11 = fmul fast float %"_2'ipl3", %_2 +// CHECK-NEXT: %12 = fadd fast float %4, %8 +// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 +// CHECK-NEXT: %14 = fadd fast float %5, %9 +// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 +// CHECK-NEXT: %16 = fadd fast float %6, %10 +// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 +// CHECK-NEXT: %18 = fadd fast float %7, %11 +// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 +// CHECK-NEXT: %20 = insertvalue { float, [4 x float] } undef, float %_0, 0 +// CHECK-NEXT: %21 = insertvalue { float, [4 x float] } %20, [4 x float] %19, 1 +// CHECK-NEXT: ret { float, [4 x float] } %21 // CHECK-NEXT: } fn main() { From 422b91443f1016aec2a1f00316d01a117ddc7829 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 4 Oct 2025 15:02:43 +0800 Subject: [PATCH 513/537] Fix top level ui tests check in tidy --- src/tools/tidy/src/ui_tests.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 12eca47c171d..c74ecf3d43f4 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -81,21 +81,20 @@ fn deny_new_top_level_ui_tests(check: &mut RunningCheck, tests_path: &Path) { // - // - - let top_level_ui_tests = walkdir::WalkDir::new(tests_path) - .min_depth(1) - .max_depth(1) + let top_level_ui_tests = ignore::WalkBuilder::new(tests_path) + .max_depth(Some(1)) .follow_links(false) - .same_file_system(true) - .into_iter() + .build() .flatten() .filter(|e| { let file_name = e.file_name(); file_name != ".gitattributes" && file_name != "README.md" }) - .filter(|e| !e.file_type().is_dir()); + .filter(|e| !e.file_type().is_some_and(|f| f.is_dir())); + for entry in top_level_ui_tests { check.error(format!( - "ui tests should be added under meaningful subdirectories: `{}`", + "ui tests should be added under meaningful subdirectories: `{}`, see https://github.com/rust-lang/compiler-team/issues/902", entry.path().display() )); } From f955c76a5b8ea3265d09139126d7f0df7fcebb18 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 3 Oct 2025 14:31:32 +1000 Subject: [PATCH 514/537] Remove inherent methods from several LLVM FFI types Using a helper trait allows the conversions to remain in `rustc_codegen_llvm`, even if the FFI types are moved to a different crate. --- compiler/rustc_codegen_llvm/src/allocator.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 3 +- .../src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- .../src/llvm/conversions.rs | 115 ++++++++++++++++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 107 ---------------- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 2 + 7 files changed, 122 insertions(+), 111 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/llvm/conversions.rs diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 896d6755c752..824aa501036d 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -14,7 +14,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use crate::attributes::llfn_attrs_from_instance; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; -use crate::llvm::{self, FALSE, TRUE, Type, Value}; +use crate::llvm::{self, FALSE, FromGeneric, TRUE, Type, Value}; use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e7cb18ab22da..08da90d535da 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -36,7 +36,8 @@ use crate::attributes; use crate::common::Funclet; use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; use crate::llvm::{ - self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, GEPNoWrapFlags, Metadata, TRUE, ToLlvmBool, + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, FromGeneric, GEPNoWrapFlags, Metadata, TRUE, + ToLlvmBool, }; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 2f9e7cae54f2..b8b5f3d30d7c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -37,11 +37,11 @@ use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::dwarf_const; use crate::debuginfo::metadata::type_map::build_type_with_children; use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; -use crate::llvm; use crate::llvm::debuginfo::{ DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, }; +use crate::llvm::{self, FromGeneric}; use crate::value::Value; impl PartialEq for llvm::Metadata { diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 36cdb4988395..f598763efcf2 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -26,7 +26,7 @@ use crate::abi::FnAbiLlvmExt; use crate::common::AsCCharPtr; use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx}; use crate::llvm::AttributePlace::Function; -use crate::llvm::Visibility; +use crate::llvm::{FromGeneric, Visibility}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, llvm}; diff --git a/compiler/rustc_codegen_llvm/src/llvm/conversions.rs b/compiler/rustc_codegen_llvm/src/llvm/conversions.rs new file mode 100644 index 000000000000..9e9f9339ade8 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/llvm/conversions.rs @@ -0,0 +1,115 @@ +//! Conversions from backend-independent data types to/from LLVM FFI types. + +use rustc_codegen_ssa::common::{AtomicRmwBinOp, IntPredicate, RealPredicate}; +use rustc_middle::ty::AtomicOrdering; +use rustc_session::config::DebugInfo; +use rustc_target::spec::SymbolVisibility; + +use crate::llvm; + +/// Helper trait for converting backend-independent types to LLVM-specific +/// types, for FFI purposes. +pub(crate) trait FromGeneric { + fn from_generic(other: T) -> Self; +} + +impl FromGeneric for llvm::Visibility { + fn from_generic(visibility: SymbolVisibility) -> Self { + match visibility { + SymbolVisibility::Hidden => Self::Hidden, + SymbolVisibility::Protected => Self::Protected, + SymbolVisibility::Interposable => Self::Default, + } + } +} + +impl FromGeneric for llvm::IntPredicate { + fn from_generic(int_pred: IntPredicate) -> Self { + match int_pred { + IntPredicate::IntEQ => Self::IntEQ, + IntPredicate::IntNE => Self::IntNE, + IntPredicate::IntUGT => Self::IntUGT, + IntPredicate::IntUGE => Self::IntUGE, + IntPredicate::IntULT => Self::IntULT, + IntPredicate::IntULE => Self::IntULE, + IntPredicate::IntSGT => Self::IntSGT, + IntPredicate::IntSGE => Self::IntSGE, + IntPredicate::IntSLT => Self::IntSLT, + IntPredicate::IntSLE => Self::IntSLE, + } + } +} + +impl FromGeneric for llvm::RealPredicate { + fn from_generic(real_pred: RealPredicate) -> Self { + match real_pred { + RealPredicate::RealPredicateFalse => Self::RealPredicateFalse, + RealPredicate::RealOEQ => Self::RealOEQ, + RealPredicate::RealOGT => Self::RealOGT, + RealPredicate::RealOGE => Self::RealOGE, + RealPredicate::RealOLT => Self::RealOLT, + RealPredicate::RealOLE => Self::RealOLE, + RealPredicate::RealONE => Self::RealONE, + RealPredicate::RealORD => Self::RealORD, + RealPredicate::RealUNO => Self::RealUNO, + RealPredicate::RealUEQ => Self::RealUEQ, + RealPredicate::RealUGT => Self::RealUGT, + RealPredicate::RealUGE => Self::RealUGE, + RealPredicate::RealULT => Self::RealULT, + RealPredicate::RealULE => Self::RealULE, + RealPredicate::RealUNE => Self::RealUNE, + RealPredicate::RealPredicateTrue => Self::RealPredicateTrue, + } + } +} + +impl FromGeneric for llvm::AtomicRmwBinOp { + fn from_generic(op: AtomicRmwBinOp) -> Self { + match op { + AtomicRmwBinOp::AtomicXchg => Self::AtomicXchg, + AtomicRmwBinOp::AtomicAdd => Self::AtomicAdd, + AtomicRmwBinOp::AtomicSub => Self::AtomicSub, + AtomicRmwBinOp::AtomicAnd => Self::AtomicAnd, + AtomicRmwBinOp::AtomicNand => Self::AtomicNand, + AtomicRmwBinOp::AtomicOr => Self::AtomicOr, + AtomicRmwBinOp::AtomicXor => Self::AtomicXor, + AtomicRmwBinOp::AtomicMax => Self::AtomicMax, + AtomicRmwBinOp::AtomicMin => Self::AtomicMin, + AtomicRmwBinOp::AtomicUMax => Self::AtomicUMax, + AtomicRmwBinOp::AtomicUMin => Self::AtomicUMin, + } + } +} + +impl FromGeneric for llvm::AtomicOrdering { + fn from_generic(ordering: AtomicOrdering) -> Self { + match ordering { + AtomicOrdering::Relaxed => Self::Monotonic, + AtomicOrdering::Acquire => Self::Acquire, + AtomicOrdering::Release => Self::Release, + AtomicOrdering::AcqRel => Self::AcquireRelease, + AtomicOrdering::SeqCst => Self::SequentiallyConsistent, + } + } +} + +impl FromGeneric for llvm::debuginfo::DebugEmissionKind { + fn from_generic(kind: DebugInfo) -> Self { + // We should be setting LLVM's emission kind to `LineTablesOnly` if + // we are compiling with "limited" debuginfo. However, some of the + // existing tools relied on slightly more debuginfo being generated than + // would be the case with `LineTablesOnly`, and we did not want to break + // these tools in a "drive-by fix", without a good idea or plan about + // what limited debuginfo should exactly look like. So for now we are + // instead adding a new debuginfo option "line-tables-only" so as to + // not break anything and to allow users to have 'limited' debug info. + // + // See https://github.com/rust-lang/rust/issues/60020 for details. + match kind { + DebugInfo::None => Self::NoDebug, + DebugInfo::LineDirectivesOnly => Self::DebugDirectivesOnly, + DebugInfo::LineTablesOnly => Self::LineTablesOnly, + DebugInfo::Limited | DebugInfo::Full => Self::FullDebug, + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7fbba0294073..965e775bed70 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -20,7 +20,6 @@ use std::ptr; use bitflags::bitflags; use libc::{c_char, c_int, c_uchar, c_uint, c_ulonglong, c_void, size_t}; use rustc_macros::TryFromU32; -use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ @@ -220,16 +219,6 @@ pub(crate) enum Visibility { Protected = 2, } -impl Visibility { - pub(crate) fn from_generic(visibility: SymbolVisibility) -> Self { - match visibility { - SymbolVisibility::Hidden => Visibility::Hidden, - SymbolVisibility::Protected => Visibility::Protected, - SymbolVisibility::Interposable => Visibility::Default, - } - } -} - /// LLVMUnnamedAddr #[repr(C)] pub(crate) enum UnnamedAddr { @@ -319,24 +308,6 @@ pub(crate) enum IntPredicate { IntSLE = 41, } -impl IntPredicate { - pub(crate) fn from_generic(intpre: rustc_codegen_ssa::common::IntPredicate) -> Self { - use rustc_codegen_ssa::common::IntPredicate as Common; - match intpre { - Common::IntEQ => Self::IntEQ, - Common::IntNE => Self::IntNE, - Common::IntUGT => Self::IntUGT, - Common::IntUGE => Self::IntUGE, - Common::IntULT => Self::IntULT, - Common::IntULE => Self::IntULE, - Common::IntSGT => Self::IntSGT, - Common::IntSGE => Self::IntSGE, - Common::IntSLT => Self::IntSLT, - Common::IntSLE => Self::IntSLE, - } - } -} - /// LLVMRealPredicate #[derive(Copy, Clone)] #[repr(C)] @@ -359,30 +330,6 @@ pub(crate) enum RealPredicate { RealPredicateTrue = 15, } -impl RealPredicate { - pub(crate) fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self { - use rustc_codegen_ssa::common::RealPredicate as Common; - match realp { - Common::RealPredicateFalse => Self::RealPredicateFalse, - Common::RealOEQ => Self::RealOEQ, - Common::RealOGT => Self::RealOGT, - Common::RealOGE => Self::RealOGE, - Common::RealOLT => Self::RealOLT, - Common::RealOLE => Self::RealOLE, - Common::RealONE => Self::RealONE, - Common::RealORD => Self::RealORD, - Common::RealUNO => Self::RealUNO, - Common::RealUEQ => Self::RealUEQ, - Common::RealUGT => Self::RealUGT, - Common::RealUGE => Self::RealUGE, - Common::RealULT => Self::RealULT, - Common::RealULE => Self::RealULE, - Common::RealUNE => Self::RealUNE, - Common::RealPredicateTrue => Self::RealPredicateTrue, - } - } -} - /// Must match the layout of `LLVMTypeKind`. /// /// Use [`RawEnum`] for values of `LLVMTypeKind` returned from LLVM, @@ -458,25 +405,6 @@ pub(crate) enum AtomicRmwBinOp { AtomicUMin = 10, } -impl AtomicRmwBinOp { - pub(crate) fn from_generic(op: rustc_codegen_ssa::common::AtomicRmwBinOp) -> Self { - use rustc_codegen_ssa::common::AtomicRmwBinOp as Common; - match op { - Common::AtomicXchg => Self::AtomicXchg, - Common::AtomicAdd => Self::AtomicAdd, - Common::AtomicSub => Self::AtomicSub, - Common::AtomicAnd => Self::AtomicAnd, - Common::AtomicNand => Self::AtomicNand, - Common::AtomicOr => Self::AtomicOr, - Common::AtomicXor => Self::AtomicXor, - Common::AtomicMax => Self::AtomicMax, - Common::AtomicMin => Self::AtomicMin, - Common::AtomicUMax => Self::AtomicUMax, - Common::AtomicUMin => Self::AtomicUMin, - } - } -} - /// LLVMAtomicOrdering #[derive(Copy, Clone)] #[repr(C)] @@ -493,19 +421,6 @@ pub(crate) enum AtomicOrdering { SequentiallyConsistent = 7, } -impl AtomicOrdering { - pub(crate) fn from_generic(ao: rustc_middle::ty::AtomicOrdering) -> Self { - use rustc_middle::ty::AtomicOrdering as Common; - match ao { - Common::Relaxed => Self::Monotonic, - Common::Acquire => Self::Acquire, - Common::Release => Self::Release, - Common::AcqRel => Self::AcquireRelease, - Common::SeqCst => Self::SequentiallyConsistent, - } - } -} - /// LLVMRustFileType #[derive(Copy, Clone)] #[repr(C)] @@ -940,28 +855,6 @@ pub(crate) mod debuginfo { DebugDirectivesOnly, } - impl DebugEmissionKind { - pub(crate) fn from_generic(kind: rustc_session::config::DebugInfo) -> Self { - // We should be setting LLVM's emission kind to `LineTablesOnly` if - // we are compiling with "limited" debuginfo. However, some of the - // existing tools relied on slightly more debuginfo being generated than - // would be the case with `LineTablesOnly`, and we did not want to break - // these tools in a "drive-by fix", without a good idea or plan about - // what limited debuginfo should exactly look like. So for now we are - // instead adding a new debuginfo option "line-tables-only" so as to - // not break anything and to allow users to have 'limited' debug info. - // - // See https://github.com/rust-lang/rust/issues/60020 for details. - use rustc_session::config::DebugInfo; - match kind { - DebugInfo::None => DebugEmissionKind::NoDebug, - DebugInfo::LineDirectivesOnly => DebugEmissionKind::DebugDirectivesOnly, - DebugInfo::LineTablesOnly => DebugEmissionKind::LineTablesOnly, - DebugInfo::Limited | DebugInfo::Full => DebugEmissionKind::FullDebug, - } - } - } - /// LLVMRustDebugNameTableKind #[derive(Clone, Copy)] #[repr(C)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 9a53dacb1dfd..4c58a92106d5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -11,10 +11,12 @@ use rustc_llvm::RustString; pub(crate) use self::CallConv::*; pub(crate) use self::CodeGenOptSize::*; +pub(crate) use self::conversions::*; pub(crate) use self::ffi::*; pub(crate) use self::metadata_kind::*; use crate::common::AsCCharPtr; +mod conversions; pub(crate) mod diagnostic; pub(crate) mod enzyme_ffi; mod ffi; From 0661a3d6fe4efd7127c66aeb6484f06b3441c63f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 3 Oct 2025 17:11:53 +1000 Subject: [PATCH 515/537] Remove inherent methods from `coverageinfo::ffi::Counter` This patch also moves `Regions` to a different module, since that type can stay put when the FFI bindings move to another crate. --- .../src/coverageinfo/ffi.rs | 45 +------------------ .../src/coverageinfo/llvm_cov.rs | 27 ++++++++++- .../src/coverageinfo/mapgen/covfun.rs | 27 +++++++---- 3 files changed, 45 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index a4b60d420f3f..caa36c5dd499 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,5 +1,3 @@ -use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId}; - /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -26,30 +24,12 @@ pub(crate) enum CounterKind { pub(crate) struct Counter { // Important: The layout (order and types of fields) must match its C++ counterpart. pub(crate) kind: CounterKind, - id: u32, + pub(crate) id: u32, } impl Counter { /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used. pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 }; - - /// Constructs a new `Counter` of kind `CounterValueReference`. - pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self { - Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() } - } - - /// Constructs a new `Counter` of kind `Expression`. - pub(crate) fn expression(expression_id: ExpressionId) -> Self { - Self { kind: CounterKind::Expression, id: expression_id.as_u32() } - } - - pub(crate) fn from_term(term: CovTerm) -> Self { - match term { - CovTerm::Zero => Self::ZERO, - CovTerm::Counter(id) => Self::counter_value_reference(id), - CovTerm::Expression(id) => Self::expression(id), - } - } } /// Corresponds to enum `llvm::coverage::CounterExpression::ExprKind`. @@ -94,29 +74,6 @@ pub(crate) struct CoverageSpan { pub(crate) end_col: u32, } -/// Holds tables of the various region types in one struct. -/// -/// Don't pass this struct across FFI; pass the individual region tables as -/// pointer/length pairs instead. -/// -/// Each field name has a `_regions` suffix for improved readability after -/// exhaustive destructing, which ensures that all region types are handled. -#[derive(Clone, Debug, Default)] -pub(crate) struct Regions { - pub(crate) code_regions: Vec, - pub(crate) expansion_regions: Vec, - pub(crate) branch_regions: Vec, -} - -impl Regions { - /// Returns true if none of this structure's tables contain any regions. - pub(crate) fn has_no_regions(&self) -> bool { - let Self { code_regions, expansion_regions, branch_regions } = self; - - code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty() - } -} - /// Must match the layout of `LLVMRustCoverageCodeRegion`. #[derive(Clone, Debug)] #[repr(C)] diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index d50eb533ffdb..a58202834cfa 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -57,12 +57,35 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef]) -> Vec, + pub(crate) expansion_regions: Vec, + pub(crate) branch_regions: Vec, +} + +impl Regions { + /// Returns true if none of this structure's tables contain any regions. + pub(crate) fn has_no_regions(&self) -> bool { + let Self { code_regions, expansion_regions, branch_regions } = self; + + code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty() + } +} + pub(crate) fn write_function_mappings_to_buffer( virtual_file_mapping: &[u32], expressions: &[ffi::CounterExpression], - regions: &ffi::Regions, + regions: &Regions, ) -> Vec { - let ffi::Regions { code_regions, expansion_regions, branch_regions } = regions; + let Regions { code_regions, expansion_regions, branch_regions } = regions; // SAFETY: // - All types are FFI-compatible and have matching representations in Rust/C++. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index e0da8d368762..7835d1804686 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use rustc_abi::Align; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods as _, ConstCodegenMethods}; use rustc_middle::mir::coverage::{ - BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, - MappingKind, Op, + BasicCoverageBlock, CounterId, CovTerm, CoverageIdsInfo, Expression, ExpressionId, + FunctionCoverageInfo, Mapping, MappingKind, Op, }; use rustc_middle::ty::{Instance, TyCtxt}; use rustc_span::{SourceFile, Span}; @@ -36,7 +36,7 @@ pub(crate) struct CovfunRecord<'tcx> { virtual_file_mapping: VirtualFileMapping, expressions: Vec, - regions: ffi::Regions, + regions: llvm_cov::Regions, } impl<'tcx> CovfunRecord<'tcx> { @@ -64,7 +64,7 @@ pub(crate) fn prepare_covfun_record<'tcx>( is_used, virtual_file_mapping: VirtualFileMapping::default(), expressions, - regions: ffi::Regions::default(), + regions: llvm_cov::Regions::default(), }; fill_region_tables(tcx, fn_cov_info, ids_info, &mut covfun); @@ -77,10 +77,21 @@ pub(crate) fn prepare_covfun_record<'tcx>( Some(covfun) } +pub(crate) fn counter_for_term(term: CovTerm) -> ffi::Counter { + use ffi::Counter; + match term { + CovTerm::Zero => Counter::ZERO, + CovTerm::Counter(id) => { + Counter { kind: ffi::CounterKind::CounterValueReference, id: CounterId::as_u32(id) } + } + CovTerm::Expression(id) => { + Counter { kind: ffi::CounterKind::Expression, id: ExpressionId::as_u32(id) } + } + } +} + /// Convert the function's coverage-counter expressions into a form suitable for FFI. fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec { - let counter_for_term = ffi::Counter::from_term; - // We know that LLVM will optimize out any unused expressions before // producing the final coverage map, so there's no need to do the same // thing on the Rust side unless we're confident we can do much better. @@ -113,7 +124,7 @@ fn fill_region_tables<'tcx>( } else { CovTerm::Zero }; - ffi::Counter::from_term(term) + counter_for_term(term) }; // Currently a function's mappings must all be in the same file, so use the @@ -136,7 +147,7 @@ fn fill_region_tables<'tcx>( if discard_all { None } else { spans::make_coords(source_map, &source_file, span) } }; - let ffi::Regions { + let llvm_cov::Regions { code_regions, expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions branch_regions, From 3831b60ef3dd46d11f63041016bd1e6f6f9039f5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 4 Oct 2025 17:54:03 +1000 Subject: [PATCH 516/537] Remove inherent methods from `llvm::Type` --- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++-- compiler/rustc_codegen_llvm/src/type_.rs | 24 +++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 1950b8288d14..6ce1cbe072c0 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -44,7 +44,7 @@ use crate::errors::{ }; use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; use crate::llvm::{self, DiagnosticInfo}; -use crate::type_::Type; +use crate::type_::llvm_type_ptr; use crate::{LlvmCodegenBackend, ModuleLlvm, base, common, llvm_util}; pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> ! { @@ -1160,7 +1160,7 @@ fn create_msvc_imps( // underscores added in front). let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" }; - let ptr_ty = Type::ptr_llcx(llcx); + let ptr_ty = llvm_type_ptr(llcx); let globals = base::iter_globals(llmod) .filter(|&val| { llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage && !llvm::is_declaration(val) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 922575dd63cf..cda5b3a5f9aa 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -740,7 +740,7 @@ impl<'ll> SimpleCx<'ll> { llcx: &'ll llvm::Context, pointer_size: Size, ) -> Self { - let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits()); + let isize_ty = llvm::LLVMIntTypeInContext(llcx, pointer_size.bits() as c_uint); Self(SCx { llmod, llcx, isize_ty }, PhantomData) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 965e775bed70..ccbc999dad1f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -954,7 +954,7 @@ unsafe extern "C" { pub(crate) fn LLVMInt16TypeInContext(C: &Context) -> &Type; pub(crate) fn LLVMInt32TypeInContext(C: &Context) -> &Type; pub(crate) fn LLVMInt64TypeInContext(C: &Context) -> &Type; - pub(crate) fn LLVMIntTypeInContext(C: &Context, NumBits: c_uint) -> &Type; + pub(crate) safe fn LLVMIntTypeInContext(C: &Context, NumBits: c_uint) -> &Type; pub(crate) fn LLVMGetIntTypeWidth(IntegerTy: &Type) -> c_uint; @@ -983,7 +983,7 @@ unsafe extern "C" { ) -> &'a Type; // Operations on array, pointer, and vector types (sequence types) - pub(crate) fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; + pub(crate) safe fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 1e5cf8374e37..9de9e0ec44c6 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -63,7 +63,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } + llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { @@ -178,7 +178,7 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_i128(&self) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) } + self.type_ix(128) } fn type_isize(&self) -> &'ll Type { @@ -210,11 +210,11 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_ptr(&self) -> &'ll Type { - self.type_ptr_ext(AddressSpace::ZERO) + llvm_type_ptr(self.llcx()) } fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type { - unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) } + llvm_type_ptr_in_address_space(self.llcx(), address_space) } fn element_type(&self, ty: &'ll Type) -> &'ll Type { @@ -253,15 +253,15 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } } -impl Type { - /// Creates an integer type with the given number of bits, e.g., i24 - pub(crate) fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { - unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) } - } +pub(crate) fn llvm_type_ptr(llcx: &llvm::Context) -> &Type { + llvm_type_ptr_in_address_space(llcx, AddressSpace::ZERO) +} - pub(crate) fn ptr_llcx(llcx: &llvm::Context) -> &Type { - unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::ZERO.0) } - } +pub(crate) fn llvm_type_ptr_in_address_space<'ll>( + llcx: &'ll llvm::Context, + addr_space: AddressSpace, +) -> &'ll Type { + llvm::LLVMPointerTypeInContext(llcx, addr_space.0) } impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { From f8c54d24e2f4ca8539cb6d9b174e4c873bbb3ed7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 3 Oct 2025 17:25:03 +1000 Subject: [PATCH 517/537] Remove inherent methods from `llvm::CallConv::from_conv` --- compiler/rustc_codegen_llvm/src/abi.rs | 78 +++++++++++----------- compiler/rustc_codegen_llvm/src/context.rs | 6 +- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 1703cab942bd..15b4d5247a97 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::cmp; use libc::c_uint; @@ -13,7 +12,7 @@ use rustc_codegen_ssa::traits::*; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{bug, ty}; -use rustc_session::config; +use rustc_session::{Session, config}; use rustc_target::callconv::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, }; @@ -400,7 +399,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } fn llvm_cconv(&self, cx: &CodegenCx<'ll, 'tcx>) -> llvm::CallConv { - llvm::CallConv::from_conv(self.conv, cx.tcx.sess.target.arch.borrow()) + to_llvm_calling_convention(cx.tcx.sess, self.conv) } fn apply_attrs_llfn( @@ -663,43 +662,44 @@ impl AbiBuilderMethods for Builder<'_, '_, '_> { } } -impl llvm::CallConv { - pub(crate) fn from_conv(conv: CanonAbi, arch: &str) -> Self { - match conv { - CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, - CanonAbi::RustCold => llvm::PreserveMost, - // Functions with this calling convention can only be called from assembly, but it is - // possible to declare an `extern "custom"` block, so the backend still needs a calling - // convention for declaring foreign functions. - CanonAbi::Custom => llvm::CCallConv, - CanonAbi::GpuKernel => { - if arch == "amdgpu" { - llvm::AmdgpuKernel - } else if arch == "nvptx64" { - llvm::PtxKernel - } else { - panic!("Architecture {arch} does not support GpuKernel calling convention"); - } +/// Determines the appropriate [`llvm::CallConv`] to use for a given function +/// ABI, for the current target. +pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm::CallConv { + match abi { + CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, + CanonAbi::RustCold => llvm::PreserveMost, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => llvm::CCallConv, + CanonAbi::GpuKernel => { + let arch = sess.target.arch.as_ref(); + if arch == "amdgpu" { + llvm::AmdgpuKernel + } else if arch == "nvptx64" { + llvm::PtxKernel + } else { + panic!("Architecture {arch} does not support GpuKernel calling convention"); } - CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { - InterruptKind::Avr => llvm::AvrInterrupt, - InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt, - InterruptKind::Msp430 => llvm::Msp430Intr, - InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv, - InterruptKind::X86 => llvm::X86_Intr, - }, - CanonAbi::Arm(arm_call) => match arm_call { - ArmCall::Aapcs => llvm::ArmAapcsCallConv, - ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv, - }, - CanonAbi::X86(x86_call) => match x86_call { - X86Call::Fastcall => llvm::X86FastcallCallConv, - X86Call::Stdcall => llvm::X86StdcallCallConv, - X86Call::SysV64 => llvm::X86_64_SysV, - X86Call::Thiscall => llvm::X86_ThisCall, - X86Call::Vectorcall => llvm::X86_VectorCall, - X86Call::Win64 => llvm::X86_64_Win64, - }, } + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => llvm::AvrInterrupt, + InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => llvm::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv, + InterruptKind::X86 => llvm::X86_Intr, + }, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => llvm::ArmAapcsCallConv, + ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => llvm::X86FastcallCallConv, + X86Call::Stdcall => llvm::X86StdcallCallConv, + X86Call::SysV64 => llvm::X86_64_SysV, + X86Call::Thiscall => llvm::X86_ThisCall, + X86Call::Vectorcall => llvm::X86_VectorCall, + X86Call::Win64 => llvm::X86_64_Win64, + }, } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index cda5b3a5f9aa..3ddbd81ef758 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -31,6 +31,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel}; use smallvec::SmallVec; +use crate::abi::to_llvm_calling_convention; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; @@ -901,10 +902,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { if self.get_declared_value(entry_name).is_none() { let llfn = self.declare_entry_fn( entry_name, - llvm::CallConv::from_conv( - self.sess().target.entry_abi, - self.sess().target.arch.borrow(), - ), + to_llvm_calling_convention(self.sess(), self.sess().target.entry_abi), llvm::UnnamedAddr::Global, fn_type, ); From e9a45e66461f3c324a249d7352eb2f4d184a6b2a Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 4 Oct 2025 14:48:55 +0800 Subject: [PATCH 518/537] Avoid to suggest pattern match on the similarly named in fn signature --- compiler/rustc_passes/src/liveness.rs | 7 +++++-- .../ui/fn/invalid-sugg-for-unused-fn-arg-147303.rs | 13 +++++++++++++ .../invalid-sugg-for-unused-fn-arg-147303.stderr | 14 ++++++++++++++ .../non-snake-case/lint-uppercase-variables.stderr | 11 +---------- 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.rs create mode 100644 tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.stderr diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 1b2ffb5b3db2..b628ff8a12df 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1691,7 +1691,10 @@ impl<'tcx> Liveness<'_, 'tcx> { if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; let mut typo = None; - for (hir_id, _, span) in &hir_ids_and_spans { + let filtered_hir_ids_and_spans = hir_ids_and_spans.iter().filter(|(hir_id, ..)| { + !matches!(self.ir.tcx.parent_hir_node(*hir_id), hir::Node::Param(_)) + }); + for (hir_id, _, span) in filtered_hir_ids_and_spans.clone() { let ty = self.typeck_results.node_type(*hir_id); if let ty::Adt(adt, _) = ty.peel_refs().kind() { let name = Symbol::intern(&name); @@ -1717,7 +1720,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } } if typo.is_none() { - for (hir_id, _, span) in &hir_ids_and_spans { + for (hir_id, _, span) in filtered_hir_ids_and_spans { let ty = self.typeck_results.node_type(*hir_id); // Look for consts of the same type with similar names as well, not just unit // structs and variants. diff --git a/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.rs b/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.rs new file mode 100644 index 000000000000..137ba8dc103e --- /dev/null +++ b/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.rs @@ -0,0 +1,13 @@ +// Regression test for . + +#![deny(unused_assignments, unused_variables)] + +mod m1 { + const _MAX_FMTVER_X1X_EVENTNUM: i32 = 0; +} + +mod m2 { + fn fun(rough: i32) {} //~ERROR unused variable +} + +fn main() {} diff --git a/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.stderr b/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.stderr new file mode 100644 index 000000000000..30e4a758c13c --- /dev/null +++ b/tests/ui/fn/invalid-sugg-for-unused-fn-arg-147303.stderr @@ -0,0 +1,14 @@ +error: unused variable: `rough` + --> $DIR/invalid-sugg-for-unused-fn-arg-147303.rs:10:12 + | +LL | fn fun(rough: i32) {} + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_rough` + | +note: the lint level is defined here + --> $DIR/invalid-sugg-for-unused-fn-arg-147303.rs:3:29 + | +LL | #![deny(unused_assignments, unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr index e5f2e65fd91d..5dec20b2ac7e 100644 --- a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr +++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr @@ -58,16 +58,7 @@ warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:33:17 | LL | fn in_param(Foo: foo::Foo) {} - | ^^^ - | -help: if this is intentional, prefix it with an underscore - | -LL | fn in_param(_Foo: foo::Foo) {} - | + -help: you might have meant to pattern match on the similarly named variant `Foo` - | -LL | fn in_param(foo::Foo::Foo: foo::Foo) {} - | ++++++++++ + | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` error: structure field `X` should have a snake case name --> $DIR/lint-uppercase-variables.rs:10:5 From ba42380142e73765eab501b3ebc2b3e05ee6b0c0 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sat, 4 Oct 2025 17:16:00 +0800 Subject: [PATCH 519/537] Implement non-poisoning `Mutex::with_mut`, `RwLock::with` and `RwLock::with_mut` ACP: https://github.com/rust-lang/libs-team/issues/497. --- library/std/src/sync/nonpoison/mutex.rs | 34 +++++++++++++ library/std/src/sync/nonpoison/rwlock.rs | 62 ++++++++++++++++++++++++ library/std/tests/sync/mutex.rs | 14 ++++++ library/std/tests/sync/rwlock.rs | 22 +++++++++ 4 files changed, 132 insertions(+) diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index eeecf5d71076..ed3f8cfed821 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -376,6 +376,40 @@ impl Mutex { pub const fn data_ptr(&self) -> *mut T { self.data.get() } + + /// Acquires the mutex and provides mutable access to the underlying data by passing + /// a mutable reference to the given closure. + /// + /// This method acquires the lock, calls the provided closure with a mutable reference + /// to the data, and returns the result of the closure. The lock is released after + /// the closure completes, even if it panics. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors, nonpoison_mutex)] + /// + /// use std::sync::nonpoison::Mutex; + /// + /// let mutex = Mutex::new(2); + /// + /// let result = mutex.with_mut(|data| { + /// *data += 3; + /// + /// *data + 5 + /// }); + /// + /// assert_eq!(*mutex.lock(), 5); + /// assert_eq!(result, 10); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_mutex", issue = "134645")] + pub fn with_mut(&self, f: F) -> R + where + F: FnOnce(&mut T) -> R, + { + f(&mut self.lock()) + } } #[unstable(feature = "nonpoison_mutex", issue = "134645")] diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs index b2f26edc083e..568c7f386847 100644 --- a/library/std/src/sync/nonpoison/rwlock.rs +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -498,6 +498,68 @@ impl RwLock { pub const fn data_ptr(&self) -> *mut T { self.data.get() } + + /// Locks this `RwLock` with shared read access to the underlying data by passing + /// a reference to the given closure. + /// + /// This method acquires the lock, calls the provided closure with a reference + /// to the data, and returns the result of the closure. The lock is released after + /// the closure completes, even if it panics. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors, nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let rwlock = RwLock::new(2); + /// let result = rwlock.with(|data| *data + 3); + /// + /// assert_eq!(result, 5); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn with(&self, f: F) -> R + where + F: FnOnce(&T) -> R, + { + f(&self.read()) + } + + /// Locks this `RwLock` with exclusive write access to the underlying data by passing + /// a mutable reference to the given closure. + /// + /// This method acquires the lock, calls the provided closure with a mutable reference + /// to the data, and returns the result of the closure. The lock is released after + /// the closure completes, even if it panics. + /// + /// # Examples + /// + /// ``` + /// #![feature(lock_value_accessors, nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let rwlock = RwLock::new(2); + /// + /// let result = rwlock.with_mut(|data| { + /// *data += 3; + /// + /// *data + 5 + /// }); + /// + /// assert_eq!(*rwlock.read(), 5); + /// assert_eq!(result, 10); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn with_mut(&self, f: F) -> R + where + F: FnOnce(&mut T) -> R, + { + f(&mut self.write()) + } } #[unstable(feature = "nonpoison_rwlock", issue = "134645")] diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs index 2445764001b8..ff6aef717936 100644 --- a/library/std/tests/sync/mutex.rs +++ b/library/std/tests/sync/mutex.rs @@ -549,3 +549,17 @@ fn panic_while_mapping_unlocked_poison() { drop(lock); } + +#[test] +fn test_mutex_with_mut() { + let mutex = std::sync::nonpoison::Mutex::new(2); + + let result = mutex.with_mut(|value| { + *value += 3; + + *value + 5 + }); + + assert_eq!(*mutex.lock(), 5); + assert_eq!(result, 10); +} diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index 65d8bac71945..392c45c8ba05 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -861,3 +861,25 @@ fn panic_while_mapping_write_unlocked_poison() { drop(lock); } + +#[test] +fn test_rwlock_with() { + let rwlock = std::sync::nonpoison::RwLock::new(2); + let result = rwlock.with(|value| *value + 3); + + assert_eq!(result, 5); +} + +#[test] +fn test_rwlock_with_mut() { + let rwlock = std::sync::nonpoison::RwLock::new(2); + + let result = rwlock.with_mut(|value| { + *value += 3; + + *value + 5 + }); + + assert_eq!(*rwlock.read(), 5); + assert_eq!(result, 10); +} From 5c95f8bea6ea37d750910e5b0ac7ae049579e437 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 2 Oct 2025 10:15:00 +0200 Subject: [PATCH 520/537] Add failing regression test for #[link="dl"] --- .../ui/attributes/link-dl.default_fcw.stderr | 26 +++++++++++++++++++ tests/ui/attributes/link-dl.rs | 19 ++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/ui/attributes/link-dl.default_fcw.stderr create mode 100644 tests/ui/attributes/link-dl.rs diff --git a/tests/ui/attributes/link-dl.default_fcw.stderr b/tests/ui/attributes/link-dl.default_fcw.stderr new file mode 100644 index 000000000000..6bff216ad03f --- /dev/null +++ b/tests/ui/attributes/link-dl.default_fcw.stderr @@ -0,0 +1,26 @@ +error[E0539]: malformed `link` attribute input + --> $DIR/link-dl.rs:14:1 + | +LL | #[link="dl"] + | ^^^^^^^^^^^^ expected this to be a list + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link="dl"] +LL + #[link(name = "...")] + | +LL - #[link="dl"] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link="dl"] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link="dl"] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/link-dl.rs b/tests/ui/attributes/link-dl.rs new file mode 100644 index 000000000000..0785c83cb442 --- /dev/null +++ b/tests/ui/attributes/link-dl.rs @@ -0,0 +1,19 @@ +// Regression test for an issue discovered in https://github.com/rust-lang/rust/pull/143193/files and rediscovered in https://github.com/rust-lang/rust/issues/147254#event-20049906781 +// Malformed #[link] attribute was supposed to be deny-by-default report-in-deps FCW, +// but accidentally was landed as a hard error. +// +// revision `default_fcw` tests that with `ill_formed_attribute_input` (the default) denied, +// the attribute produces an FCW +// revision `allowed` tests that with `ill_formed_attribute_input` allowed the test passes + +//@ revisions: default_fcw allowed +//@[allowed] check-pass + +#[cfg_attr(allowed, allow(ill_formed_attribute_input))] + +#[link="dl"] +//[default_fcw]~^ ERROR valid forms for the attribute are +//[default_fcw]~| WARN previously accepted +extern "C" { } + +fn main() {} From 1c85a1dc2eaa2cbc55b5d0a6bbde1ca73706385d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 2 Oct 2025 10:20:08 +0200 Subject: [PATCH 521/537] Make `#[link="dl"]` a warning rather than an error --- .../src/attributes/link_attrs.rs | 29 ++++++++++----- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/attributes/link-dl.allowed.stderr | 10 ++++++ .../ui/attributes/link-dl.default_fcw.stderr | 35 +++++++++---------- 4 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 tests/ui/attributes/link-dl.allowed.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index d4942e56f429..04eaa485f736 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -65,10 +65,22 @@ impl CombineAttributeParser for LinkParser { cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator + 'c { - let mut result = None; - let Some(items) = args.list() else { - cx.expected_list(cx.attr_span); - return result; + let items = match args { + ArgParser::List(list) => list, + // This is an edgecase added because making this a hard error would break too many crates + // Specifically `#[link = "dl"]` is accepted with a FCW + // For more information, see https://github.com/rust-lang/rust/pull/143193 + ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => { + let suggestions = >::TEMPLATE + .suggestions(cx.attr_style, "link"); + let span = cx.attr_span; + cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); + return None; + } + _ => { + cx.expected_list(cx.attr_span); + return None; + } }; let sess = cx.sess(); @@ -113,7 +125,7 @@ impl CombineAttributeParser for LinkParser { } }; if !cont { - return result; + return None; } } @@ -202,7 +214,7 @@ impl CombineAttributeParser for LinkParser { } let Some((name, name_span)) = name else { cx.emit_err(LinkRequiresName { span: cx.attr_span }); - return result; + return None; }; // Do this outside of the loop so that `import_name_type` can be specified before `kind`. @@ -218,15 +230,14 @@ impl CombineAttributeParser for LinkParser { cx.emit_err(RawDylibNoNul { span: name_span }); } - result = Some(LinkEntry { + Some(LinkEntry { span: cx.attr_span, kind: kind.unwrap_or(NativeLibKind::Unspecified), name, cfg, verbatim, import_name_type, - }); - result + }) } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b34a64108e3b..20cdd79c3470 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -873,6 +873,7 @@ symbols! { div, div_assign, diverging_block_default, + dl, do_not_recommend, doc, doc_alias, diff --git a/tests/ui/attributes/link-dl.allowed.stderr b/tests/ui/attributes/link-dl.allowed.stderr new file mode 100644 index 000000000000..e0070d970595 --- /dev/null +++ b/tests/ui/attributes/link-dl.allowed.stderr @@ -0,0 +1,10 @@ +Future incompatibility report: Future breakage diagnostic: +warning: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", wasm_import_module = "...")]` + --> $DIR/link-dl.rs:14:1 + | +LL | #[link="dl"] + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + diff --git a/tests/ui/attributes/link-dl.default_fcw.stderr b/tests/ui/attributes/link-dl.default_fcw.stderr index 6bff216ad03f..249895fd17d0 100644 --- a/tests/ui/attributes/link-dl.default_fcw.stderr +++ b/tests/ui/attributes/link-dl.default_fcw.stderr @@ -1,26 +1,23 @@ -error[E0539]: malformed `link` attribute input +error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", wasm_import_module = "...")]` --> $DIR/link-dl.rs:14:1 | LL | #[link="dl"] - | ^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^^^ | - = note: for more information, visit -help: try changing it to one of the following valid forms of the attribute - | -LL - #[link="dl"] -LL + #[link(name = "...")] - | -LL - #[link="dl"] -LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] - | -LL - #[link="dl"] -LL + #[link(name = "...", kind = "dylib|static|...")] - | -LL - #[link="dl"] -LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] - | - = and 1 other candidate + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0539`. +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", wasm_import_module = "...")]` + --> $DIR/link-dl.rs:14:1 + | +LL | #[link="dl"] + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + From 2688f601ddc29b75caa2c48a4badc00d15042d7a Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 4 Oct 2025 16:07:06 +0200 Subject: [PATCH 522/537] Make `fmt::Write` a diagnostic item --- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/fmt/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b34a64108e3b..083e04730bc3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -236,6 +236,7 @@ symbols! { File, FileType, FmtArgumentsNew, + FmtWrite, Fn, FnMut, FnOnce, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index fcd2e52101ff..0f255e57fe58 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -115,6 +115,7 @@ pub struct Error; /// [`std::io::Write`]: ../../std/io/trait.Write.html /// [flushable]: ../../std/io/trait.Write.html#tymethod.flush #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "FmtWrite"] pub trait Write { /// Writes a string slice into this writer, returning whether the write /// succeeded. From b4578775b471b723b2210a838d6a8521f45de1db Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 4 Oct 2025 10:22:41 -0400 Subject: [PATCH 523/537] Update cargo submodule --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 2394ea6cea8b..801d9b4981dd 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2394ea6cea8b26d717aa67eb1663a2dbf2d26078 +Subproject commit 801d9b4981dd07e3aecdca1ab86834c13615737e From 67bc0308336a115c3ea45130d9845a97f33b8196 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sat, 4 Oct 2025 17:43:59 +0000 Subject: [PATCH 524/537] change flt back to ftl --- compiler/rustc_attr_parsing/messages.ftl | 157 ++++++++++----------- compiler/rustc_builtin_macros/messages.ftl | 18 +-- compiler/rustc_codegen_ssa/messages.ftl | 4 +- compiler/rustc_const_eval/messages.ftl | 8 +- compiler/rustc_expand/messages.ftl | 10 +- compiler/rustc_lint/messages.ftl | 16 +-- compiler/rustc_metadata/messages.ftl | 25 ++-- compiler/rustc_middle/messages.ftl | 6 +- compiler/rustc_parse/messages.ftl | 15 +- compiler/rustc_passes/messages.ftl | 8 +- compiler/rustc_resolve/messages.ftl | 12 +- compiler/rustc_ty_utils/messages.ftl | 4 - src/tools/tidy/src/fluent_alphabetical.rs | 2 +- 13 files changed, 135 insertions(+), 150 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 6c5346e83554..a432fa099ef4 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -1,3 +1,9 @@ +attr_parsing_as_needed_compatibility = + linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds + +attr_parsing_bundle_needs_static = + linking modifier `bundle` is only compatible with `static` linking kind + attr_parsing_cfg_predicate_identifier = `cfg` predicate key must be an identifier @@ -18,16 +24,12 @@ attr_parsing_empty_attribute = } -attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} - .help = `#[{$name}]` can {$only}be applied to {$applied} - .suggestion = remove the attribute -attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} - .warn = {-attr_parsing_previously_accepted} - .help = `#[{$name}]` can {$only}be applied to {$applied} - .suggestion = remove the attribute - attr_parsing_empty_confusables = expected at least one confusable name +attr_parsing_empty_link_name = + link name must not be empty + .label = empty link name + attr_parsing_expected_one_cfg_pattern = expected 1 cfg-pattern @@ -48,6 +50,15 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions -> *[other] valid forms for the attribute are {$suggestions} } +attr_parsing_import_name_type_raw = + import name type can only be used with link kind `raw-dylib` + +attr_parsing_import_name_type_x86 = + import name type is only supported on x86 + +attr_parsing_incompatible_wasm_link = + `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -67,6 +78,11 @@ attr_parsing_incorrect_repr_format_packed_one_or_zero_arg = attr_parsing_invalid_alignment_value = invalid alignment value: {$error_part} +attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .label = this is not an unsafe attribute + .suggestion = remove the `unsafe(...)` + .note = extraneous unsafe is not allowed in attributes + attr_parsing_invalid_issue_string = `issue` must be a non-zero numeric string or "none" .must_not_be_zero = `issue` must not be "0", use "none" instead @@ -75,6 +91,13 @@ attr_parsing_invalid_issue_string = .pos_overflow = number too large to fit in target type .neg_overflow = number too small to fit in target type +attr_parsing_invalid_link_modifier = + invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + +attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr} + .remove_neg_sugg = negative numbers are not literals, try removing the `-` sign + .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal + attr_parsing_invalid_predicate = invalid predicate `{$predicate}` @@ -100,9 +123,36 @@ attr_parsing_invalid_style = {$is_used_as_inner -> } .note = This attribute does not have an `!`, which means it is applied to this {$target} +attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} + .help = `#[{$name}]` can {$only}be applied to {$applied} + .suggestion = remove the attribute +attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} + .warn = {-attr_parsing_previously_accepted} + .help = `#[{$name}]` can {$only}be applied to {$applied} + .suggestion = remove the attribute + +attr_parsing_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} +attr_parsing_link_arg_unstable = + link kind `link-arg` is unstable + +attr_parsing_link_cfg_unstable = + link cfg is unstable + +attr_parsing_link_framework_apple = + link kind `framework` is only supported on Apple targets + attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}` .note = the value may not exceed `u16::MAX` +attr_parsing_link_requires_name = + `#[link]` attribute requires a `name = "string"` argument + .label = missing `name` argument + +attr_parsing_meta_bad_delim = wrong meta list delimiters +attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)` + attr_parsing_missing_feature = missing 'feature' @@ -115,6 +165,9 @@ attr_parsing_missing_note = attr_parsing_missing_since = missing 'since' +attr_parsing_multiple_modifiers = + multiple `{$modifier}` modifiers in a single `modifiers` argument + attr_parsing_multiple_stability_levels = multiple stability levels @@ -138,6 +191,15 @@ attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a stri attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal +attr_parsing_raw_dylib_elf_unstable = + link kind `raw-dylib` is unstable on ELF platforms + +attr_parsing_raw_dylib_no_nul = + link name must not contain NUL characters if link kind is `raw-dylib` + +attr_parsing_raw_dylib_only_windows = + link kind `raw-dylib` is only supported on Windows targets + attr_parsing_repr_ident = meta item in `repr` must be an identifier @@ -152,6 +214,9 @@ attr_parsing_soft_no_args = attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library +attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes + .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + attr_parsing_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} @@ -164,6 +229,10 @@ attr_parsing_unrecognized_repr_hint = .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` .note = for more information, visit +attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change @@ -193,77 +262,5 @@ attr_parsing_unused_multiple = -attr_parsing_previously_accepted = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -attr_parsing_meta_bad_delim = wrong meta list delimiters -attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)` - -attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe - .label = usage of unsafe attribute -attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` - -attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute - .label = this is not an unsafe attribute - .suggestion = remove the `unsafe(...)` - .note = extraneous unsafe is not allowed in attributes - -attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr} - .remove_neg_sugg = negative numbers are not literals, try removing the `-` sign - .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal - -attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes - .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -attr_parsing_as_needed_compatibility = - linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds - -attr_parsing_bundle_needs_static = - linking modifier `bundle` is only compatible with `static` linking kind - -attr_parsing_empty_link_name = - link name must not be empty - .label = empty link name - -attr_parsing_import_name_type_raw = - import name type can only be used with link kind `raw-dylib` - -attr_parsing_import_name_type_x86 = - import name type is only supported on x86 - -attr_parsing_incompatible_wasm_link = - `wasm_import_module` is incompatible with other arguments in `#[link]` attributes - -attr_parsing_invalid_link_modifier = - invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed - -attr_parsing_link_arg_unstable = - link kind `link-arg` is unstable - -attr_parsing_link_cfg_unstable = - link cfg is unstable - -attr_parsing_link_framework_apple = - link kind `framework` is only supported on Apple targets - -attr_parsing_link_requires_name = - `#[link]` attribute requires a `name = "string"` argument - .label = missing `name` argument - -attr_parsing_multiple_modifiers = - multiple `{$modifier}` modifiers in a single `modifiers` argument - -attr_parsing_multiple_renamings = - multiple renamings were specified for library `{$lib_name}` -attr_parsing_raw_dylib_no_nul = - link name must not contain NUL characters if link kind is `raw-dylib` - -attr_parsing_raw_dylib_elf_unstable = - link kind `raw-dylib` is unstable on ELF platforms - -attr_parsing_raw_dylib_only_windows = - link kind `raw-dylib` is only supported on Windows targets - attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind - -attr_parsing_limit_invalid = - `limit` must be a non-negative integer - .label = {$error_str} diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 7c1a5f44e165..cbdd8199d7ba 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -135,6 +135,15 @@ builtin_macros_concat_missing_literal = expected a literal builtin_macros_default_arg = `#[default]` attribute does not accept a value .suggestion = try using `#[default]` +builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field + +builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields -> + [true] multiple fields + *[false] no fields +} + +builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind} + builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments @@ -229,15 +238,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead -builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind} - -builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields -> - [true] multiple fields - *[false] no fields -} - -builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field - builtin_macros_incomplete_include = include macro expected single expression in source builtin_macros_multiple_default_attrs = multiple `#[default]` attributes diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 91c3806df4c3..97ff04f66dae 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -97,10 +97,10 @@ codegen_ssa_invalid_literal_value = invalid literal value codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` -codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` - codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}` +codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` + codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}` diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 010ffa60c7a5..13a49e80cf2d 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -231,9 +231,6 @@ const_eval_mutable_borrow_escaping = const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} -const_eval_partial_pointer_in_final = encountered partial pointer in final value of {const_eval_intern_kind} - .note = while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value - const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead const_eval_non_const_await = @@ -302,6 +299,9 @@ const_eval_panic = evaluation panicked: {$msg} const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` +const_eval_partial_pointer_in_final = encountered partial pointer in final value of {const_eval_intern_kind} + .note = while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value + const_eval_partial_pointer_read = unable to read parts of a pointer from memory at {$ptr} const_eval_pointer_arithmetic_overflow = @@ -476,6 +476,7 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` +const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero const_eval_validation_null_box = {$front_matter}: encountered a {$maybe -> [true] maybe-null *[false] null @@ -485,7 +486,6 @@ const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe -> [true] maybe-null *[false] null } reference -const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 47c00bff5c95..e914f24e294c 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -95,6 +95,8 @@ expand_malformed_feature_attribute = malformed `feature` attribute input .expected = expected just one word +expand_meta_var_dif_seq_matchers = {$msg} + expand_metavar_still_repeating = variable `{$ident}` is still repeating at this depth .label = expected repetition @@ -102,8 +104,6 @@ expand_metavariable_wrong_operator = meta-variable repeats with different Kleene .binder_label = expected repetition .occurrence_label = conflicting repetition -expand_meta_var_dif_seq_matchers = {$msg} - expand_missing_fragment_specifier = missing fragment specifier .note = fragment specifiers must be provided .suggestion_add_fragspec = try adding a specifier here @@ -198,12 +198,12 @@ expand_trailing_semi_macro = trailing semicolon in macro used in expression posi expand_unknown_macro_variable = unknown macro variable `{$name}` +expand_unsupported_key_value = + key-value macro attributes are not supported + expand_unused_builtin_attribute = unused attribute `{$attr_name}` .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}` .suggestion = remove the attribute -expand_unsupported_key_value = - key-value macro attributes are not supported - expand_wrong_fragment_kind = non-{$kind} macro in {$kind} position: {$name} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5b98c9fafaad..bc0a98fc7aa8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -392,6 +392,14 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance + .note = this is dangerous because dereferencing the resulting pointer is undefined behavior + .note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance + .help_transmute = for more information about transmute, see + .help_exposed_provenance = for more information about exposed provenance, see + .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance + .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` + lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly .label = use a different label that doesn't start with `0` or `1` .help = start numbering with `2` instead @@ -439,14 +447,6 @@ lint_invalid_reference_casting_note_book = for more information, visit - .help_exposed_provenance = for more information about exposed provenance, see - .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance - .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` - lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index e624bfc5b8bd..fac7b6c21f60 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -98,13 +98,6 @@ metadata_full_metadata_not_found = metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait -metadata_incompatible_with_immediate_abort = - the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort` - -metadata_incompatible_with_immediate_abort_core = - the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` - .help = consider building the standard library from source with `cargo build -Zbuild-std` - metadata_incompatible_panic_in_drop_strategy = the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` @@ -132,6 +125,13 @@ metadata_incompatible_target_modifiers_r_missed = .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}` .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely +metadata_incompatible_with_immediate_abort = + the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort` + +metadata_incompatible_with_immediate_abort_core = + the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` + .help = consider building the standard library from source with `cargo build -Zbuild-std` + metadata_install_missing_components = maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` @@ -197,6 +197,8 @@ metadata_prev_alloc_error_handler = metadata_prev_global_alloc = previous global allocator defined here +metadata_raw_dylib_malformed = + link name must be well-formed if link kind is `raw-dylib` metadata_raw_dylib_unsupported_abi = ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture @@ -236,12 +238,3 @@ metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$fla metadata_wasm_c_abi = older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88 - -metadata_wasm_import_form = - wasm import module must be of the form `wasm_import_module = "string"` - -metadata_whole_archive_needs_static = - linking modifier `whole-archive` is only compatible with `static` linking kind - -metadata_raw_dylib_malformed = - link name must be well-formed if link kind is `raw-dylib` diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 82f3df8da3b1..b46f43841c8e 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -95,15 +95,15 @@ middle_layout_normalization_failure = middle_layout_references_error = the type has an unknown layout -middle_layout_size_overflow = - values of the type `{$ty}` are too big for the target architecture - middle_layout_simd_too_many = the SIMD type `{$ty}` has more elements than the limit {$max_lanes} middle_layout_simd_zero_length = the SIMD type `{$ty}` has zero elements +middle_layout_size_overflow = + values of the type `{$ty}` are too big for the target architecture + middle_layout_too_generic = the type `{$ty}` does not have a fixed layout middle_layout_unknown = diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f83cf645f829..b1894ab92192 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -68,6 +68,13 @@ parse_attr_after_generic = trailing attribute after generic parameter parse_attr_without_generics = attribute without generic parameters .label = attributes are only permitted when preceding parameters +parse_attribute_on_empty_type = attributes cannot be applied here + .label = attributes are not allowed here + +parse_attribute_on_generic_arg = attributes cannot be applied to generic arguments + .label = attributes are not allowed here + .suggestion = remove attribute from here + parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type .label = attributes are not allowed here @@ -75,13 +82,6 @@ parse_attribute_on_type = attributes cannot be applied to types .label = attributes are not allowed here .suggestion = remove attribute from here -parse_attribute_on_generic_arg = attributes cannot be applied to generic arguments - .label = attributes are not allowed here - .suggestion = remove attribute from here - -parse_attribute_on_empty_type = attributes cannot be applied here - .label = attributes are not allowed here - parse_bad_assoc_type_bounds = bounds on associated types do not belong here .label = belongs in `where` clause @@ -868,7 +868,6 @@ parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up parse_too_short_hex_escape = numeric character escape is too short parse_trailing_vert_not_allowed = a trailing `{$token}` is not allowed in an or-pattern -parse_trailing_vert_not_allowed_suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` parse_trait_alias_cannot_be_const = trait aliases cannot be `const` diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index df4016dfa1b8..9971f0c3fa32 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -13,10 +13,6 @@ passes_abi_ne = passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} -passes_macro_only_attribute = - attribute should be applied to a macro - .label = not a macro - passes_attr_application_enum = attribute should be applied to an enum .label = not an enum @@ -392,6 +388,10 @@ passes_macro_export_on_decl_macro = `#[macro_export]` has no effect on declarative macro definitions .note = declarative macros follow the same exporting rules as regular items +passes_macro_only_attribute = + attribute should be applied to a macro + .label = not a macro + passes_may_dangle = `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index cc8fbc18b737..5bf90d2637df 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -93,9 +93,6 @@ resolve_consider_adding_a_derive = resolve_consider_adding_macro_export = consider adding a `#[macro_export]` to the macro in the imported module -resolve_consider_marking_as_pub_crate = - in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)` - resolve_consider_declaring_with_pub = consider declaring type or module `{$ident}` with `pub` @@ -108,6 +105,9 @@ resolve_consider_making_the_field_public = resolve_consider_marking_as_pub = consider marking `{$ident}` as `pub` in the imported module +resolve_consider_marking_as_pub_crate = + in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)` + resolve_consider_move_macro_position = consider moving the definition of `{$ident}` before this call @@ -248,15 +248,15 @@ resolve_lowercase_self = attempt to use a non-constant value in a constant .suggestion = try using `Self` -resolve_macro_cannot_use_as_fn_like = - `{$ident}` exists, but has no rules for function-like invocation - resolve_macro_cannot_use_as_attr = `{$ident}` exists, but has no `attr` rules resolve_macro_cannot_use_as_derive = `{$ident}` exists, but has no `derive` rules +resolve_macro_cannot_use_as_fn_like = + `{$ident}` exists, but has no rules for function-like invocation + resolve_macro_defined_later = a macro with the same name exists, but it appears later diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index 8bc7bf10865f..c1684bfb43b6 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -52,8 +52,6 @@ ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-p ty_utils_operation_not_supported = unsupported operation in generic constants -ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} - ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants ty_utils_tuple_not_supported = tuple construction is not supported in generic constants @@ -61,5 +59,3 @@ ty_utils_tuple_not_supported = tuple construction is not supported in generic co ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item ty_utils_yield_not_supported = coroutine control flow is not allowed in generic constants - -ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs index 02b914c21aeb..b1d1c16b4549 100644 --- a/src/tools/tidy/src/fluent_alphabetical.rs +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -15,7 +15,7 @@ fn message() -> &'static Regex { } fn is_fluent(path: &Path) -> bool { - path.extension().is_some_and(|ext| ext == "flt") + path.extension().is_some_and(|ext| ext == "ftl") } fn check_alphabetic( From b5fb01d67db9726180fd85b58d00e3b954fc7e45 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 4 Oct 2025 15:53:00 -0400 Subject: [PATCH 525/537] Improve the advice given by panic_immediate_abort --- library/core/src/panicking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 3f30038dbc03..b5150837e6a9 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -35,7 +35,8 @@ use crate::panic::{Location, PanicInfo}; #[cfg(feature = "panic_immediate_abort")] compile_error!( "panic_immediate_abort is now a real panic strategy! \ - Enable it with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`" + Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \ + or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`" ); // First we define the two main entry points that all panics go through. From 757d98ce2b55162e22051be354418291e88f8d46 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 3 Oct 2025 13:20:39 +1000 Subject: [PATCH 526/537] Move `DirectiveLine` into its own submodule --- src/tools/compiletest/src/directives.rs | 68 +------------------- src/tools/compiletest/src/directives/line.rs | 67 +++++++++++++++++++ 2 files changed, 69 insertions(+), 66 deletions(-) create mode 100644 src/tools/compiletest/src/directives/line.rs diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index a79978d036ce..edb06dd7345d 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -15,6 +15,7 @@ use crate::directives::auxiliary::{AuxProps, parse_and_update_aux}; use crate::directives::directive_names::{ KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES, }; +use crate::directives::line::{DirectiveLine, line_directive}; use crate::directives::needs::CachedNeedsConditions; use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; @@ -25,6 +26,7 @@ use crate::{fatal, help}; pub(crate) mod auxiliary; mod cfg; mod directive_names; +mod line; mod needs; #[cfg(test)] mod tests; @@ -824,70 +826,6 @@ impl TestProps { } } -/// If the given line begins with the appropriate comment prefix for a directive, -/// returns a struct containing various parts of the directive. -fn line_directive<'line>( - line_number: usize, - original_line: &'line str, -) -> Option> { - // Ignore lines that don't start with the comment prefix. - let after_comment = - original_line.trim_start().strip_prefix(COMPILETEST_DIRECTIVE_PREFIX)?.trim_start(); - - let revision; - let raw_directive; - - if let Some(after_open_bracket) = after_comment.strip_prefix('[') { - // A comment like `//@[foo]` only applies to revision `foo`. - let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { - panic!( - "malformed condition directive: expected `{COMPILETEST_DIRECTIVE_PREFIX}[foo]`, found `{original_line}`" - ) - }; - - revision = Some(line_revision); - raw_directive = after_close_bracket.trim_start(); - } else { - revision = None; - raw_directive = after_comment; - }; - - Some(DirectiveLine { line_number, revision, raw_directive }) -} - -/// The (partly) broken-down contents of a line containing a test directive, -/// which [`iter_directives`] passes to its callback function. -/// -/// For example: -/// -/// ```text -/// //@ compile-flags: -O -/// ^^^^^^^^^^^^^^^^^ raw_directive -/// -/// //@ [foo] compile-flags: -O -/// ^^^ revision -/// ^^^^^^^^^^^^^^^^^ raw_directive -/// ``` -struct DirectiveLine<'ln> { - line_number: usize, - /// Some test directives start with a revision name in square brackets - /// (e.g. `[foo]`), and only apply to that revision of the test. - /// If present, this field contains the revision name (e.g. `foo`). - revision: Option<&'ln str>, - /// The main part of the directive, after removing the comment prefix - /// and the optional revision specifier. - /// - /// This is "raw" because the directive's name and colon-separated value - /// (if present) have not yet been extracted or checked. - raw_directive: &'ln str, -} - -impl<'ln> DirectiveLine<'ln> { - fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool { - self.revision.is_none() || self.revision == test_revision - } -} - pub(crate) struct CheckDirectiveResult<'ln> { is_known_directive: bool, trailing_directive: Option<&'ln str>, @@ -920,8 +858,6 @@ fn check_directive<'a>( CheckDirectiveResult { is_known_directive, trailing_directive } } -const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; - fn iter_directives( mode: TestMode, poisoned: &mut bool, diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs new file mode 100644 index 000000000000..584d5b5b35be --- /dev/null +++ b/src/tools/compiletest/src/directives/line.rs @@ -0,0 +1,67 @@ +const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; + +/// If the given line begins with the appropriate comment prefix for a directive, +/// returns a struct containing various parts of the directive. +pub(crate) fn line_directive<'line>( + line_number: usize, + original_line: &'line str, +) -> Option> { + // Ignore lines that don't start with the comment prefix. + let after_comment = + original_line.trim_start().strip_prefix(COMPILETEST_DIRECTIVE_PREFIX)?.trim_start(); + + let revision; + let raw_directive; + + if let Some(after_open_bracket) = after_comment.strip_prefix('[') { + // A comment like `//@[foo]` only applies to revision `foo`. + let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { + panic!( + "malformed condition directive: expected `{COMPILETEST_DIRECTIVE_PREFIX}[foo]`, found `{original_line}`" + ) + }; + + revision = Some(line_revision); + raw_directive = after_close_bracket.trim_start(); + } else { + revision = None; + raw_directive = after_comment; + }; + + Some(DirectiveLine { line_number, revision, raw_directive }) +} + +/// The (partly) broken-down contents of a line containing a test directive, +/// which `iter_directives` passes to its callback function. +/// +/// For example: +/// +/// ```text +/// //@ compile-flags: -O +/// ^^^^^^^^^^^^^^^^^ raw_directive +/// +/// //@ [foo] compile-flags: -O +/// ^^^ revision +/// ^^^^^^^^^^^^^^^^^ raw_directive +/// ``` +pub(crate) struct DirectiveLine<'ln> { + pub(crate) line_number: usize, + + /// Some test directives start with a revision name in square brackets + /// (e.g. `[foo]`), and only apply to that revision of the test. + /// If present, this field contains the revision name (e.g. `foo`). + pub(crate) revision: Option<&'ln str>, + + /// The main part of the directive, after removing the comment prefix + /// and the optional revision specifier. + /// + /// This is "raw" because the directive's name and colon-separated value + /// (if present) have not yet been extracted or checked. + pub(crate) raw_directive: &'ln str, +} + +impl<'ln> DirectiveLine<'ln> { + pub(crate) fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool { + self.revision.is_none() || self.revision == test_revision + } +} From 6783e9465b62e77c7e3cb76a747d92b1de4339f7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 20:08:40 +1000 Subject: [PATCH 527/537] Allow easy extraction of name/value from a `DirectiveLine` --- src/tools/compiletest/src/directives.rs | 10 +++-- src/tools/compiletest/src/directives/line.rs | 45 +++++++++++++++++++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index edb06dd7345d..bbbeecc1b71b 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -875,15 +875,17 @@ fn iter_directives( // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. if mode == TestMode::CoverageRun { let extra_directives: &[&str] = &[ - "needs-profiler-runtime", + "//@ needs-profiler-runtime", // FIXME(pietroalbini): this test currently does not work on cross-compiled targets // because remote-test is not capable of sending back the *.profraw files generated by // the LLVM instrumentation. - "ignore-cross-compile", + "//@ ignore-cross-compile", ]; // Process the extra implied directives, with a dummy line number of 0. - for raw_directive in extra_directives { - it(DirectiveLine { line_number: 0, revision: None, raw_directive }); + for directive_str in extra_directives { + let directive_line = line_directive(0, directive_str) + .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}")); + it(directive_line); } } diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs index 584d5b5b35be..5c1b592d045d 100644 --- a/src/tools/compiletest/src/directives/line.rs +++ b/src/tools/compiletest/src/directives/line.rs @@ -1,3 +1,7 @@ +#![expect(dead_code)] // (removed later in this PR) + +use std::fmt; + const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; /// If the given line begins with the appropriate comment prefix for a directive, @@ -28,7 +32,10 @@ pub(crate) fn line_directive<'line>( raw_directive = after_comment; }; - Some(DirectiveLine { line_number, revision, raw_directive }) + // The directive name ends at the first occurrence of colon, space, or end-of-string. + let name = raw_directive.split([':', ' ']).next().expect("split is never empty"); + + Some(DirectiveLine { line_number, revision, raw_directive, name }) } /// The (partly) broken-down contents of a line containing a test directive, @@ -39,10 +46,12 @@ pub(crate) fn line_directive<'line>( /// ```text /// //@ compile-flags: -O /// ^^^^^^^^^^^^^^^^^ raw_directive +/// ^^^^^^^^^^^^^ name /// /// //@ [foo] compile-flags: -O /// ^^^ revision /// ^^^^^^^^^^^^^^^^^ raw_directive +/// ^^^^^^^^^^^^^ name /// ``` pub(crate) struct DirectiveLine<'ln> { pub(crate) line_number: usize, @@ -58,10 +67,44 @@ pub(crate) struct DirectiveLine<'ln> { /// This is "raw" because the directive's name and colon-separated value /// (if present) have not yet been extracted or checked. pub(crate) raw_directive: &'ln str, + + /// Name of the directive. + /// + /// Invariant: `self.raw_directive.starts_with(self.name)` + pub(crate) name: &'ln str, } impl<'ln> DirectiveLine<'ln> { pub(crate) fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool { self.revision.is_none() || self.revision == test_revision } + + /// Helper method used by `value_after_colon` and `remark_after_space`. + /// Don't call this directly. + fn rest_after_separator(&self, separator: u8) -> Option<&'ln str> { + let n = self.name.len(); + if self.raw_directive.as_bytes().get(n) != Some(&separator) { + return None; + } + + Some(&self.raw_directive[n + 1..]) + } + + /// If this directive uses `name: value` syntax, returns the part after + /// the colon character. + pub(crate) fn value_after_colon(&self) -> Option<&'ln str> { + self.rest_after_separator(b':') + } + + /// If this directive uses `name remark` syntax, returns the part after + /// the separating space. + pub(crate) fn remark_after_space(&self) -> Option<&'ln str> { + self.rest_after_separator(b' ') + } + + /// Allows callers to print `raw_directive` if necessary, + /// without accessing the field directly. + pub(crate) fn display(&self) -> impl fmt::Display { + self.raw_directive + } } From 33c99a0468302f1bb9bd7dd0d63d460b1a88ed52 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 Oct 2025 20:16:59 +1000 Subject: [PATCH 528/537] Use new `DirectiveLine` features in directive parsing --- src/tools/compiletest/src/directives.rs | 100 +++++++++--------- .../compiletest/src/directives/auxiliary.rs | 4 +- src/tools/compiletest/src/directives/cfg.rs | 26 ++--- src/tools/compiletest/src/directives/line.rs | 4 +- src/tools/compiletest/src/directives/needs.rs | 15 +-- src/tools/compiletest/src/directives/tests.rs | 13 +-- 6 files changed, 73 insertions(+), 89 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index bbbeecc1b71b..dab6850e0d62 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -835,9 +835,7 @@ fn check_directive<'a>( directive_ln: &DirectiveLine<'a>, mode: TestMode, ) -> CheckDirectiveResult<'a> { - let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln; - - let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); + let &DirectiveLine { name: directive_name, .. } = directive_ln; let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name) || match mode { @@ -846,14 +844,13 @@ fn check_directive<'a>( _ => false, }; - let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post); - let trailing_directive = { - // 1. is the directive name followed by a space? (to exclude `:`) - directive_ln.get(directive_name.len()..).is_some_and(|s| s.starts_with(' ')) - // 2. is what is after that directive also a directive (ex: "only-x86 only-arm") - && KNOWN_DIRECTIVE_NAMES.contains(&trailing) - } - .then_some(trailing); + // If it looks like the user tried to put two directives on the same line + // (e.g. `//@ only-linux only-x86_64`), signal an error, because the + // second "directive" would actually be ignored with no effect. + let trailing_directive = directive_ln + .remark_after_space() + .map(|remark| remark.trim_start().split(' ').next().unwrap()) + .filter(|token| KNOWN_DIRECTIVE_NAMES.contains(token)); CheckDirectiveResult { is_known_directive, trailing_directive } } @@ -915,7 +912,7 @@ fn iter_directives( error!( "{testfile}:{line_number}: detected unknown compiletest test directive `{}`", - directive_line.raw_directive, + directive_line.display(), ); return; @@ -1011,13 +1008,9 @@ impl Config { } fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option { - let &DirectiveLine { raw_directive, .. } = line; + let &DirectiveLine { name, .. } = line; - // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine` - // instead of doing it here. - let (directive_name, raw_value) = raw_directive.split_once(':')?; - - let kind = match directive_name { + let kind = match name { "normalize-stdout" => NormalizeKind::Stdout, "normalize-stderr" => NormalizeKind::Stderr, "normalize-stderr-32bit" => NormalizeKind::Stderr32bit, @@ -1025,21 +1018,20 @@ impl Config { _ => return None, }; - let Some((regex, replacement)) = parse_normalize_rule(raw_value) else { - error!("couldn't parse custom normalization rule: `{raw_directive}`"); - help!("expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`"); + let Some((regex, replacement)) = line.value_after_colon().and_then(parse_normalize_rule) + else { + error!("couldn't parse custom normalization rule: `{}`", line.display()); + help!("expected syntax is: `{name}: \"REGEX\" -> \"REPLACEMENT\"`"); panic!("invalid normalization rule detected"); }; Some(NormalizeRule { kind, regex, replacement }) } fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool { - let &DirectiveLine { raw_directive: line, .. } = line; - - // Ensure the directive is a whole word. Do not match "ignore-x86" when - // the line says "ignore-x86_64". - line.starts_with(directive) - && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':')) + // FIXME(Zalathar): Ideally, this should raise an error if a name-only + // directive is followed by a colon, since that's the wrong syntax. + // But we would need to fix tests that rely on the current behaviour. + line.name == directive } fn parse_name_value_directive( @@ -1048,22 +1040,26 @@ impl Config { directive: &str, testfile: &Utf8Path, ) -> Option { - let &DirectiveLine { line_number, raw_directive: line, .. } = line; + let &DirectiveLine { line_number, .. } = line; - let colon = directive.len(); - if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') { - let value = line[(colon + 1)..].to_owned(); - debug!("{}: {}", directive, value); - let value = expand_variables(value, self); - if value.is_empty() { - error!("{testfile}:{line_number}: empty value for directive `{directive}`"); - help!("expected syntax is: `{directive}: value`"); - panic!("empty directive value detected"); - } - Some(value) - } else { - None + if line.name != directive { + return None; + }; + + // FIXME(Zalathar): This silently discards directives with a matching + // name but no colon. Unfortunately, some directives (e.g. "pp-exact") + // currently rely on _not_ panicking here. + let value = line.value_after_colon()?; + debug!("{}: {}", directive, value); + let value = expand_variables(value.to_owned(), self); + + if value.is_empty() { + error!("{testfile}:{line_number}: empty value for directive `{directive}`"); + help!("expected syntax is: `{directive}: value`"); + panic!("empty directive value detected"); } + + Some(value) } fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) { @@ -1453,14 +1449,14 @@ pub(crate) fn make_test_description( } fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let &DirectiveLine { raw_directive: line, .. } = line; - if config.debugger != Some(Debugger::Cdb) { return IgnoreDecision::Continue; } if let Some(actual_version) = config.cdb_version { - if let Some(rest) = line.strip_prefix("min-cdb-version:").map(str::trim) { + if line.name == "min-cdb-version" + && let Some(rest) = line.value_after_colon().map(str::trim) + { let min_version = extract_cdb_version(rest).unwrap_or_else(|| { panic!("couldn't parse version range: {:?}", rest); }); @@ -1478,14 +1474,14 @@ fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { } fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let &DirectiveLine { raw_directive: line, .. } = line; - if config.debugger != Some(Debugger::Gdb) { return IgnoreDecision::Continue; } if let Some(actual_version) = config.gdb_version { - if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { + if line.name == "min-gdb-version" + && let Some(rest) = line.value_after_colon().map(str::trim) + { let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version) .unwrap_or_else(|| { panic!("couldn't parse version range: {:?}", rest); @@ -1501,7 +1497,9 @@ fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { reason: format!("ignored when the GDB version is lower than {rest}"), }; } - } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { + } else if line.name == "ignore-gdb-version" + && let Some(rest) = line.value_after_colon().map(str::trim) + { let (min_version, max_version) = extract_version_range(rest, extract_gdb_version) .unwrap_or_else(|| { panic!("couldn't parse version range: {:?}", rest); @@ -1528,14 +1526,14 @@ fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { } fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let &DirectiveLine { raw_directive: line, .. } = line; - if config.debugger != Some(Debugger::Lldb) { return IgnoreDecision::Continue; } if let Some(actual_version) = config.lldb_version { - if let Some(rest) = line.strip_prefix("min-lldb-version:").map(str::trim) { + if line.name == "min-lldb-version" + && let Some(rest) = line.value_after_colon().map(str::trim) + { let min_version = rest.parse().unwrap_or_else(|e| { panic!("Unexpected format of LLDB version string: {}\n{:?}", rest, e); }); diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 0675a6feac3f..7cf98178e733 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -50,9 +50,7 @@ pub(super) fn parse_and_update_aux( testfile: &Utf8Path, aux: &mut AuxProps, ) { - let &DirectiveLine { raw_directive: ln, .. } = directive_line; - - if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) { + if !(directive_line.name.starts_with("aux-") || directive_line.name == "proc-macro") { return; } diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 62a4b88a33a6..3855ba7ac5f4 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -6,8 +6,8 @@ use crate::directives::{DirectiveLine, IgnoreDecision}; const EXTRA_ARCHS: &[&str] = &["spirv"]; pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "ignore"); - let &DirectiveLine { raw_directive: line, .. } = line; + let parsed = parse_cfg_name_directive(config, line, "ignore-"); + let line = line.display(); match parsed.outcome { MatchOutcome::NoMatch => IgnoreDecision::Continue, @@ -24,8 +24,8 @@ pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> Ignore } pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { - let parsed = parse_cfg_name_directive(config, line, "only"); - let &DirectiveLine { raw_directive: line, .. } = line; + let parsed = parse_cfg_name_directive(config, line, "only-"); + let line = line.display(); match parsed.outcome { MatchOutcome::Match => IgnoreDecision::Continue, @@ -50,18 +50,14 @@ fn parse_cfg_name_directive<'a>( line: &'a DirectiveLine<'a>, prefix: &str, ) -> ParsedNameDirective<'a> { - let &DirectiveLine { raw_directive: line, .. } = line; - - if !line.as_bytes().starts_with(prefix.as_bytes()) { + let Some(name) = line.name.strip_prefix(prefix) else { return ParsedNameDirective::not_a_directive(); - } - if line.as_bytes().get(prefix.len()) != Some(&b'-') { - return ParsedNameDirective::not_a_directive(); - } - let line = &line[prefix.len() + 1..]; + }; - let (name, comment) = - line.split_once(&[':', ' ']).map(|(l, c)| (l, Some(c))).unwrap_or((line, None)); + // FIXME(Zalathar): This currently allows either a space or a colon, and + // treats any "value" after a colon as though it were a remark. + // We should instead forbid the colon syntax for these directives. + let comment = line.remark_after_space().or_else(|| line.value_after_colon()); // Some of the matchers might be "" depending on what the target information is. To avoid // problems we outright reject empty directives. @@ -269,7 +265,7 @@ fn parse_cfg_name_directive<'a>( message: "when performing tests on dist toolchain" } - if prefix == "ignore" && outcome == MatchOutcome::Invalid { + if prefix == "ignore-" && outcome == MatchOutcome::Invalid { // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest. if name.starts_with("tidy-") { outcome = MatchOutcome::External; diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs index 5c1b592d045d..49907207d2e6 100644 --- a/src/tools/compiletest/src/directives/line.rs +++ b/src/tools/compiletest/src/directives/line.rs @@ -1,5 +1,3 @@ -#![expect(dead_code)] // (removed later in this PR) - use std::fmt; const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; @@ -66,7 +64,7 @@ pub(crate) struct DirectiveLine<'ln> { /// /// This is "raw" because the directive's name and colon-separated value /// (if present) have not yet been extracted or checked. - pub(crate) raw_directive: &'ln str, + raw_directive: &'ln str, /// Name of the directive. /// diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 9d72492e5b07..5e9fe59d8d1c 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -181,17 +181,10 @@ pub(super) fn handle_needs( }, ]; - let &DirectiveLine { raw_directive: ln, .. } = ln; + let &DirectiveLine { name, .. } = ln; - let (name, rest) = match ln.split_once([':', ' ']) { - Some((name, rest)) => (name, Some(rest)), - None => (ln, None), - }; - - // FIXME(jieyouxu): tighten up this parsing to reject using both `:` and ` ` as means to - // delineate value. if name == "needs-target-has-atomic" { - let Some(rest) = rest else { + let Some(rest) = ln.value_after_colon() else { return IgnoreDecision::Error { message: "expected `needs-target-has-atomic` to have a comma-separated list of atomic widths".to_string(), }; @@ -233,7 +226,7 @@ pub(super) fn handle_needs( // FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above. if name == "needs-crate-type" { - let Some(rest) = rest else { + let Some(rest) = ln.value_after_colon() else { return IgnoreDecision::Error { message: "expected `needs-crate-type` to have a comma-separated list of crate types" @@ -292,7 +285,7 @@ pub(super) fn handle_needs( break; } else { return IgnoreDecision::Ignore { - reason: if let Some(comment) = rest { + reason: if let Some(comment) = ln.remark_after_space() { format!("{} ({})", need.ignore_reason, comment.trim()) } else { need.ignore_reason.into() diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 93621192d4bd..95dd46532ba8 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -3,12 +3,11 @@ use std::io::Read; use camino::Utf8Path; use semver::Version; -use super::{ - DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version, - extract_version_range, iter_directives, parse_normalize_rule, -}; use crate::common::{Config, Debugger, TestMode}; -use crate::directives::parse_edition; +use crate::directives::{ + DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version, + extract_version_range, iter_directives, line_directive, parse_edition, parse_normalize_rule, +}; use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description( @@ -955,7 +954,9 @@ fn test_needs_target_std() { fn parse_edition_range(line: &str) -> Option { let config = cfg().build(); - let line = super::DirectiveLine { line_number: 0, revision: None, raw_directive: line }; + + let line_with_comment = format!("//@ {line}"); + let line = line_directive(0, &line_with_comment).unwrap(); super::parse_edition_range(&config, &line, "tmp.rs".into()) } From 7c8fe29fd65d994e25a8eed3d0e2bbed3415ca61 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 5 Oct 2025 03:07:51 -0400 Subject: [PATCH 529/537] solve autodiffv2.rs FIXME and make identical_fnc test more robust --- tests/codegen-llvm/autodiff/autodiffv2.rs | 31 ++++++++------------ tests/codegen-llvm/autodiff/identical_fnc.rs | 4 +-- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/tests/codegen-llvm/autodiff/autodiffv2.rs b/tests/codegen-llvm/autodiff/autodiffv2.rs index 85aed6a183b6..c24a374148c3 100644 --- a/tests/codegen-llvm/autodiff/autodiffv2.rs +++ b/tests/codegen-llvm/autodiff/autodiffv2.rs @@ -18,11 +18,6 @@ // but each shadow argument is `width` times larger (thus 16 and 20 elements here). // `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the // original function arguments. -// -// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they -// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which -// try to rewrite the dummy functions later. We should consider to change to pure declarations both -// in our frontend and in the llvm backend to avoid these issues. #![feature(autodiff)] @@ -30,7 +25,7 @@ use std::autodiff::autodiff_forward; // CHECK: ; #[no_mangle] -//#[autodiff(d_square1, Forward, Dual, Dual)] +#[autodiff_forward(d_square1, Dual, Dual)] #[autodiff_forward(d_square2, 4, Dualv, Dualv)] #[autodiff_forward(d_square3, 4, Dual, Dual)] fn square(x: &[f32], y: &mut [f32]) { @@ -79,25 +74,25 @@ fn main() { let mut dy3_4 = std::hint::black_box(vec![0.0; 5]); // scalar. - //d_square1(&x1, &z1, &mut y1, &mut dy1_1); - //d_square1(&x1, &z2, &mut y2, &mut dy1_2); - //d_square1(&x1, &z3, &mut y3, &mut dy1_3); - //d_square1(&x1, &z4, &mut y4, &mut dy1_4); + d_square1(&x1, &z1, &mut y1, &mut dy1_1); + d_square1(&x1, &z2, &mut y2, &mut dy1_2); + d_square1(&x1, &z3, &mut y3, &mut dy1_3); + d_square1(&x1, &z4, &mut y4, &mut dy1_4); // assert y1 == y2 == y3 == y4 - //for i in 0..5 { - // assert_eq!(y1[i], y2[i]); - // assert_eq!(y1[i], y3[i]); - // assert_eq!(y1[i], y4[i]); - //} + for i in 0..5 { + assert_eq!(y1[i], y2[i]); + assert_eq!(y1[i], y3[i]); + assert_eq!(y1[i], y4[i]); + } // batch mode A) d_square2(&x1, &z5, &mut y5, &mut dy2); // assert y1 == y2 == y3 == y4 == y5 - //for i in 0..5 { - // assert_eq!(y1[i], y5[i]); - //} + for i in 0..5 { + assert_eq!(y1[i], y5[i]); + } // batch mode B) d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4); diff --git a/tests/codegen-llvm/autodiff/identical_fnc.rs b/tests/codegen-llvm/autodiff/identical_fnc.rs index 6066f8cb34fb..1c18e7acc4b6 100644 --- a/tests/codegen-llvm/autodiff/identical_fnc.rs +++ b/tests/codegen-llvm/autodiff/identical_fnc.rs @@ -32,9 +32,9 @@ fn square2(x: &f64) -> f64 { // CHECK-NOT:br // CHECK-NOT:ret // CHECK:; call identical_fnc::d_square -// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square17hcb5768e95528c35fE(double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx1) +// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square[[HASH:.+]](double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx1) // CHECK:; call identical_fnc::d_square -// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square17hcb5768e95528c35fE(double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx2) +// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square[[HASH]](double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx2) fn main() { let x = std::hint::black_box(3.0); From 99c7959bb7fde07f1326c52312c12671239849b7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Aug 2025 16:59:58 +0200 Subject: [PATCH 530/537] Add regression test for rustdoc output format --- .../rustdoc-doctest-output-format/file.rs | 3 + .../rustdoc-doctest-output-format/rmake.rs | 83 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tests/run-make/rustdoc-doctest-output-format/file.rs create mode 100644 tests/run-make/rustdoc-doctest-output-format/rmake.rs diff --git a/tests/run-make/rustdoc-doctest-output-format/file.rs b/tests/run-make/rustdoc-doctest-output-format/file.rs new file mode 100644 index 000000000000..51d17849fd71 --- /dev/null +++ b/tests/run-make/rustdoc-doctest-output-format/file.rs @@ -0,0 +1,3 @@ +//! ``` +//! let x = 12; +//! ``` diff --git a/tests/run-make/rustdoc-doctest-output-format/rmake.rs b/tests/run-make/rustdoc-doctest-output-format/rmake.rs new file mode 100644 index 000000000000..61b5c0c4fd11 --- /dev/null +++ b/tests/run-make/rustdoc-doctest-output-format/rmake.rs @@ -0,0 +1,83 @@ +//! Regression test to ensure that the output format is respected for doctests. +//! +//! Regression test for . + +//@ ignore-cross-compile + +use run_make_support::{rustdoc, serde_json}; + +fn run_test(edition: &str, format: Option<&str>) -> String { + let mut r = rustdoc(); + r.input("file.rs").edition(edition).arg("--test"); + if let Some(format) = format { + r.args(&[ + "--test-args", + "-Zunstable-options", + "--test-args", + "--format", + "--test-args", + format, + ]); + } + r.run().stdout_utf8() +} + +fn check_json_output(edition: &str, expected_reports: usize) { + let out = run_test(edition, Some("json")); + let mut found_report = 0; + for (line_nb, line) in out.lines().enumerate() { + match serde_json::from_str::(&line) { + Ok(value) => { + if value.get("type") == Some(&serde_json::json!("report")) { + found_report += 1; + } + } + Err(error) => panic!( + "failed for {edition} edition (json format) at line {}: non-JSON value: {error}\n\ + ====== output ======\n{out}", + line_nb + 1, + ), + } + } + if found_report != expected_reports { + panic!( + "failed for {edition} edition (json format): expected {expected_reports} doctest \ + time `report`, found {found_report}\n====== output ======\n{out}", + ); + } +} + +fn check_non_json_output(edition: &str, expected_reports: usize) { + let out = run_test(edition, None); + let mut found_report = 0; + for (line_nb, line) in out.lines().enumerate() { + if line.starts_with('{') && serde_json::from_str::(&line).is_ok() { + panic!( + "failed for {edition} edition: unexpected json at line {}: `{line}`\n\ + ====== output ======\n{out}", + line_nb + 1 + ); + } + if line.starts_with("all doctests ran in") + && line.contains("; merged doctests compilation took ") + { + found_report += 1; + } + } + if found_report != expected_reports { + panic!( + "failed for {edition} edition: expected {expected_reports} doctest time `report`, \ + found {found_report}\n====== output ======\n{out}", + ); + } +} + +fn main() { + // Only the merged doctests generate the "times report". + check_json_output("2021", 0); + check_json_output("2024", 1); + + // Only the merged doctests generate the "times report". + check_non_json_output("2021", 0); + check_non_json_output("2024", 1); +} From 95445f9b9652c24a48493bafdc5a8fce12927aec Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 5 Oct 2025 17:27:45 +0800 Subject: [PATCH 531/537] Trivial code cleanup in resolve --- compiler/rustc_resolve/src/imports.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index ce90a1bcd313..04eb312a0f8b 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -741,14 +741,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors.retain(|(_import, err)| match err.module { // Skip `use` errors for `use foo::Bar;` if `foo.rs` has unrecovered parse errors. Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false, - _ => true, - }); - errors.retain(|(_import, err)| { // If we've encountered something like `use _;`, we've already emitted an error stating // that `_` is not a valid identifier, so we ignore that resolve error. - err.segment != Some(kw::Underscore) + _ => err.segment != Some(kw::Underscore), }); - if errors.is_empty() { self.tcx.dcx().delayed_bug("expected a parse or \"`_` can't be an identifier\" error"); return; From 9ccaf080cbef74aae96760564fd23447d5aa906b Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:01:23 +0200 Subject: [PATCH 532/537] Fill out AVR target metadata This will make `-Zbuild-std` automatically build the right crates, notably not building `std` by default, which will both be useful for users and also fix the build for https://does-it-build.noratrieb.dev. --- compiler/rustc_target/src/spec/targets/avr_none.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index ad056d023267..65a171e4515a 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -5,9 +5,9 @@ pub(crate) fn target() -> Target { arch: "avr".into(), metadata: crate::spec::TargetMetadata { description: None, - tier: None, - host_tools: None, - std: None, + tier: Some(3), + host_tools: Some(false), + std: Some(false), }, data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8".into(), llvm_target: "avr-unknown-unknown".into(), From 87e8ec8114532e252fb93df5a115f7fb91c6d668 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 5 Oct 2025 14:12:49 +0200 Subject: [PATCH 533/537] power align: format test file --- tests/ui/layout/reprc-power-alignment.rs | 25 +++++++++---------- tests/ui/layout/reprc-power-alignment.stderr | 26 ++++++++++---------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/tests/ui/layout/reprc-power-alignment.rs b/tests/ui/layout/reprc-power-alignment.rs index f144094d43fb..3456c4ef8029 100644 --- a/tests/ui/layout/reprc-power-alignment.rs +++ b/tests/ui/layout/reprc-power-alignment.rs @@ -5,12 +5,12 @@ #![feature(no_core)] #![no_core] #![no_std] +#![crate_type = "lib"] extern crate minicore; use minicore::*; #[warn(uses_power_alignment)] - #[repr(C)] pub struct Floats { a: f64, @@ -96,32 +96,32 @@ pub struct FloatAgg7 { #[repr(C)] pub struct A { - d: f64, + d: f64, } #[repr(C)] pub struct B { - a: A, - f: f32, - d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + a: A, + f: f32, + d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type } #[repr(C)] pub struct C { - c: u8, - b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + c: u8, + b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type } #[repr(C)] pub struct D { - x: f64, + x: f64, } #[repr(C)] pub struct E { - x: i32, - d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + x: i32, + d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type } #[repr(C)] pub struct F { - a: u8, - b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + a: u8, + b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type } #[repr(C)] pub struct G { @@ -173,4 +173,3 @@ pub struct M { b: K, c: L, } -fn main() { } diff --git a/tests/ui/layout/reprc-power-alignment.stderr b/tests/ui/layout/reprc-power-alignment.stderr index 18664e4d655d..2f4612f3ff8f 100644 --- a/tests/ui/layout/reprc-power-alignment.stderr +++ b/tests/ui/layout/reprc-power-alignment.stderr @@ -5,7 +5,7 @@ LL | c: f64, | ^^^^^^ | note: the lint level is defined here - --> $DIR/reprc-power-alignment.rs:12:8 + --> $DIR/reprc-power-alignment.rs:13:8 | LL | #[warn(uses_power_alignment)] | ^^^^^^^^^^^^^^^^^^^^ @@ -73,28 +73,28 @@ LL | y: Floats, | ^^^^^^^^^ warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type - --> $DIR/reprc-power-alignment.rs:105:3 + --> $DIR/reprc-power-alignment.rs:105:5 | -LL | d: f64, - | ^^^^^^ +LL | d: f64, + | ^^^^^^ warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type - --> $DIR/reprc-power-alignment.rs:110:3 + --> $DIR/reprc-power-alignment.rs:110:5 | -LL | b: B, - | ^^^^ +LL | b: B, + | ^^^^ warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type - --> $DIR/reprc-power-alignment.rs:119:3 + --> $DIR/reprc-power-alignment.rs:119:5 | -LL | d: D, - | ^^^^ +LL | d: D, + | ^^^^ warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type - --> $DIR/reprc-power-alignment.rs:124:3 + --> $DIR/reprc-power-alignment.rs:124:5 | -LL | b: f64, - | ^^^^^^ +LL | b: f64, + | ^^^^^^ warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type --> $DIR/reprc-power-alignment.rs:130:5 From 5a0ea3bfba56e4d1c768e25fa30088964b38277f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 5 Oct 2025 14:18:17 +0200 Subject: [PATCH 534/537] power align: ignore repr(C) unions and enums --- .../rustc_lint/src/types/improper_ctypes.rs | 20 +++++++++---------- tests/ui/layout/reprc-power-alignment.rs | 16 +++++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 7ca57b0094ee..2c8839708669 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -220,21 +220,21 @@ fn check_struct_for_power_alignment<'tcx>( adt_def: AdtDef<'tcx>, ) { let tcx = cx.tcx; - // repr(C) structs also with packed or aligned representation - // should be ignored. - if adt_def.repr().c() - && !adt_def.repr().packed() - && adt_def.repr().align.is_none() - && tcx.sess.target.os == "aix" - && !adt_def.all_fields().next().is_none() - { + + // Only consider structs (not enums or unions) on AIX. + if tcx.sess.target.os != "aix" || !adt_def.is_struct() { + return; + } + + // The struct must be repr(C), but ignore it if it explicitly specifies its alignment with + // either `align(N)` or `packed(N)`. + if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() { let struct_variant_data = item.expect_struct().2; for field_def in struct_variant_data.fields().iter().skip(1) { // Struct fields (after the first field) are checked for the // power alignment rule, as fields after the first are likely // to be the fields that are misaligned. - let def_id = field_def.def_id; - let ty = tcx.type_of(def_id).instantiate_identity(); + let ty = tcx.type_of(field_def.def_id).instantiate_identity(); if check_arg_for_power_alignment(cx, ty) { cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment); } diff --git a/tests/ui/layout/reprc-power-alignment.rs b/tests/ui/layout/reprc-power-alignment.rs index 3456c4ef8029..ffe311a9a2a8 100644 --- a/tests/ui/layout/reprc-power-alignment.rs +++ b/tests/ui/layout/reprc-power-alignment.rs @@ -173,3 +173,19 @@ pub struct M { b: K, c: L, } + +// The lint ignores unions +#[repr(C)] +pub union Union { + a: f64, + b: u8, + c: f64, + d: f32, +} + +// The lint ignores enums +#[repr(C)] +pub enum Enum { + A { a: f64, b: u8, c: f64, d: f32 }, + B, +} From 7ed476f51fe6d3240abb4d54435dc12c9da0b91d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 5 Oct 2025 19:58:56 +0800 Subject: [PATCH 535/537] bootstrap: don't build redirect pages during dry-run/test --- src/bootstrap/src/core/build_steps/doc.rs | 4 ++++ src/bootstrap/src/core/builder/tests.rs | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 37462c63f1b0..0a0f3b95b2cf 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -274,6 +274,10 @@ impl Step for TheBook { // build the redirect pages let _guard = builder.msg(Kind::Doc, "book redirect pages", None, build_compiler, target); + if builder.config.dry_run() { + return; + } + for file in t!(fs::read_dir(redirect_path)) { let file = t!(file); let path = file.path(); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 3306435758b4..d0429387f824 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1270,12 +1270,12 @@ mod snapshot { [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) - [build] rustdoc 1 [build] rustc 1 -> std 1 [doc] book (book) [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) + [build] rustdoc 1 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] @@ -1409,12 +1409,12 @@ mod snapshot { [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) - [build] rustdoc 1 [build] rustc 1 -> std 1 [doc] book (book) [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) + [build] rustdoc 1 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] @@ -1493,8 +1493,8 @@ mod snapshot { [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) - [build] rustdoc 1 [build] rustc 1 -> std 1 + [build] rustdoc 1 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [doc] nomicon (book) @@ -1537,8 +1537,8 @@ mod snapshot { [doc] book/first-edition (book) [doc] book/second-edition (book) [doc] book/2018-edition (book) - [build] rustdoc 1 [build] rustc 1 -> std 1 + [build] rustdoc 1 [doc] rustc 1 -> standalone 2 [doc] rustc 1 -> std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,rustc-std-workspace-core,std,std_detect,sysroot,test,unwind] [build] llvm From a8b9a576745d4e6a13198952c7b4b4b8d825624d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 5 Oct 2025 20:30:24 +0800 Subject: [PATCH 536/537] bootstrap: relax `compiler-rt` root assertion Not needed during tests. --- src/bootstrap/src/core/build_steps/compile.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 96b4e15433f7..d29d1041486b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -590,7 +590,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car ), ); let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); - assert!(compiler_builtins_root.exists()); + if !builder.config.dry_run() { + // This assertion would otherwise trigger during tests if `llvm-project` is not + // checked out. + assert!(compiler_builtins_root.exists()); + } + // The path to `compiler-rt` is also used by `profiler_builtins` (above), // so if you're changing something here please also change that as appropriate. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); From 8a31837054e95417b7356848225583e33ec3c439 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sat, 4 Oct 2025 11:29:07 +0100 Subject: [PATCH 537/537] Set opt-level for installing tool only on CI ensure_version_or_cargo_install uses -Copt-level=0 for quicker installation. However, the flag affects the tool's performance. For example, typos-cli with opt-level=0 takes 15 seconds for checking ./compiler, but the tool with default opt-level only takes less than 1 sec. This commit enables the option only when the test tidy is run on CI. --- src/tools/tidy/src/lib.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 874a758bd9b3..0acbcd64f067 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -194,8 +194,8 @@ pub fn ensure_version_or_cargo_install( // use --force to ensure that if the required version is bumped, we update it. // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. // modify PATH so that cargo doesn't print a warning telling the user to modify the path. - let cargo_exit_code = Command::new(cargo) - .args(["install", "--locked", "--force", "--quiet"]) + let mut cmd = Command::new(cargo); + cmd.args(["install", "--locked", "--force", "--quiet"]) .arg("--root") .arg(&tool_root_dir) .arg("--target-dir") @@ -208,10 +208,16 @@ pub fn ensure_version_or_cargo_install( .chain(std::iter::once(tool_bin_dir.clone())), ) .expect("build dir contains invalid char"), - ) - .env("RUSTFLAGS", "-Copt-level=0") - .spawn()? - .wait()?; + ); + + // On CI, we set opt-level flag for quicker installation. + // Since lower opt-level decreases the tool's performance, + // we don't set this option on local. + if CiEnv::is_ci() { + cmd.env("RUSTFLAGS", "-Copt-level=0"); + } + + let cargo_exit_code = cmd.spawn()?.wait()?; if !cargo_exit_code.success() { return Err(io::Error::other("cargo install failed")); }

", match tooltip { Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", @@ -79,58 +81,48 @@ fn write_header( Tooltip::Edition(_) => " edition", Tooltip::None => "", } - ), - ); + )?; - if tooltip != Tooltip::None { - let tooltip = fmt::from_fn(|f| match &tooltip { - Tooltip::IgnoreAll => f.write_str("This example is not tested"), - Tooltip::IgnoreSome(platforms) => { - f.write_str("This example is not tested on ")?; - match &platforms[..] { - [] => unreachable!(), - [platform] => f.write_str(platform)?, - [first, second] => write!(f, "{first} or {second}")?, - [platforms @ .., last] => { - for platform in platforms { - write!(f, "{platform}, ")?; + if *tooltip != Tooltip::None { + let tooltip = fmt::from_fn(|f| match tooltip { + Tooltip::IgnoreAll => f.write_str("This example is not tested"), + Tooltip::IgnoreSome(platforms) => { + f.write_str("This example is not tested on ")?; + match &platforms[..] { + [] => unreachable!(), + [platform] => f.write_str(platform)?, + [first, second] => write!(f, "{first} or {second}")?, + [platforms @ .., last] => { + for platform in platforms { + write!(f, "{platform}, ")?; + } + write!(f, "or {last}")?; } - write!(f, "or {last}")?; } + Ok(()) } - Ok(()) - } - Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), - Tooltip::ShouldPanic => f.write_str("This example panics"), - Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), - Tooltip::None => unreachable!(), - }); - write_str(out, format_args!("")); - } + Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), + Tooltip::ShouldPanic => f.write_str("This example panics"), + Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), + Tooltip::None => unreachable!(), + }); - if let Some(extra) = extra_content { - out.push_str(extra); - } - if class.is_empty() { - write_str( - out, - format_args!( - "
",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    } else {
-        write_str(
-            out,
-            format_args!(
-                "
",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    }
-    write_str(out, format_args!(""));
+            write!(f, "")?;
+        }
+
+        if let Some(extra) = extra_content {
+            f.write_str(extra)?;
+        }
+
+        let classes = fmt::from_fn(|f| {
+            iter::once("rust")
+                .chain(Some(class).filter(|class| !class.is_empty()))
+                .chain(extra_classes.iter().map(String::as_str))
+                .joined(" ", f)
+        });
+
+        write!(f, "
")
+    })
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +569,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut String, playground_button: Option<&str>) {
-    write_str(out, format_args!("
{}