From e7d56c6d01a11cddc94d2f12edeb381bf4f0f579 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 14 Jan 2026 19:03:30 -0500 Subject: [PATCH 01/40] Add functions to `GrowableBitSet`. --- compiler/rustc_index/src/bit_set.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index a9bdf597e128f..2a850898b2d67 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1336,6 +1336,12 @@ impl GrowableBitSet { self.bit_set.insert(elem) } + #[inline] + pub fn insert_range(&mut self, elems: Range) { + self.ensure(elems.end.index()); + self.bit_set.insert_range(elems); + } + /// Returns `true` if the set has changed. #[inline] pub fn remove(&mut self, elem: T) -> bool { @@ -1343,6 +1349,16 @@ impl GrowableBitSet { self.bit_set.remove(elem) } + #[inline] + pub fn clear(&mut self) { + self.bit_set.clear(); + } + + #[inline] + pub fn count(&self) -> usize { + self.bit_set.count() + } + #[inline] pub fn is_empty(&self) -> bool { self.bit_set.is_empty() @@ -1354,6 +1370,14 @@ impl GrowableBitSet { self.bit_set.words.get(word_index).is_some_and(|word| (word & mask) != 0) } + #[inline] + pub fn contains_any(&self, elems: Range) -> bool { + elems.start.index() < self.bit_set.domain_size + && self + .bit_set + .contains_any(elems.start..T::new(elems.end.index().min(self.bit_set.domain_size))) + } + #[inline] pub fn iter(&self) -> BitIter<'_, T> { self.bit_set.iter() From 5fb179fd991247fe83fbbee00635112c1d829465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 9 Mar 2026 23:28:01 +0000 Subject: [PATCH 02/40] Detect more cases of method shadowing with incorrect arguments ``` error[E0061]: this method takes 0 arguments but 1 argument was supplied --> $DIR/shadowed-intrinsic-method.rs:18:7 | LL | a.borrow(()); | ^^^^^^ -- unexpected argument of type `()` | note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `A` --> $DIR/shadowed-intrinsic-method.rs:18:7 | LL | use std::borrow::Borrow; | ------------------- `std::borrow::Borrow` imported here ... LL | a.borrow(()); | ^^^^^^ refers to `std::borrow::Borrow::borrow` note: method defined here --> $SRC_DIR/core/src/borrow.rs:LL:COL help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - a.borrow(()); LL + A::borrow(&mut a, ()); | help: remove the extra argument | LL - a.borrow(()); LL + a.borrow(); | ``` --- compiler/rustc_hir_typeck/src/demand.rs | 57 +++++---- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 + tests/ui/methods/shadowed-intrinsic-method.rs | 35 ++++++ .../methods/shadowed-intrinsic-method.stderr | 111 ++++++++++++++++++ ...-lookup-returns-sig-with-fewer-args.stderr | 14 +++ 5 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 tests/ui/methods/shadowed-intrinsic-method.rs create mode 100644 tests/ui/methods/shadowed-intrinsic-method.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0d49e06240532..47bf767ec122e 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -29,7 +29,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if expr_ty == expected { return; } - self.annotate_alternative_method_deref(err, expr, error); + self.annotate_alternative_method_deref_for_unop(err, expr, error); self.explain_self_literal(err, expr, expected, expr_ty); // Use `||` to give these suggestions a precedence @@ -899,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn annotate_alternative_method_deref( + fn annotate_alternative_method_deref_for_unop( &self, err: &mut Diag<'_>, expr: &hir::Expr<'_>, @@ -919,7 +919,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; }; - let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { + self.annotate_alternative_method_deref(err, deref, Some(expected)) + } + + #[tracing::instrument(skip(self, err), level = "debug")] + pub(crate) fn annotate_alternative_method_deref( + &self, + err: &mut Diag<'_>, + expr: &hir::Expr<'_>, + expected: Option>, + ) { + let hir::ExprKind::MethodCall(path, base, args, _) = expr.kind else { return; }; let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { @@ -929,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(pick) = self.lookup_probe_for_diagnostic( path.ident, self_ty, - deref, + expr, probe::ProbeScope::TraitsInScope, None, ) else { @@ -939,10 +949,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(in_scope_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, - Some(expected), + expected, probe::IsSuggestion(true), self_ty, - deref.hir_id, + expr.hir_id, probe::ProbeScope::TraitsInScope, ) else { return; @@ -954,10 +964,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(all_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, - Some(expected), + expected, probe::IsSuggestion(true), self_ty, - deref.hir_id, + expr.hir_id, probe::ProbeScope::AllTraits, ) else { return; @@ -965,21 +975,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestions: Vec<_> = all_methods .into_iter() - .filter(|c| c.item.def_id != pick.item.def_id) - .map(|c| { + .filter_map(|c| { + if c.item.def_id == pick.item.def_id { + return None; + } let m = c.item; let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| { - self.var_for_def(deref.span, param) + self.var_for_def(expr.span, param) }); - let mutability = - match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() { - ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", - ty::Ref(_, _, _) => "&", - _ => "", - }; - vec![ + let fn_sig = self.tcx.fn_sig(m.def_id); + if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 { + return None; + } + let mutability = match fn_sig.skip_binder().input(0).skip_binder().kind() { + ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", + ty::Ref(_, _, _) => "&", + _ => "", + }; + Some(vec![ ( - deref.span.until(base.span), + expr.span.until(base.span), format!( "{}({}", with_no_trimmed_paths!( @@ -989,10 +1004,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ), match &args { - [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()), + [] => (base.span.shrink_to_hi().with_hi(expr.span.hi()), ")".to_string()), [first, ..] => (base.span.between(first.span), ", ".to_string()), }, - ] + ]) }) .collect(); if suggestions.is_empty() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9faa75e18480d..e30cbf2e418e8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2819,6 +2819,8 @@ impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> { ); return; } + + self.annotate_alternative_method_deref(err, self.call_expr, None); } /// A "softer" version of the `demand_compatible`, which checks types without persisting them, diff --git a/tests/ui/methods/shadowed-intrinsic-method.rs b/tests/ui/methods/shadowed-intrinsic-method.rs new file mode 100644 index 0000000000000..3d27c2597d98e --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method.rs @@ -0,0 +1,35 @@ +use std::borrow::Borrow; + +struct A; + +impl A { fn borrow(&mut self, _: ()) {} } + +struct B; + +fn main() { + // The fully-qualified path for items within functions is unnameable from outside that function. + impl B { fn borrow(&mut self, _: ()) {} } + + struct C; + // The fully-qualified path for items within functions is unnameable from outside that function. + impl C { fn borrow(&mut self, _: ()) {} } + + let mut a = A; + a.borrow(()); //~ ERROR E0061 + // A::borrow(&mut a, ()); + let mut b = B; + b.borrow(()); //~ ERROR E0061 + // This currently suggests `main::::borrow`, which is not correct, it should be + // B::borrow(&mut b, ()); + let mut c = C; + c.borrow(()); //~ ERROR E0061 + // This currently suggests `main::C::borrow`, which is not correct, it should be + // C::borrow(&mut c, ()); +} + +fn foo() { + let mut b = B; + b.borrow(()); //~ ERROR E0061 + // This currently suggests `main::::borrow`, which is not correct, it should be + // B::borrow(&mut b, ()); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method.stderr b/tests/ui/methods/shadowed-intrinsic-method.stderr new file mode 100644 index 0000000000000..4de38fd396a09 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method.stderr @@ -0,0 +1,111 @@ +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:18:7 + | +LL | a.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `A` + --> $DIR/shadowed-intrinsic-method.rs:18:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | a.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - a.borrow(()); +LL + A::borrow(&mut a, ()); + | +help: remove the extra argument + | +LL - a.borrow(()); +LL + a.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:21:7 + | +LL | b.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` + --> $DIR/shadowed-intrinsic-method.rs:21:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | b.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - b.borrow(()); +LL + main::::borrow(&mut b, ()); + | +help: remove the extra argument + | +LL - b.borrow(()); +LL + b.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:25:7 + | +LL | c.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::C` + --> $DIR/shadowed-intrinsic-method.rs:25:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | c.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - c.borrow(()); +LL + main::C::borrow(&mut c, ()); + | +help: remove the extra argument + | +LL - c.borrow(()); +LL + c.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:32:7 + | +LL | b.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` + --> $DIR/shadowed-intrinsic-method.rs:32:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | b.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - b.borrow(()); +LL + main::::borrow(&mut b, ()); + | +help: remove the extra argument + | +LL - b.borrow(()); +LL + b.borrow(); + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr index 0f86916fcdae4..e5d22a2251f22 100644 --- a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr +++ b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr @@ -11,6 +11,20 @@ note: method defined here | LL | pub fn get(&self, data: i32) { | ^^^ --------- +note: the `get` call is resolved to the method in `Target`, shadowing the method of the same name on trait `RandomTrait` + --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:4:12 + | +LL | target.get(10.0); // (used to crash here) + | ^^^ refers to `Target::get` + = note: additionally, there are 1 other available methods that aren't in scope +help: you might have meant to call one of the other methods; you can use the fully-qualified path to call one of them explicitly + | +LL - target.get(10.0); // (used to crash here) +LL + <_ as std::slice::SliceIndex<_>>::get(target, 10.0); // (used to crash here) + | +LL - target.get(10.0); // (used to crash here) +LL + <_ as object::read::elf::relocation::Relr>::get(&target, 10.0); // (used to crash here) + | error: aborting due to 1 previous error From 4c60edd17a6a22e9da4b5bf1de2aff63b8ef187e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Mar 2026 15:24:11 +0000 Subject: [PATCH 03/40] Account for inherent methods --- compiler/rustc_hir_typeck/src/demand.rs | 48 ++++++++++++------- .../methods/shadowed-intrinsic-method.stderr | 4 +- .../suggestions/shadowed-lplace-method.fixed | 2 +- .../suggestions/shadowed-lplace-method.stderr | 2 +- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 47bf767ec122e..2d41455b65a3c 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,5 +1,5 @@ use rustc_errors::{Applicability, Diag, MultiSpan, listify}; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, find_attr}; use rustc_infer::infer::DefineOpaqueTypes; @@ -723,8 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Path { res: hir::def::Res::Def( - hir::def::DefKind::Static { .. } - | hir::def::DefKind::Const { .. }, + DefKind::Static { .. } | DefKind::Const { .. }, def_id, ), .. @@ -987,22 +986,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 { return None; } - let mutability = match fn_sig.skip_binder().input(0).skip_binder().kind() { - ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", - ty::Ref(_, _, _) => "&", - _ => "", + let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder(); + let (mutability, ty) = match rcvr_ty.kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty), + ty::Ref(_, ty, _) => ("&", ty), + _ => ("", &rcvr_ty), + }; + let path = match self.tcx.assoc_parent(m.def_id) { + Some((_, DefKind::Impl { of_trait: true })) => with_no_trimmed_paths!( + // We have `impl Trait for T {}`, suggest `::method`. + self.tcx.def_path_str_with_args(m.def_id, generic_args) + ) + .to_string(), + Some((_, DefKind::Impl { of_trait: false })) => { + with_no_trimmed_paths!(if let ty::Adt(def, _) = ty.kind() { + // We have `impl T {}`, suggest `T::method`. + format!("{}::{}", self.tcx.def_path_str(def.did()), path.ident) + } else { + // This should be unreachable, as `impl &'a T {}` is invalid. + format!("{ty}::{}", path.ident) + }) + } + // Fallback for arbitrary self types. + _ => with_no_trimmed_paths!( + self.tcx.def_path_str_with_args(m.def_id, generic_args) + ) + .to_string(), }; Some(vec![ - ( - expr.span.until(base.span), - format!( - "{}({}", - with_no_trimmed_paths!( - self.tcx.def_path_str_with_args(m.def_id, generic_args,) - ), - mutability, - ), - ), + (expr.span.until(base.span), format!("{path}({}", mutability,)), match &args { [] => (base.span.shrink_to_hi().with_hi(expr.span.hi()), ")".to_string()), [first, ..] => (base.span.between(first.span), ", ".to_string()), @@ -1278,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::def::Res::Def(kind, def_id) = path.res else { return; }; - let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { + let callable_kind = if matches!(kind, DefKind::Ctor(_, _)) { CallableKind::Constructor } else { CallableKind::Function diff --git a/tests/ui/methods/shadowed-intrinsic-method.stderr b/tests/ui/methods/shadowed-intrinsic-method.stderr index 4de38fd396a09..a7fda06bee331 100644 --- a/tests/ui/methods/shadowed-intrinsic-method.stderr +++ b/tests/ui/methods/shadowed-intrinsic-method.stderr @@ -44,7 +44,7 @@ note: method defined here help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - b.borrow(()); -LL + main::::borrow(&mut b, ()); +LL + B::borrow(&mut b, ()); | help: remove the extra argument | @@ -98,7 +98,7 @@ note: method defined here help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - b.borrow(()); -LL + main::::borrow(&mut b, ()); +LL + B::borrow(&mut b, ()); | help: remove the extra argument | diff --git a/tests/ui/suggestions/shadowed-lplace-method.fixed b/tests/ui/suggestions/shadowed-lplace-method.fixed index 87db01a3b230b..fc94782f516a4 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.fixed +++ b/tests/ui/suggestions/shadowed-lplace-method.fixed @@ -6,5 +6,5 @@ use std::rc::Rc; fn main() { let rc = Rc::new(RefCell::new(true)); - *std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308 + *std::cell::RefCell::borrow_mut(&rc) = false; //~ ERROR E0308 } diff --git a/tests/ui/suggestions/shadowed-lplace-method.stderr b/tests/ui/suggestions/shadowed-lplace-method.stderr index aab9e442007ff..3469da21b1f04 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.stderr +++ b/tests/ui/suggestions/shadowed-lplace-method.stderr @@ -19,7 +19,7 @@ LL | *rc.borrow_mut() = false; help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - *rc.borrow_mut() = false; -LL + *std::cell::RefCell::<_>::borrow_mut(&rc) = false; +LL + *std::cell::RefCell::borrow_mut(&rc) = false; | error: aborting due to 1 previous error From 67036af05db01cd057df04636fe1388c0d459375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 10 Mar 2026 15:45:24 +0000 Subject: [PATCH 04/40] Tweak output --- compiler/rustc_hir_typeck/src/demand.rs | 13 ++++++------- tests/ui/methods/shadowed-intrinsic-method.rs | 2 ++ .../methods/shadowed-intrinsic-method.stderr | 18 +++++++++--------- .../suggestions/shadowed-lplace-method.fixed | 2 +- .../suggestions/shadowed-lplace-method.stderr | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 2d41455b65a3c..01365a8c559c3 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -993,19 +993,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => ("", &rcvr_ty), }; let path = match self.tcx.assoc_parent(m.def_id) { - Some((_, DefKind::Impl { of_trait: true })) => with_no_trimmed_paths!( + Some((_, DefKind::Impl { of_trait: true })) => { // We have `impl Trait for T {}`, suggest `::method`. - self.tcx.def_path_str_with_args(m.def_id, generic_args) - ) - .to_string(), + self.tcx.def_path_str_with_args(m.def_id, generic_args).to_string() + } Some((_, DefKind::Impl { of_trait: false })) => { - with_no_trimmed_paths!(if let ty::Adt(def, _) = ty.kind() { + if let ty::Adt(def, _) = ty.kind() { // We have `impl T {}`, suggest `T::method`. format!("{}::{}", self.tcx.def_path_str(def.did()), path.ident) } else { // This should be unreachable, as `impl &'a T {}` is invalid. format!("{ty}::{}", path.ident) - }) + } } // Fallback for arbitrary self types. _ => with_no_trimmed_paths!( @@ -1014,7 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .to_string(), }; Some(vec![ - (expr.span.until(base.span), format!("{path}({}", mutability,)), + (expr.span.until(base.span), format!("{path}({}", mutability)), match &args { [] => (base.span.shrink_to_hi().with_hi(expr.span.hi()), ")".to_string()), [first, ..] => (base.span.between(first.span), ", ".to_string()), diff --git a/tests/ui/methods/shadowed-intrinsic-method.rs b/tests/ui/methods/shadowed-intrinsic-method.rs index 3d27c2597d98e..8350d6a7ba5f0 100644 --- a/tests/ui/methods/shadowed-intrinsic-method.rs +++ b/tests/ui/methods/shadowed-intrinsic-method.rs @@ -1,3 +1,5 @@ +// Can't use rustfix because we provide two suggestions: +// to remove the arg for `Borrow::borrow` or to call `Type::borrow`. use std::borrow::Borrow; struct A; diff --git a/tests/ui/methods/shadowed-intrinsic-method.stderr b/tests/ui/methods/shadowed-intrinsic-method.stderr index a7fda06bee331..a832714cd1f97 100644 --- a/tests/ui/methods/shadowed-intrinsic-method.stderr +++ b/tests/ui/methods/shadowed-intrinsic-method.stderr @@ -1,11 +1,11 @@ error[E0061]: this method takes 0 arguments but 1 argument was supplied - --> $DIR/shadowed-intrinsic-method.rs:18:7 + --> $DIR/shadowed-intrinsic-method.rs:20:7 | LL | a.borrow(()); | ^^^^^^ -- unexpected argument of type `()` | note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `A` - --> $DIR/shadowed-intrinsic-method.rs:18:7 + --> $DIR/shadowed-intrinsic-method.rs:20:7 | LL | use std::borrow::Borrow; | ------------------- `std::borrow::Borrow` imported here @@ -26,13 +26,13 @@ LL + a.borrow(); | error[E0061]: this method takes 0 arguments but 1 argument was supplied - --> $DIR/shadowed-intrinsic-method.rs:21:7 + --> $DIR/shadowed-intrinsic-method.rs:23:7 | LL | b.borrow(()); | ^^^^^^ -- unexpected argument of type `()` | note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` - --> $DIR/shadowed-intrinsic-method.rs:21:7 + --> $DIR/shadowed-intrinsic-method.rs:23:7 | LL | use std::borrow::Borrow; | ------------------- `std::borrow::Borrow` imported here @@ -53,13 +53,13 @@ LL + b.borrow(); | error[E0061]: this method takes 0 arguments but 1 argument was supplied - --> $DIR/shadowed-intrinsic-method.rs:25:7 + --> $DIR/shadowed-intrinsic-method.rs:27:7 | LL | c.borrow(()); | ^^^^^^ -- unexpected argument of type `()` | note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::C` - --> $DIR/shadowed-intrinsic-method.rs:25:7 + --> $DIR/shadowed-intrinsic-method.rs:27:7 | LL | use std::borrow::Borrow; | ------------------- `std::borrow::Borrow` imported here @@ -71,7 +71,7 @@ note: method defined here help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - c.borrow(()); -LL + main::C::borrow(&mut c, ()); +LL + C::borrow(&mut c, ()); | help: remove the extra argument | @@ -80,13 +80,13 @@ LL + c.borrow(); | error[E0061]: this method takes 0 arguments but 1 argument was supplied - --> $DIR/shadowed-intrinsic-method.rs:32:7 + --> $DIR/shadowed-intrinsic-method.rs:34:7 | LL | b.borrow(()); | ^^^^^^ -- unexpected argument of type `()` | note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` - --> $DIR/shadowed-intrinsic-method.rs:32:7 + --> $DIR/shadowed-intrinsic-method.rs:34:7 | LL | use std::borrow::Borrow; | ------------------- `std::borrow::Borrow` imported here diff --git a/tests/ui/suggestions/shadowed-lplace-method.fixed b/tests/ui/suggestions/shadowed-lplace-method.fixed index fc94782f516a4..e7f6df9fff8fb 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.fixed +++ b/tests/ui/suggestions/shadowed-lplace-method.fixed @@ -6,5 +6,5 @@ use std::rc::Rc; fn main() { let rc = Rc::new(RefCell::new(true)); - *std::cell::RefCell::borrow_mut(&rc) = false; //~ ERROR E0308 + *RefCell::borrow_mut(&rc) = false; //~ ERROR E0308 } diff --git a/tests/ui/suggestions/shadowed-lplace-method.stderr b/tests/ui/suggestions/shadowed-lplace-method.stderr index 3469da21b1f04..dfd52b9b5587b 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.stderr +++ b/tests/ui/suggestions/shadowed-lplace-method.stderr @@ -19,7 +19,7 @@ LL | *rc.borrow_mut() = false; help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - *rc.borrow_mut() = false; -LL + *std::cell::RefCell::borrow_mut(&rc) = false; +LL + *RefCell::borrow_mut(&rc) = false; | error: aborting due to 1 previous error From 9729bb2558d6e3a3e430304b18d7f5211ffc2427 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 11 Mar 2026 09:37:35 +0000 Subject: [PATCH 05/40] Add macro matcher for `guard` fragment specifier --- compiler/rustc_ast/src/ast.rs | 16 +- compiler/rustc_ast/src/token.rs | 5 + compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/expr.rs | 4 +- compiler/rustc_ast_lowering/src/pat.rs | 7 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 4 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 58 ++++- compiler/rustc_expand/src/mbe/transcribe.rs | 16 +- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_parse/src/parser/expr.rs | 128 ++++++---- compiler/rustc_parse/src/parser/mod.rs | 1 + .../rustc_parse/src/parser/nonterminal.rs | 10 +- compiler/rustc_parse/src/parser/pat.rs | 28 ++- compiler/rustc_resolve/src/late.rs | 4 +- compiler/rustc_span/src/symbol.rs | 2 + .../clippy/clippy_utils/src/ast_utils/mod.rs | 2 +- src/tools/rustfmt/src/matches.rs | 10 +- .../feature-gate-macro-guard-matcher.rs | 5 + .../feature-gate-macro-guard-matcher.stderr | 13 + tests/ui/macros/macro-follow-rpass.rs | 3 +- tests/ui/macros/macro-follow.rs | 7 +- tests/ui/macros/macro-follow.stderr | 238 ++++++++++-------- tests/ui/macros/macro-guard-matcher.rs | 17 ++ tests/ui/macros/macro-guard-matcher.stderr | 17 ++ .../macros/macro-input-future-proofing.stderr | 6 +- ...-pat-pattern-followed-by-or-in-2021.stderr | 6 +- ...acro-pat2021-pattern-followed-by-or.stderr | 6 +- tests/ui/macros/stringify.rs | 17 ++ 29 files changed, 441 insertions(+), 196 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs create mode 100644 tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr create mode 100644 tests/ui/macros/macro-guard-matcher.rs create mode 100644 tests/ui/macros/macro-guard-matcher.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 74cc1ec17e6f0..024624cd3bb87 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -938,7 +938,7 @@ pub enum PatKind { Never, /// A guard pattern (e.g., `x if guard(x)`). - Guard(Box, Box), + Guard(Box, Box), /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(Box), @@ -1346,7 +1346,7 @@ pub struct Arm { /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`. pub pat: Box, /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`. - pub guard: Option>, + pub guard: Option>, /// Match arm body. Omitted if the pattern is a never pattern. pub body: Option>, pub span: Span, @@ -3954,6 +3954,18 @@ impl ConstBlockItem { pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP }; } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct Guard { + pub cond: Expr, + pub span_with_leading_if: Span, +} + +impl Guard { + pub fn span(&self) -> Span { + self.cond.span + } +} + // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f82513094aa1f..62ec063585171 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -94,6 +94,7 @@ pub enum MetaVarKind { }, Path, Vis, + Guard, TT, } @@ -114,6 +115,7 @@ impl fmt::Display for MetaVarKind { MetaVarKind::Meta { .. } => sym::meta, MetaVarKind::Path => sym::path, MetaVarKind::Vis => sym::vis, + MetaVarKind::Guard => sym::guard, MetaVarKind::TT => sym::tt, }; write!(f, "{sym}") @@ -1124,6 +1126,7 @@ pub enum NonterminalKind { Meta, Path, Vis, + Guard, TT, } @@ -1161,6 +1164,7 @@ impl NonterminalKind { sym::meta => NonterminalKind::Meta, sym::path => NonterminalKind::Path, sym::vis => NonterminalKind::Vis, + sym::guard => NonterminalKind::Guard, sym::tt => NonterminalKind::TT, _ => return None, }) @@ -1182,6 +1186,7 @@ impl NonterminalKind { NonterminalKind::Meta => sym::meta, NonterminalKind::Path => sym::path, NonterminalKind::Vis => sym::vis, + NonterminalKind::Guard => sym::guard, NonterminalKind::TT => sym::tt, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bdf290f9a9e63..6aa8d5f38ad24 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -442,6 +442,7 @@ macro_rules! common_visitor_and_walkers { FormatArguments, FormatPlaceholder, GenericParamKind, + Guard, Impl, ImplPolarity, Inline, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 305df40651969..35a74a63b8e4c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -639,7 +639,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); - let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); + let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm); @@ -662,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else if let Some(body) = &arm.body { self.dcx().emit_err(NeverPatternWithBody { span: body.span }); } else if let Some(g) = &arm.guard { - self.dcx().emit_err(NeverPatternWithGuard { span: g.span }); + self.dcx().emit_err(NeverPatternWithGuard { span: g.span() }); } // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index c1c13977e1037..3aadf09597ee2 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -133,8 +133,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_range_end(end, e2.is_some()), ); } - PatKind::Guard(inner, cond) => { - break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond)); + PatKind::Guard(inner, guard) => { + break hir::PatKind::Guard( + self.lower_pat(inner), + self.lower_expr(&guard.cond), + ); } PatKind::Slice(pats) => break self.lower_pat_slice(pats), PatKind::Rest => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4ba5dc541342a..1f07ee71c420a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1889,12 +1889,12 @@ impl<'a> State<'a> { self.print_expr(e, FixupContext::default()); } } - PatKind::Guard(subpat, condition) => { + PatKind::Guard(subpat, guard) => { self.popen(); self.print_pat(subpat); self.space(); self.word_space("if"); - self.print_expr(condition, FixupContext::default()); + self.print_expr(&guard.cond, FixupContext::default()); self.pclose(); } PatKind::Slice(elts) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9b4ff2b63bd45..f6db4cdef7224 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -880,9 +880,9 @@ impl<'a> State<'a> { self.print_outer_attributes(&arm.attrs); self.print_pat(&arm.pat); self.space(); - if let Some(e) = &arm.guard { + if let Some(guard) = &arm.guard { self.word_space("if"); - self.print_expr(e, FixupContext::default()); + self.print_expr(&guard.cond, FixupContext::default()); self.space(); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 7ff49e040f6f3..82d941a289e07 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -724,7 +724,7 @@ pub fn compile_declarative_macro( let args = p.parse_token_tree(); check_args_parens(sess, sym::attr, &args); let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition); - check_emission(check_lhs(sess, node_id, &args)); + check_emission(check_lhs(sess, features, node_id, &args)); if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") { return dummy_syn_ext(guar); } @@ -773,7 +773,7 @@ pub fn compile_declarative_macro( }; let lhs_tt = p.parse_token_tree(); let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition); - check_emission(check_lhs(sess, node_id, &lhs_tt)); + check_emission(check_lhs(sess, features, node_id, &lhs_tt)); if let Err(e) = p.expect(exp!(FatArrow)) { return dummy_syn_ext(e.emit()); } @@ -870,21 +870,27 @@ fn check_args_empty(sess: &Session, args: &tokenstream::TokenTree) -> Result<(), } } -fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> { - let e1 = check_lhs_nt_follows(sess, node_id, lhs); +fn check_lhs( + sess: &Session, + features: &Features, + node_id: NodeId, + lhs: &mbe::TokenTree, +) -> Result<(), ErrorGuaranteed> { + let e1 = check_lhs_nt_follows(sess, features, node_id, lhs); let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); e1.and(e2) } fn check_lhs_nt_follows( sess: &Session, + features: &Features, node_id: NodeId, lhs: &mbe::TokenTree, ) -> Result<(), ErrorGuaranteed> { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let mbe::TokenTree::Delimited(.., delimited) = lhs { - check_matcher(sess, node_id, &delimited.tts) + check_matcher(sess, features, node_id, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; Err(sess.dcx().span_err(lhs.span(), msg)) @@ -989,12 +995,13 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed fn check_matcher( sess: &Session, + features: &Features, node_id: NodeId, matcher: &[mbe::TokenTree], ) -> Result<(), ErrorGuaranteed> { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?; + check_matcher_core(sess, features, node_id, &first_sets, matcher, &empty_suffix)?; Ok(()) } @@ -1331,6 +1338,7 @@ impl<'tt> TokenSet<'tt> { // see `FirstSets::new`. fn check_matcher_core<'tt>( sess: &Session, + features: &Features, node_id: NodeId, first_sets: &FirstSets<'tt>, matcher: &'tt [mbe::TokenTree], @@ -1369,6 +1377,17 @@ fn check_matcher_core<'tt>( | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl { .. } | TokenTree::MetaVarExpr(..) => { + if let TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } = token + && !features.macro_guard_matcher() + { + feature_err( + sess, + sym::macro_guard_matcher, + token.span(), + "`guard` fragments in macro are unstable", + ) + .emit(); + } if token_can_be_followed_by_any(token) { // don't need to track tokens that work with any, last.replace_with_irrelevant(); @@ -1385,7 +1404,7 @@ fn check_matcher_core<'tt>( d.delim.as_close_token_kind(), span.close, )); - check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?; + check_matcher_core(sess, features, node_id, first_sets, &d.tts, &my_suffix)?; // don't track non NT tokens last.replace_with_irrelevant(); @@ -1417,7 +1436,14 @@ fn check_matcher_core<'tt>( // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?; + let next = check_matcher_core( + sess, + features, + node_id, + first_sets, + &seq_rep.tts, + my_suffix, + )?; if next.maybe_empty { last.add_all(&next); } else { @@ -1609,7 +1635,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } } NonterminalKind::Pat(PatParam { .. }) => { - const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; + const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`if let`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq | Or => IsInFollow::Yes, @@ -1618,11 +1644,12 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, + TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes, _ => IsInFollow::No(TOKENS), } } NonterminalKind::Pat(PatWithOr) => { - const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; + const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`if let`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { FatArrow | Comma | Eq => IsInFollow::Yes, @@ -1631,6 +1658,17 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { } _ => IsInFollow::No(TOKENS), }, + TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes, + _ => IsInFollow::No(TOKENS), + } + } + NonterminalKind::Guard => { + const TOKENS: &[&str] = &["`=>`", "`,`", "`{`"]; + match tok { + TokenTree::Token(token) => match token.kind { + FatArrow | Comma | OpenBrace => IsInFollow::Yes, + _ => IsInFollow::No(TOKENS), + }, _ => IsInFollow::No(TOKENS), } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 09f006c3de578..dcf2cd1fa36af 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -12,7 +12,8 @@ use rustc_parse::parser::ParseNtResult; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::{ - Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, sym, with_metavar_spans, + BytePos, Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, + with_metavar_spans, }; use smallvec::{SmallVec, smallvec}; @@ -556,6 +557,19 @@ fn transcribe_pnr<'tx>( ParseNtResult::Vis(vis) => { mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } + ParseNtResult::Guard(guard) => { + // FIXME(macro_guard_matcher): + // Perhaps it would be better to treat the leading `if` as part of `ast::Guard` during parsing? + // Currently they are separate, but in macros we match and emit the leading `if` for `:guard` matchers, which creates some inconsistency. + + let leading_if_span = + guard.span_with_leading_if.with_hi(guard.span_with_leading_if.lo() + BytePos(2)); + let mut ts = + TokenStream::token_alone(token::Ident(kw::If, IdentIsRaw::No), leading_if_span); + ts.push_stream(TokenStream::from_ast(&guard.cond)); + + mk_delimited(guard.span_with_leading_if, MetaVarKind::Guard, ts) + } }; tscx.result.push(tt); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 39e886227d946..b5db4e20d0d37 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -565,6 +565,8 @@ declare_features! ( (unstable, macro_attr, "1.91.0", Some(143547)), /// Allow `macro_rules!` derive rules (unstable, macro_derive, "1.91.0", Some(143549)), + /// Allow `$x:guard` matcher in macros + (unstable, macro_guard_matcher, "CURRENT_RUSTC_VERSION", Some(153104)), /// 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. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index adfc68f4bb22a..79f370bb828c3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, - StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, + RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; @@ -2762,7 +2762,7 @@ impl<'a> Parser<'a> { /// Parses a `let $pat = $expr` pseudo-expression. fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box> { - let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { + let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: errors::ForbiddenLetReason::OtherForbidden, @@ -3458,20 +3458,54 @@ impl<'a> Parser<'a> { }) } - fn parse_match_arm_guard(&mut self) -> PResult<'a, Option>> { + pub(crate) fn eat_metavar_guard(&mut self) -> Option> { + self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Guard), + |this| this.parse_match_arm_guard(), + ) + .flatten() + } + + fn parse_match_arm_guard(&mut self) -> PResult<'a, Option>> { + if let Some(guard) = self.eat_metavar_guard() { + return Ok(Some(guard)); + } + if !self.eat_keyword(exp!(If)) { // No match arm guard present. return Ok(None); } + self.expect_match_arm_guard_cond(ForceCollect::No).map(Some) + } - let mut cond = self.parse_match_guard_condition()?; + pub(crate) fn expect_match_arm_guard( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { + if let Some(guard) = self.eat_metavar_guard() { + return Ok(guard); + } + + self.expect_keyword(exp!(If))?; + self.expect_match_arm_guard_cond(force_collect) + } + + fn expect_match_arm_guard_cond( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { + let leading_if_span = self.prev_token.span; + + let mut cond = self.parse_match_guard_condition(force_collect)?; + let cond_span = cond.span; CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond); - Ok(Some(cond)) + let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }; + Ok(Box::new(guard)) } - fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option>)> { + fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option>)> { if self.token == token::OpenParen { let left = self.token.span; let pat = self.parse_pat_no_top_guard( @@ -3487,10 +3521,10 @@ impl<'a> Parser<'a> { // FIXME(guard_patterns): convert this to a normal guard instead let span = pat.span; let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() }; - let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() }; - self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span); + let ast::PatKind::Guard(_, mut guard) = subpat.kind else { unreachable!() }; + self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span()); let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed); - checker.visit_expr(&mut cond); + checker.visit_expr(&mut guard.cond); let right = self.prev_token.span; self.dcx().emit_err(errors::ParenthesesInMatchPat { @@ -3498,14 +3532,10 @@ impl<'a> Parser<'a> { sugg: errors::ParenthesesInMatchPatSugg { left, right }, }); - Ok(( - self.mk_pat(span, ast::PatKind::Wild), - (if let Some(guar) = checker.found_incorrect_let_chain { - Some(self.mk_expr_err(cond.span, guar)) - } else { - Some(cond) - }), - )) + if let Some(guar) = checker.found_incorrect_let_chain { + guard.cond = *self.mk_expr_err(guard.span(), guar); + } + Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard))) } else { Ok((pat, self.parse_match_arm_guard()?)) } @@ -3521,33 +3551,47 @@ impl<'a> Parser<'a> { } } - fn parse_match_guard_condition(&mut self) -> PResult<'a, Box> { + fn parse_match_guard_condition( + &mut self, + force_collect: ForceCollect, + ) -> PResult<'a, Box> { let attrs = self.parse_outer_attributes()?; - match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) { - Ok((expr, _)) => Ok(expr), - Err(mut err) => { - if self.prev_token == token::OpenBrace { - let sugg_sp = self.prev_token.span.shrink_to_lo(); - // Consume everything within the braces, let's avoid further parse - // errors. - self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); - let msg = "you might have meant to start a match arm after the match guard"; - if self.eat(exp!(CloseBrace)) { - let applicability = if self.token != token::FatArrow { - // We have high confidence that we indeed didn't have a struct - // literal in the match guard, but rather we had some operation - // that ended in a path, immediately followed by a block that was - // meant to be the match arm. - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); + let expr = self.collect_tokens( + None, + AttrWrapper::empty(), + force_collect, + |this, _empty_attrs| { + match this + .parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) + { + Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)), + Err(mut err) => { + if this.prev_token == token::OpenBrace { + let sugg_sp = this.prev_token.span.shrink_to_lo(); + // Consume everything within the braces, let's avoid further parse + // errors. + this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); + let msg = + "you might have meant to start a match arm after the match guard"; + if this.eat(exp!(CloseBrace)) { + let applicability = if this.token != token::FatArrow { + // We have high confidence that we indeed didn't have a struct + // literal in the match guard, but rather we had some operation + // that ended in a path, immediately followed by a block that was + // meant to be the match arm. + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); + } + } + Err(err) } } - Err(err) - } - } + }, + )?; + Ok(expr) } pub(crate) fn is_builtin(&self) -> bool { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 36ca8a7d61339..8c1c3c7025f5e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1788,4 +1788,5 @@ pub enum ParseNtResult { Meta(Box), Path(Box), Vis(Box), + Guard(Box), } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 706b454835fab..ddf1b10e5235d 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -31,7 +31,8 @@ impl<'a> Parser<'a> { MetaVarKind::Item | MetaVarKind::Block - | MetaVarKind::Vis => false, + | MetaVarKind::Vis + | MetaVarKind::Guard => false, MetaVarKind::Ident | MetaVarKind::Lifetime @@ -86,7 +87,8 @@ impl<'a> Parser<'a> { | MetaVarKind::Ty { .. } | MetaVarKind::Meta { .. } | MetaVarKind::Path - | MetaVarKind::Vis => false, + | MetaVarKind::Vis + | MetaVarKind::Guard => false, MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { unreachable!() } @@ -103,6 +105,7 @@ impl<'a> Parser<'a> { token::Lifetime(..) | token::NtLifetime(..) => true, _ => false, }, + NonterminalKind::Guard => token.is_keyword(kw::If), NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { token.kind.close_delim().is_none() } @@ -196,6 +199,9 @@ impl<'a> Parser<'a> { })) } } + NonterminalKind::Guard => { + Ok(ParseNtResult::Guard(self.expect_match_arm_guard(ForceCollect::Yes)?)) + } } } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7ee7781f6be0a..a21d19b6d3a20 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -6,8 +6,9 @@ use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token}; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability, - Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind, + self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, Guard, LocalKind, MacCall, + Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, + StmtKind, }; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey}; @@ -110,11 +111,19 @@ impl<'a> Parser<'a> { let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?; if self.eat_keyword(exp!(If)) { - let cond = self.parse_expr()?; + let guard = if let Some(guard) = self.eat_metavar_guard() { + guard + } else { + let leading_if_span = self.prev_token.span; + let cond = self.parse_expr()?; + let cond_span = cond.span; + Box::new(Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) }) + }; + // Feature-gate guard patterns - self.psess.gated_spans.gate(sym::guard_patterns, cond.span); - let span = pat.span.to(cond.span); - Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), cond))) + self.psess.gated_spans.gate(sym::guard_patterns, guard.span()); + let span = pat.span.to(guard.span()); + Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), guard))) } else { Ok(pat) } @@ -601,17 +610,18 @@ impl<'a> Parser<'a> { } Some(guard) => { // Are parentheses required around the old guard? - let wrap_guard = guard.precedence() <= ExprPrecedence::LAnd; + let wrap_guard = + guard.cond.precedence() <= ExprPrecedence::LAnd; err.subdiagnostic( UnexpectedExpressionInPatternSugg::UpdateGuard { ident_span, guard_lo: if wrap_guard { - Some(guard.span.shrink_to_lo()) + Some(guard.span().shrink_to_lo()) } else { None }, - guard_hi: guard.span.shrink_to_hi(), + guard_hi: guard.span().shrink_to_hi(), guard_hi_paren: if wrap_guard { ")" } else { "" }, ident, expr, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 453fe9d7a8e0e..d5cb3aefec0f9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4054,7 +4054,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_arm(&mut self, arm: &'ast Arm) { self.with_rib(ValueNS, RibKind::Normal, |this| { this.resolve_pattern_top(&arm.pat, PatternSource::Match); - visit_opt!(this, visit_expr, &arm.guard); + visit_opt!(this, visit_expr, arm.guard.as_ref().map(|g| &g.cond)); visit_opt!(this, visit_expr, &arm.body); }); } @@ -4196,7 +4196,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let subpat_bindings = bindings.pop().unwrap().1; self.with_rib(ValueNS, RibKind::Normal, |this| { *this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone(); - this.resolve_expr(guard, None); + this.resolve_expr(&guard.cond, None); }); // Propagate the subpattern's bindings upwards. // FIXME(guard_patterns): For `if let` guards, we'll also need to get the diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 257ac3f51c2c1..96bda60c363ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1027,6 +1027,7 @@ symbols! { global_registration, globs, gt, + guard, guard_patterns, half_open_range_patterns, half_open_range_patterns_in_slices, @@ -1190,6 +1191,7 @@ symbols! { macro_derive, macro_escape, macro_export, + macro_guard_matcher, macro_lifetime_matcher, macro_literal_matcher, macro_metavar_expr, diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 50cfb0ed89dec..9a463d1a9d71e 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -280,7 +280,7 @@ pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) && eq_expr_opt(l.body.as_deref(), r.body.as_deref()) - && eq_expr_opt(l.guard.as_deref(), r.guard.as_deref()) + && eq_expr_opt(l.guard.as_deref().map(|g| &g.cond), r.guard.as_deref().map(|g| &g.cond)) && over(&l.attrs, &r.attrs, eq_attr) } diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index 4741abbe46583..50c0db8ac06e5 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -571,7 +571,7 @@ fn rewrite_match_body( // The `if ...` guard on a match arm. fn rewrite_guard( context: &RewriteContext<'_>, - guard: &Option>, + guard: &Option>, shape: Shape, // The amount of space used up on this line for the pattern in // the arm (excludes offset). @@ -586,7 +586,7 @@ fn rewrite_guard( .and_then(|s| s.sub_width_opt(5)); if !multiline_pattern { if let Some(cond_shape) = cond_shape { - if let Ok(cond_str) = guard.rewrite_result(context, cond_shape) { + if let Ok(cond_str) = guard.cond.rewrite_result(context, cond_shape) { if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() { return Ok(format!(" if {cond_str}")); } @@ -597,9 +597,9 @@ fn rewrite_guard( // Not enough space to put the guard after the pattern, try a newline. // 3 = `if `, 5 = ` => {` let cond_shape = Shape::indented(shape.indent.block_indent(context.config), context.config) - .offset_left(3, guard.span)? - .sub_width(5, guard.span)?; - let cond_str = guard.rewrite_result(context, cond_shape)?; + .offset_left(3, guard.span())? + .sub_width(5, guard.span())?; + let cond_str = guard.cond.rewrite_result(context, cond_shape)?; Ok(format!( "{}if {}", cond_shape.indent.to_string_with_newline(context.config), diff --git a/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs new file mode 100644 index 0000000000000..662161f19fac7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.rs @@ -0,0 +1,5 @@ +fn main() { + macro_rules! m { + ($x:guard) => {}; //~ ERROR `guard` fragments in macro are unstable + } +} diff --git a/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr new file mode 100644 index 0000000000000..0977f944f74fd --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-guard-matcher.stderr @@ -0,0 +1,13 @@ +error[E0658]: `guard` fragments in macro are unstable + --> $DIR/feature-gate-macro-guard-matcher.rs:3:10 + | +LL | ($x:guard) => {}; + | ^^^^^^^^ + | + = note: see issue #153104 for more information + = help: add `#![feature(macro_guard_matcher)]` 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/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs index 8551b1887708e..d941423656287 100644 --- a/tests/ui/macros/macro-follow-rpass.rs +++ b/tests/ui/macros/macro-follow-rpass.rs @@ -3,13 +3,14 @@ #![allow(unused_macros)] // Check the macro follow sets (see corresponding cfail test). -// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)} macro_rules! follow_pat { ($p:pat =>) => {}; ($p:pat ,) => {}; ($p:pat =) => {}; ($p:pat |) => {}; ($p:pat if) => {}; + ($p:pat if let) => {}; ($p:pat in) => {}; } // FOLLOW(expr) = {FatArrow, Comma, Semicolon} diff --git a/tests/ui/macros/macro-follow.rs b/tests/ui/macros/macro-follow.rs index 923c9bd6cedc9..874bad6a74316 100644 --- a/tests/ui/macros/macro-follow.rs +++ b/tests/ui/macros/macro-follow.rs @@ -2,9 +2,10 @@ // // Check the macro follow sets (see corresponding rpass test). +#![feature(macro_guard_matcher)] #![allow(unused_macros)] -// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)} macro_rules! follow_pat { ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[` @@ -47,6 +48,7 @@ macro_rules! follow_expr { ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` + ($e:expr $g:guard) => {}; //~ERROR `$e:expr` is followed by `$g:guard` } // FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, // Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)} @@ -66,6 +68,7 @@ macro_rules! follow_ty { ($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt` ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` + ($t:ty $g:guard) => {}; //~ERROR `$t:ty` is followed by `$g:guard` } // FOLLOW(stmt) = FOLLOW(expr) macro_rules! follow_stmt { @@ -90,6 +93,7 @@ macro_rules! follow_stmt { ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` + ($s:stmt $g:guard) => {}; //~ERROR `$s:stmt` is followed by `$g:guard` } // FOLLOW(path) = FOLLOW(ty) macro_rules! follow_path { @@ -108,6 +112,7 @@ macro_rules! follow_path { ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta` + ($p:path $g:guard) => {}; //~ERROR `$p:path` is followed by `$g:guard` } // FOLLOW(block) = any token // FOLLOW(ident) = any token diff --git a/tests/ui/macros/macro-follow.stderr b/tests/ui/macros/macro-follow.stderr index 92491dc26d12b..78d167added73 100644 --- a/tests/ui/macros/macro-follow.stderr +++ b/tests/ui/macros/macro-follow.stderr @@ -1,141 +1,141 @@ error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:9:13 + --> $DIR/macro-follow.rs:10:13 | LL | ($p:pat ()) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:10:13 + --> $DIR/macro-follow.rs:11:13 | LL | ($p:pat []) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:11:13 + --> $DIR/macro-follow.rs:12:13 | LL | ($p:pat {}) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:12:13 + --> $DIR/macro-follow.rs:13:13 | LL | ($p:pat :) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:13:13 + --> $DIR/macro-follow.rs:14:13 | LL | ($p:pat >) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:14:13 + --> $DIR/macro-follow.rs:15:13 | LL | ($p:pat +) => {}; | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:15:13 + --> $DIR/macro-follow.rs:16:13 | LL | ($p:pat ident) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:16:13 + --> $DIR/macro-follow.rs:17:13 | LL | ($p:pat $q:pat) => {}; | ^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:17:13 + --> $DIR/macro-follow.rs:18:13 | LL | ($p:pat $e:expr) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:18:13 + --> $DIR/macro-follow.rs:19:13 | LL | ($p:pat $t:ty) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:19:13 + --> $DIR/macro-follow.rs:20:13 | LL | ($p:pat $s:stmt) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:20:13 + --> $DIR/macro-follow.rs:21:13 | LL | ($p:pat $q:path) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:21:13 + --> $DIR/macro-follow.rs:22:13 | LL | ($p:pat $b:block) => {}; | ^^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:22:13 + --> $DIR/macro-follow.rs:23:13 | LL | ($p:pat $i:ident) => {}; | ^^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:23:13 + --> $DIR/macro-follow.rs:24:13 | LL | ($p:pat $t:tt) => {}; | ^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:24:13 + --> $DIR/macro-follow.rs:25:13 | LL | ($p:pat $i:item) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:25:13 + --> $DIR/macro-follow.rs:26:13 | LL | ($p:pat $m:meta) => {}; | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:29:14 + --> $DIR/macro-follow.rs:30:14 | LL | ($e:expr ()) => {}; | ^ not allowed after `expr` fragments @@ -143,7 +143,7 @@ LL | ($e:expr ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:30:14 + --> $DIR/macro-follow.rs:31:14 | LL | ($e:expr []) => {}; | ^ not allowed after `expr` fragments @@ -151,7 +151,7 @@ LL | ($e:expr []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:31:14 + --> $DIR/macro-follow.rs:32:14 | LL | ($e:expr {}) => {}; | ^ not allowed after `expr` fragments @@ -159,7 +159,7 @@ LL | ($e:expr {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:32:14 + --> $DIR/macro-follow.rs:33:14 | LL | ($e:expr =) => {}; | ^ not allowed after `expr` fragments @@ -167,7 +167,7 @@ LL | ($e:expr =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:33:14 + --> $DIR/macro-follow.rs:34:14 | LL | ($e:expr |) => {}; | ^ not allowed after `expr` fragments @@ -175,7 +175,7 @@ LL | ($e:expr |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:34:14 + --> $DIR/macro-follow.rs:35:14 | LL | ($e:expr :) => {}; | ^ not allowed after `expr` fragments @@ -183,7 +183,7 @@ LL | ($e:expr :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:35:14 + --> $DIR/macro-follow.rs:36:14 | LL | ($e:expr >) => {}; | ^ not allowed after `expr` fragments @@ -191,7 +191,7 @@ LL | ($e:expr >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:36:14 + --> $DIR/macro-follow.rs:37:14 | LL | ($e:expr +) => {}; | ^ not allowed after `expr` fragments @@ -199,7 +199,7 @@ LL | ($e:expr +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:37:14 + --> $DIR/macro-follow.rs:38:14 | LL | ($e:expr ident) => {}; | ^^^^^ not allowed after `expr` fragments @@ -207,7 +207,7 @@ LL | ($e:expr ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:38:14 + --> $DIR/macro-follow.rs:39:14 | LL | ($e:expr if) => {}; | ^^ not allowed after `expr` fragments @@ -215,7 +215,7 @@ LL | ($e:expr if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:39:14 + --> $DIR/macro-follow.rs:40:14 | LL | ($e:expr in) => {}; | ^^ not allowed after `expr` fragments @@ -223,7 +223,7 @@ LL | ($e:expr in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:40:14 + --> $DIR/macro-follow.rs:41:14 | LL | ($e:expr $p:pat) => {}; | ^^^^^^ not allowed after `expr` fragments @@ -231,7 +231,7 @@ LL | ($e:expr $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:41:14 + --> $DIR/macro-follow.rs:42:14 | LL | ($e:expr $f:expr) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -239,7 +239,7 @@ LL | ($e:expr $f:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:42:14 + --> $DIR/macro-follow.rs:43:14 | LL | ($e:expr $t:ty) => {}; | ^^^^^ not allowed after `expr` fragments @@ -247,7 +247,7 @@ LL | ($e:expr $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:43:14 + --> $DIR/macro-follow.rs:44:14 | LL | ($e:expr $s:stmt) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -255,7 +255,7 @@ LL | ($e:expr $s:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:44:14 + --> $DIR/macro-follow.rs:45:14 | LL | ($e:expr $p:path) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -263,7 +263,7 @@ LL | ($e:expr $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:45:14 + --> $DIR/macro-follow.rs:46:14 | LL | ($e:expr $b:block) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -271,7 +271,7 @@ LL | ($e:expr $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:46:14 + --> $DIR/macro-follow.rs:47:14 | LL | ($e:expr $i:ident) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -279,7 +279,7 @@ LL | ($e:expr $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:47:14 + --> $DIR/macro-follow.rs:48:14 | LL | ($e:expr $t:tt) => {}; | ^^^^^ not allowed after `expr` fragments @@ -287,7 +287,7 @@ LL | ($e:expr $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:48:14 + --> $DIR/macro-follow.rs:49:14 | LL | ($e:expr $i:item) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -295,15 +295,23 @@ LL | ($e:expr $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:49:14 + --> $DIR/macro-follow.rs:50:14 | LL | ($e:expr $m:meta) => {}; | ^^^^^^^ not allowed after `expr` fragments | = note: allowed there are: `=>`, `,` or `;` +error: `$e:expr` is followed by `$g:guard`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:51:14 + | +LL | ($e:expr $g:guard) => {}; + | ^^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:54:12 + --> $DIR/macro-follow.rs:56:12 | LL | ($t:ty ()) => {}; | ^ not allowed after `ty` fragments @@ -311,7 +319,7 @@ LL | ($t:ty ()) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:56:12 + --> $DIR/macro-follow.rs:58:12 | LL | ($t:ty +) => {}; | ^ not allowed after `ty` fragments @@ -319,7 +327,7 @@ LL | ($t:ty +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:57:12 + --> $DIR/macro-follow.rs:59:12 | LL | ($t:ty ident) => {}; | ^^^^^ not allowed after `ty` fragments @@ -327,7 +335,7 @@ LL | ($t:ty ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:58:12 + --> $DIR/macro-follow.rs:60:12 | LL | ($t:ty if) => {}; | ^^ not allowed after `ty` fragments @@ -335,7 +343,7 @@ LL | ($t:ty if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:59:12 + --> $DIR/macro-follow.rs:61:12 | LL | ($t:ty $p:pat) => {}; | ^^^^^^ not allowed after `ty` fragments @@ -343,7 +351,7 @@ LL | ($t:ty $p:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:60:12 + --> $DIR/macro-follow.rs:62:12 | LL | ($t:ty $e:expr) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -351,7 +359,7 @@ LL | ($t:ty $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:61:12 + --> $DIR/macro-follow.rs:63:12 | LL | ($t:ty $r:ty) => {}; | ^^^^^ not allowed after `ty` fragments @@ -359,7 +367,7 @@ LL | ($t:ty $r:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:62:12 + --> $DIR/macro-follow.rs:64:12 | LL | ($t:ty $s:stmt) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -367,7 +375,7 @@ LL | ($t:ty $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:63:12 + --> $DIR/macro-follow.rs:65:12 | LL | ($t:ty $p:path) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -375,7 +383,7 @@ LL | ($t:ty $p:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:65:12 + --> $DIR/macro-follow.rs:67:12 | LL | ($t:ty $i:ident) => {}; | ^^^^^^^^ not allowed after `ty` fragments @@ -383,7 +391,7 @@ LL | ($t:ty $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:66:12 + --> $DIR/macro-follow.rs:68:12 | LL | ($t:ty $r:tt) => {}; | ^^^^^ not allowed after `ty` fragments @@ -391,7 +399,7 @@ LL | ($t:ty $r:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:67:12 + --> $DIR/macro-follow.rs:69:12 | LL | ($t:ty $i:item) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -399,15 +407,23 @@ LL | ($t:ty $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:68:12 + --> $DIR/macro-follow.rs:70:12 | LL | ($t:ty $m:meta) => {}; | ^^^^^^^ not allowed after `ty` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` +error: `$t:ty` is followed by `$g:guard`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:71:12 + | +LL | ($t:ty $g:guard) => {}; + | ^^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:72:14 + --> $DIR/macro-follow.rs:75:14 | LL | ($s:stmt ()) => {}; | ^ not allowed after `stmt` fragments @@ -415,7 +431,7 @@ LL | ($s:stmt ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:73:14 + --> $DIR/macro-follow.rs:76:14 | LL | ($s:stmt []) => {}; | ^ not allowed after `stmt` fragments @@ -423,7 +439,7 @@ LL | ($s:stmt []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:74:14 + --> $DIR/macro-follow.rs:77:14 | LL | ($s:stmt {}) => {}; | ^ not allowed after `stmt` fragments @@ -431,7 +447,7 @@ LL | ($s:stmt {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:75:14 + --> $DIR/macro-follow.rs:78:14 | LL | ($s:stmt =) => {}; | ^ not allowed after `stmt` fragments @@ -439,7 +455,7 @@ LL | ($s:stmt =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:76:14 + --> $DIR/macro-follow.rs:79:14 | LL | ($s:stmt |) => {}; | ^ not allowed after `stmt` fragments @@ -447,7 +463,7 @@ LL | ($s:stmt |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:77:14 + --> $DIR/macro-follow.rs:80:14 | LL | ($s:stmt :) => {}; | ^ not allowed after `stmt` fragments @@ -455,7 +471,7 @@ LL | ($s:stmt :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:78:14 + --> $DIR/macro-follow.rs:81:14 | LL | ($s:stmt >) => {}; | ^ not allowed after `stmt` fragments @@ -463,7 +479,7 @@ LL | ($s:stmt >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:79:14 + --> $DIR/macro-follow.rs:82:14 | LL | ($s:stmt +) => {}; | ^ not allowed after `stmt` fragments @@ -471,7 +487,7 @@ LL | ($s:stmt +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:80:14 + --> $DIR/macro-follow.rs:83:14 | LL | ($s:stmt ident) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -479,7 +495,7 @@ LL | ($s:stmt ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:81:14 + --> $DIR/macro-follow.rs:84:14 | LL | ($s:stmt if) => {}; | ^^ not allowed after `stmt` fragments @@ -487,7 +503,7 @@ LL | ($s:stmt if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:82:14 + --> $DIR/macro-follow.rs:85:14 | LL | ($s:stmt in) => {}; | ^^ not allowed after `stmt` fragments @@ -495,7 +511,7 @@ LL | ($s:stmt in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:83:14 + --> $DIR/macro-follow.rs:86:14 | LL | ($s:stmt $p:pat) => {}; | ^^^^^^ not allowed after `stmt` fragments @@ -503,7 +519,7 @@ LL | ($s:stmt $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:84:14 + --> $DIR/macro-follow.rs:87:14 | LL | ($s:stmt $e:expr) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -511,7 +527,7 @@ LL | ($s:stmt $e:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:85:14 + --> $DIR/macro-follow.rs:88:14 | LL | ($s:stmt $t:ty) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -519,7 +535,7 @@ LL | ($s:stmt $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:86:14 + --> $DIR/macro-follow.rs:89:14 | LL | ($s:stmt $t:stmt) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -527,7 +543,7 @@ LL | ($s:stmt $t:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:87:14 + --> $DIR/macro-follow.rs:90:14 | LL | ($s:stmt $p:path) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -535,7 +551,7 @@ LL | ($s:stmt $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:88:14 + --> $DIR/macro-follow.rs:91:14 | LL | ($s:stmt $b:block) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -543,7 +559,7 @@ LL | ($s:stmt $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:89:14 + --> $DIR/macro-follow.rs:92:14 | LL | ($s:stmt $i:ident) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -551,7 +567,7 @@ LL | ($s:stmt $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:90:14 + --> $DIR/macro-follow.rs:93:14 | LL | ($s:stmt $t:tt) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -559,7 +575,7 @@ LL | ($s:stmt $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:91:14 + --> $DIR/macro-follow.rs:94:14 | LL | ($s:stmt $i:item) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -567,23 +583,31 @@ LL | ($s:stmt $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:92:14 + --> $DIR/macro-follow.rs:95:14 | LL | ($s:stmt $m:meta) => {}; | ^^^^^^^ not allowed after `stmt` fragments | = note: allowed there are: `=>`, `,` or `;` -error: `$p:path` is followed by `(`, which is not allowed for `path` fragments +error: `$s:stmt` is followed by `$g:guard`, which is not allowed for `stmt` fragments --> $DIR/macro-follow.rs:96:14 | +LL | ($s:stmt $g:guard) => {}; + | ^^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$p:path` is followed by `(`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:100:14 + | LL | ($p:path ()) => {}; | ^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `+`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:98:14 + --> $DIR/macro-follow.rs:102:14 | LL | ($p:path +) => {}; | ^ not allowed after `path` fragments @@ -591,7 +615,7 @@ LL | ($p:path +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:99:14 + --> $DIR/macro-follow.rs:103:14 | LL | ($p:path ident) => {}; | ^^^^^ not allowed after `path` fragments @@ -599,7 +623,7 @@ LL | ($p:path ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `if`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:100:14 + --> $DIR/macro-follow.rs:104:14 | LL | ($p:path if) => {}; | ^^ not allowed after `path` fragments @@ -607,7 +631,7 @@ LL | ($p:path if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:101:14 + --> $DIR/macro-follow.rs:105:14 | LL | ($p:path $q:pat) => {}; | ^^^^^^ not allowed after `path` fragments @@ -615,7 +639,7 @@ LL | ($p:path $q:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:102:14 + --> $DIR/macro-follow.rs:106:14 | LL | ($p:path $e:expr) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -623,7 +647,7 @@ LL | ($p:path $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:103:14 + --> $DIR/macro-follow.rs:107:14 | LL | ($p:path $t:ty) => {}; | ^^^^^ not allowed after `path` fragments @@ -631,7 +655,7 @@ LL | ($p:path $t:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:104:14 + --> $DIR/macro-follow.rs:108:14 | LL | ($p:path $s:stmt) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -639,7 +663,7 @@ LL | ($p:path $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:105:14 + --> $DIR/macro-follow.rs:109:14 | LL | ($p:path $q:path) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -647,7 +671,7 @@ LL | ($p:path $q:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:107:14 + --> $DIR/macro-follow.rs:111:14 | LL | ($p:path $i:ident) => {}; | ^^^^^^^^ not allowed after `path` fragments @@ -655,7 +679,7 @@ LL | ($p:path $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:108:14 + --> $DIR/macro-follow.rs:112:14 | LL | ($p:path $t:tt) => {}; | ^^^^^ not allowed after `path` fragments @@ -663,7 +687,7 @@ LL | ($p:path $t:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:109:14 + --> $DIR/macro-follow.rs:113:14 | LL | ($p:path $i:item) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -671,12 +695,20 @@ LL | ($p:path $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:110:14 + --> $DIR/macro-follow.rs:114:14 | LL | ($p:path $m:meta) => {}; | ^^^^^^^ not allowed after `path` fragments | = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` -error: aborting due to 85 previous errors +error: `$p:path` is followed by `$g:guard`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:115:14 + | +LL | ($p:path $g:guard) => {}; + | ^^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 89 previous errors diff --git a/tests/ui/macros/macro-guard-matcher.rs b/tests/ui/macros/macro-guard-matcher.rs new file mode 100644 index 0000000000000..81a4412686de3 --- /dev/null +++ b/tests/ui/macros/macro-guard-matcher.rs @@ -0,0 +1,17 @@ +#![feature(macro_guard_matcher)] + +fn main() { + macro_rules! m { + ($x:guard) => {}; + } + + // Accepts + m!(if true); + m!(if let Some(x) = Some(1)); + m!(if let Some(x) = Some(1) && x == 1); + m!(if let Some(x) = Some(Some(1)) && let Some(1) = x); + m!(if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1); + + // Rejects + m!(let Some(x) = Some(1)); //~ERROR no rules expected keyword `let` +} diff --git a/tests/ui/macros/macro-guard-matcher.stderr b/tests/ui/macros/macro-guard-matcher.stderr new file mode 100644 index 0000000000000..eddb0de9c4c54 --- /dev/null +++ b/tests/ui/macros/macro-guard-matcher.stderr @@ -0,0 +1,17 @@ +error: no rules expected keyword `let` + --> $DIR/macro-guard-matcher.rs:16:8 + | +LL | macro_rules! m { + | -------------- when calling this macro +... +LL | m!(let Some(x) = Some(1)); + | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$x:guard` + --> $DIR/macro-guard-matcher.rs:5:10 + | +LL | ($x:guard) => {}; + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/macro-input-future-proofing.stderr b/tests/ui/macros/macro-input-future-proofing.stderr index 11960db987435..a12cc9f9b416d 100644 --- a/tests/ui/macros/macro-input-future-proofing.stderr +++ b/tests/ui/macros/macro-input-future-proofing.stderr @@ -20,7 +20,7 @@ error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments LL | ($pa:pat >) => (); | ^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments --> $DIR/macro-input-future-proofing.rs:14:14 @@ -28,7 +28,7 @@ error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragme LL | ($pa:pat $pb:pat $ty:ty ,) => (); | ^^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments --> $DIR/macro-input-future-proofing.rs:14:22 @@ -36,7 +36,7 @@ error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragmen LL | ($pa:pat $pb:pat $ty:ty ,) => (); | ^^^^^^ not allowed after `pat` fragments | - = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments --> $DIR/macro-input-future-proofing.rs:17:17 diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr index a06487be3d601..9179fbc31961c 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr @@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32 @@ -16,7 +16,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36 @@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { | | | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr index c3754dde080a3..af76e3f095f15 100644 --- a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr @@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28 @@ -16,7 +16,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } | | | help: try a `pat_param` fragment specifier instead: `$x:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35 @@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { | | | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` | - = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: aborting due to 3 previous errors diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 3f331b0dd5f14..af2ba7a809ad0 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -14,6 +14,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(macro_guard_matcher)] #![deny(unused_macros)] // These macros force the use of AST pretty-printing by converting the input to @@ -27,6 +28,7 @@ macro_rules! path { ($path:path) => { stringify!($path) }; } macro_rules! stmt { ($stmt:stmt) => { stringify!($stmt) }; } macro_rules! ty { ($ty:ty) => { stringify!($ty) }; } macro_rules! vis { ($vis:vis) => { stringify!($vis) }; } +macro_rules! guard { ($guard:guard) => { stringify!($guard) }; } macro_rules! c1 { ($frag:ident, [$($tt:tt)*], $s:literal) => { @@ -792,6 +794,21 @@ fn test_vis() { // Attributes are not allowed on visibilities. } +#[test] +fn test_guard() { + c1!(guard, [ if true ], "if true"); + c1!(guard, [ if let Some(x) = Some(1) ], "if let Some(x) = Some(1)"); + c1!(guard, [ if let Some(x) = Some(1) && x == 1 ], "if let Some(x) = Some(1) && x == 1"); + c1!(guard, + [ if let Some(x) = Some(Some(1)) && let Some(1) = x ], + "if let Some(x) = Some(Some(1)) && let Some(1) = x" + ); + c1!(guard, + [ if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1 ], + "if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1" + ); +} + macro_rules! p { ([$($tt:tt)*], $s:literal) => { assert_eq!(stringify!($($tt)*), $s); From a197752e88d99e449caf695f9d2101ceeded24a7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 24 Feb 2026 11:10:51 +0000 Subject: [PATCH 06/40] Add kernel-hwaddress sanitizer Signed-off-by: Alice Ryhl --- .../src/attributes/codegen_attrs.rs | 6 ++- compiler/rustc_codegen_llvm/src/attributes.rs | 3 +- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++ compiler/rustc_codegen_llvm/src/base.rs | 8 +++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 + compiler/rustc_codegen_ssa/src/back/link.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 2 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 10 +++-- compiler/rustc_session/src/config/cfg.rs | 4 ++ compiler/rustc_session/src/options.rs | 4 +- compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 17 +++++++-- .../aarch64_be_unknown_none_softfloat.rs | 4 +- .../src/spec/targets/aarch64_unknown_none.rs | 4 +- .../targets/aarch64_unknown_none_softfloat.rs | 4 +- .../src/spec/targets/aarch64_unknown_nuttx.rs | 4 +- .../spec/targets/aarch64v8r_unknown_none.rs | 4 +- .../aarch64v8r_unknown_none_softfloat.rs | 4 +- src/tools/compiletest/src/common.rs | 1 + .../src/directives/directive_names.rs | 1 + src/tools/compiletest/src/directives/needs.rs | 7 ++++ .../sanitizer/hwasan-vs-khwasan.rs | 29 ++++++++++++++ .../sanitizer/hwasan-vs-khwasan.rs | 27 +++++++++++++ tests/codegen-llvm/sanitizer/kasan-recover.rs | 33 ++++++++++++++++ .../sanitizer/khwasan-lifetime-markers.rs | 21 ++++++++++ .../codegen-llvm/sanitizer/khwasan-recover.rs | 37 ++++++++++++++++++ .../sanitizer/sanitize-off-hwasan-khwasan.rs | 38 +++++++++++++++++++ .../sanitizer/sanitize-off-khwasan-hwasan.rs | 31 +++++++++++++++ .../sanitizer/sanitizer-recover.rs | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- .../ui/sanitize-attr/invalid-sanitize.stderr | 2 +- tests/ui/sanitizer/cfg-khwasan.rs | 22 +++++++++++ tests/ui/sanitizer/incompatible-khwasan.rs | 9 +++++ .../ui/sanitizer/incompatible-khwasan.stderr | 4 ++ .../sanitizer/unsupported-target-khwasan.rs | 9 +++++ .../unsupported-target-khwasan.stderr | 4 ++ 37 files changed, 345 insertions(+), 22 deletions(-) create mode 100644 tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs create mode 100644 tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs create mode 100644 tests/codegen-llvm/sanitizer/kasan-recover.rs create mode 100644 tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs create mode 100644 tests/codegen-llvm/sanitizer/khwasan-recover.rs create mode 100644 tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs create mode 100644 tests/codegen-llvm/sanitizer/sanitize-off-khwasan-hwasan.rs create mode 100644 tests/ui/sanitizer/cfg-khwasan.rs create mode 100644 tests/ui/sanitizer/incompatible-khwasan.rs create mode 100644 tests/ui/sanitizer/incompatible-khwasan.stderr create mode 100644 tests/ui/sanitizer/unsupported-target-khwasan.rs create mode 100644 tests/ui/sanitizer/unsupported-target-khwasan.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a8db114129ffd..33fb19089ba55 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -587,6 +587,7 @@ impl SingleAttributeParser for SanitizeParser { r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, + r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, @@ -654,7 +655,9 @@ impl SingleAttributeParser for SanitizeParser { Some(sym::memtag) => apply(SanitizerSet::MEMTAG), Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK), Some(sym::thread) => apply(SanitizerSet::THREAD), - Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS), + Some(sym::hwaddress) | Some(sym::kernel_hwaddress) => { + apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) + } Some(sym::realtime) => match value.value_as_str() { Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking), Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking), @@ -679,6 +682,7 @@ impl SingleAttributeParser for SanitizeParser { sym::shadow_call_stack, sym::thread, sym::hwaddress, + sym::kernel_hwaddress, sym::realtime, ], ); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index d51adb6e13b07..f300ee5d4c991 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -120,7 +120,8 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>( if enabled.contains(SanitizerSet::THREAD) { attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx)); } - if enabled.contains(SanitizerSet::HWADDRESS) { + if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS) + { attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx)); } if enabled.contains(SanitizerSet::SHADOWCALLSTACK) { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index efd4e55d5a856..2125cf6383bf3 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -652,6 +652,10 @@ pub(crate) unsafe fn llvm_optimize( sanitize_kernel_address_recover: config .sanitizer_recover .contains(SanitizerSet::KERNELADDRESS), + sanitize_kernel_hwaddress: config.sanitizer.contains(SanitizerSet::KERNELHWADDRESS), + sanitize_kernel_hwaddress_recover: config + .sanitizer_recover + .contains(SanitizerSet::KERNELHWADDRESS), }) } else { None diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index d00e70638b45a..2276809477121 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -210,10 +210,14 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { } pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) { - if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) { + if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) + || attrs.sanitizers.disabled.contains(SanitizerSet::KERNELADDRESS) + { unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) }; } - if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) { + if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) + || attrs.sanitizers.disabled.contains(SanitizerSet::KERNELHWADDRESS) + { unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) }; } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 77438472644fc..7355d11367920 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -464,6 +464,8 @@ pub(crate) struct SanitizerOptions { pub sanitize_hwaddress_recover: bool, pub sanitize_kernel_address: bool, pub sanitize_kernel_address_recover: bool, + pub sanitize_kernel_hwaddress: bool, + pub sanitize_kernel_hwaddress_recover: bool, } /// LLVMRustRelocModel diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7a3d5a6bb2248..be7da2e81add8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1341,6 +1341,7 @@ fn add_sanitizer_libraries( if sanitizer.contains(SanitizerSet::LEAK) && !sanitizer.contains(SanitizerSet::ADDRESS) && !sanitizer.contains(SanitizerSet::HWADDRESS) + && !sanitizer.contains(SanitizerSet::KERNELHWADDRESS) { link_sanitizer_runtime(sess, flavor, linker, "lsan"); } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3a2f548902d11..3187876626f3e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -773,7 +773,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature) ), gated!( - sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, + sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, EncodeCrossCrate::No, sanitize, experimental!(sanitize), ), gated!( diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 00d03f023924a..b4f6bb4583c10 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -540,6 +540,8 @@ struct LLVMRustSanitizerOptions { bool SanitizeHWAddressRecover; bool SanitizeKernelAddress; bool SanitizeKernelAddressRecover; + bool SanitizeKernelHWAddress; + bool SanitizeKernelHWAddressRecover; }; extern "C" typedef void (*registerEnzymeAndPassPipelineFn)( @@ -767,13 +769,15 @@ extern "C" LLVMRustResult LLVMRustOptimize( !TM->getTargetTriple().isOSWindows())); }); } - if (SanitizerOptions->SanitizeHWAddress) { + if (SanitizerOptions->SanitizeHWAddress || + SanitizerOptions->SanitizeKernelHWAddress) { OptimizerLastEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase phase) { HWAddressSanitizerOptions opts( - /*CompileKernel=*/false, - SanitizerOptions->SanitizeHWAddressRecover, + SanitizerOptions->SanitizeKernelHWAddress, + SanitizerOptions->SanitizeHWAddressRecover || + SanitizerOptions->SanitizeKernelHWAddressRecover, /*DisableOptimization=*/false); MPM.addPass(HWAddressSanitizerPass(opts)); }); diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index ebbbe36878daa..17fdba37b4bc7 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -229,6 +229,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { if s == SanitizerSet::KERNELADDRESS { s = SanitizerSet::ADDRESS; } + // KHWASAN is still HWASAN under the hood, so it uses the same attribute. + if s == SanitizerSet::KERNELHWADDRESS { + s = SanitizerSet::HWADDRESS; + } ins_str!(sym::sanitize, &s.to_string()); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0bc432a0ff06c..d370f00d21987 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -106,6 +106,7 @@ mod target_modifier_consistency_check { | SanitizerSet::SHADOWCALLSTACK | SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS | SanitizerSet::SAFESTACK | SanitizerSet::DATAFLOW; @@ -810,7 +811,7 @@ mod desc { 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; pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'"; + pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'"; pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub(crate) const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -1252,6 +1253,7 @@ pub mod parse { "dataflow" => SanitizerSet::DATAFLOW, "kcfi" => SanitizerSet::KCFI, "kernel-address" => SanitizerSet::KERNELADDRESS, + "kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0548380331bef..3da2d891e19db 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -529,7 +529,7 @@ impl Session { // AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs. // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. - || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) + || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) } pub fn diagnostic_width(&self) -> usize { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 286fea7d90505..6da8974cba641 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1115,6 +1115,7 @@ symbols! { iterator_collect_fn, kcfi, kernel_address, + kernel_hwaddress, keylocker_x86, keyword, kind, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8683e4f51279e..2b5cbd6703084 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1175,9 +1175,10 @@ bitflags::bitflags! { const SHADOWCALLSTACK = 1 << 7; const KCFI = 1 << 8; const KERNELADDRESS = 1 << 9; - const SAFESTACK = 1 << 10; - const DATAFLOW = 1 << 11; - const REALTIME = 1 << 12; + const KERNELHWADDRESS = 1 << 10; + const SAFESTACK = 1 << 11; + const DATAFLOW = 1 << 12; + const REALTIME = 1 << 13; } } rustc_data_structures::external_bitflags_debug! { SanitizerSet } @@ -1191,24 +1192,32 @@ impl SanitizerSet { (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS), (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG), (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::ADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK), (SanitizerSet::LEAK, SanitizerSet::MEMORY), (SanitizerSet::LEAK, SanitizerSet::THREAD), (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS), + (SanitizerSet::LEAK, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::LEAK, SanitizerSet::SAFESTACK), (SanitizerSet::MEMORY, SanitizerSet::THREAD), (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS), (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS), + (SanitizerSet::MEMORY, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK), (SanitizerSet::THREAD, SanitizerSet::HWADDRESS), (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS), + (SanitizerSet::THREAD, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::THREAD, SanitizerSet::SAFESTACK), (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG), (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS), + (SanitizerSet::HWADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK), (SanitizerSet::CFI, SanitizerSet::KCFI), (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS), + (SanitizerSet::MEMTAG, SanitizerSet::KERNELHWADDRESS), + (SanitizerSet::KERNELADDRESS, SanitizerSet::KERNELHWADDRESS), (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK), + (SanitizerSet::KERNELHWADDRESS, SanitizerSet::SAFESTACK), ]; /// Return sanitizer's name @@ -1221,6 +1230,7 @@ impl SanitizerSet { SanitizerSet::DATAFLOW => "dataflow", SanitizerSet::KCFI => "kcfi", SanitizerSet::KERNELADDRESS => "kernel-address", + SanitizerSet::KERNELHWADDRESS => "kernel-hwaddress", SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", @@ -1266,6 +1276,7 @@ impl FromStr for SanitizerSet { "dataflow" => SanitizerSet::DATAFLOW, "kcfi" => SanitizerSet::KCFI, "kernel-address" => SanitizerSet::KERNELADDRESS, + "kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, "memtag" => SanitizerSet::MEMTAG, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs index e204c6466e297..aae7af82d5536 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs @@ -22,7 +22,9 @@ pub(crate) fn target() -> Target { relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index 1c166030d5e5d..13d3b77588a0e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { &["--fix-cortex-a53-843419"], ), features: "+v8a,+strict-align,+neon".into(), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index ed2e2fb6ab70b..2e972f2fa2acf 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, default_uwtable: true, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs index 19b7ebe036747..1e06d3abb723b 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs @@ -21,7 +21,9 @@ pub(crate) fn target() -> Target { &["--fix-cortex-a53-843419"], ), features: "+v8a,+strict-align,+neon".into(), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs index 8f8bbb4a41caf..680d89653db82 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none.rs @@ -8,7 +8,9 @@ pub(crate) fn target() -> Target { // based off the aarch64-unknown-none target at time of addition linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs index 6f11f97e3d1df..731b61d6731f8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64v8r_unknown_none_softfloat.rs @@ -12,7 +12,9 @@ pub(crate) fn target() -> Target { relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), - supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, default_uwtable: true, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index bc94a81ba3b52..7cac7f5c04940 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -168,6 +168,7 @@ pub enum Sanitizer { Dataflow, Kcfi, KernelAddress, + KernelHwaddress, Leak, Memory, Memtag, diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 9af881b5c2f58..eaa1a39a9eeef 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -179,6 +179,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-hwaddress", "needs-sanitizer-kasan", "needs-sanitizer-kcfi", + "needs-sanitizer-khwasan", "needs-sanitizer-leak", "needs-sanitizer-memory", "needs-sanitizer-memtag", diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 168d5e9eb649b..e9f3d6c28d6ef 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -46,6 +46,11 @@ pub(super) fn handle_needs( condition: cache.sanitizer_kasan, ignore_reason: "ignored on targets without kernel address sanitizer", }, + Need { + name: "needs-sanitizer-khwasan", + condition: cache.sanitizer_khwasan, + ignore_reason: "ignored on targets without kernel hardware-assisted address sanitizer", + }, Need { name: "needs-sanitizer-leak", condition: cache.sanitizer_leak, @@ -332,6 +337,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_dataflow: bool, sanitizer_kcfi: bool, sanitizer_kasan: bool, + sanitizer_khwasan: bool, sanitizer_leak: bool, sanitizer_memory: bool, sanitizer_thread: bool, @@ -359,6 +365,7 @@ impl CachedNeedsConditions { sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow), sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi), sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress), + sanitizer_khwasan: sanitizers.contains(&Sanitizer::KernelHwaddress), sanitizer_leak: sanitizers.contains(&Sanitizer::Leak), sanitizer_memory: sanitizers.contains(&Sanitizer::Memory), sanitizer_thread: sanitizers.contains(&Sanitizer::Thread), diff --git a/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs new file mode 100644 index 0000000000000..bcb2fbc613dff --- /dev/null +++ b/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -0,0 +1,29 @@ +// Verifies that HWASAN and KHWASAN emit different assembly instrumentation on AArch64. +// +//@ add-minicore +//@ assembly-output: emit-asm +//@ revisions: hwasan khwasan +//@[hwasan] compile-flags: --target aarch64-unknown-linux-gnu -Zsanitizer=hwaddress +//@[khwasan] compile-flags: --target aarch64-unknown-none -Zsanitizer=kernel-hwaddress +//@ compile-flags: -Copt-level=1 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; + +// hwasan-LABEL: test: +// hwasan: adrp x{{[0-9]+}}, :gottprel:__hwasan_tls +// hwasan: mrs x{{[0-9]+}}, TPIDR_EL0 +// hwasan: bl __hwasan_check_x0_0_short_v2 + +// khwasan-LABEL: test: +// khwasan-NOT: __hwasan_tls +// khwasan: orr x{{[0-9]+}}, x0, #0xff00000000000000 +// khwasan: bl __hwasan_check_x0_67043328_fixed_0_short_v2 + +#[no_mangle] +pub fn test(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs new file mode 100644 index 0000000000000..fd3aacee5af2c --- /dev/null +++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -0,0 +1,27 @@ +// Verifies that HWASAN and KHWASAN emit different instrumentation. +// +//@ add-minicore +//@ revisions: hwasan khwasan +//@[hwasan] compile-flags: --target aarch64-unknown-linux-gnu -Zsanitizer=hwaddress +//@[khwasan] compile-flags: --target aarch64-unknown-none -Zsanitizer=kernel-hwaddress +//@ compile-flags: -Copt-level=0 + +#![crate_type = "lib"] +#![feature(no_core, lang_items, sanitize)] +#![no_core] + +extern crate minicore; + +// hwasan-LABEL: define {{.*}} @test +// hwasan: @__hwasan_tls +// hwasan: call void @llvm.hwasan.check.memaccess.shortgranules +// hwasan: declare void @__hwasan_init() + +// khwasan-LABEL: define {{.*}} @test +// khwasan-NOT: @__hwasan_init +// khwasan: @__hwasan_tls +// khwasan: call void @llvm.hwasan.check.memaccess.shortgranules +#[no_mangle] +pub fn test(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/kasan-recover.rs b/tests/codegen-llvm/sanitizer/kasan-recover.rs new file mode 100644 index 0000000000000..8f0e6eb3a605d --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kasan-recover.rs @@ -0,0 +1,33 @@ +// Verifies that KernelAddressSanitizer recovery mode can be enabled +// with -Zsanitizer-recover=kernel-address. +// +//@ add-minicore +//@ revisions: KASAN KASAN-RECOVER +//@ compile-flags: -Copt-level=0 +//@[KASAN] compile-flags: -Zsanitizer=kernel-address --target x86_64-unknown-none +//@[KASAN] needs-llvm-components: x86 +//@[KASAN-RECOVER] compile-flags: -Zsanitizer=kernel-address +//@[KASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-address --target x86_64-unknown-none +//@[KASAN-RECOVER] needs-llvm-components: x86 + +#![feature(no_core, sanitize, lang_items)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// KASAN-LABEL: define{{.*}}@penguin( +// KASAN: call void @__asan_report_load4( +// KASAN: unreachable +// KASAN: } + +// KASAN-RECOVER-LABEL: define{{.*}}@penguin( +// KASAN-RECOVER: call void @__asan_report_load4_noabort( +// KASAN-RECOVER-NOT: unreachable +// KASAN-RECOVER: } + +#[no_mangle] +pub unsafe fn penguin(p: *mut i32) -> i32 { + *p +} diff --git a/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs b/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs new file mode 100644 index 0000000000000..01b129cb69207 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs @@ -0,0 +1,21 @@ +// Verifies that `-Zsanitizer=kernel-hwaddress` enables lifetime markers. + +//@ add-minicore +//@ compile-flags: -Zsanitizer=kernel-hwaddress -Copt-level=0 +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-none +//@[aarch64] needs-llvm-components: aarch64 + +#![crate_type = "rlib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: ; khwasan_lifetime_markers::test +// CHECK: call void @llvm.lifetime.start +// CHECK: call void @llvm.lifetime.end +pub fn test() { + let _x = [0u8; 10]; +} diff --git a/tests/codegen-llvm/sanitizer/khwasan-recover.rs b/tests/codegen-llvm/sanitizer/khwasan-recover.rs new file mode 100644 index 0000000000000..957b867a61ad9 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/khwasan-recover.rs @@ -0,0 +1,37 @@ +// Verifies that KernelHWAddressSanitizer recovery mode can be enabled +// with -Zsanitizer-recover=kernel-hwaddress. +// +//@ add-minicore +//@[KHWASAN] needs-llvm-components: aarch64 +//@[KHWASAN-RECOVER] needs-llvm-components: aarch64 +//@ revisions: KHWASAN KHWASAN-RECOVER +//@ no-prefer-dynamic +//@ compile-flags: -Copt-level=0 +//@[KHWASAN] compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none +//@[KHWASAN-RECOVER] compile-flags: -Zsanitizer=kernel-hwaddress +//@[KHWASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-hwaddress +//@[KHWASAN-RECOVER] compile-flags: --target aarch64-unknown-none + +#![feature(no_core, sanitize, lang_items)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// KHWASAN-LABEL: define{{.*}}@penguin( +// KHWASAN: call void @llvm.hwasan.check.memaccess +// KHWASAN: ret i32 +// KHWASAN: } +// KHWASAN: declare void @__hwasan_load4(i64) + +// KHWASAN-RECOVER-LABEL: define{{.*}}@penguin( +// KHWASAN-RECOVER: call void asm sideeffect "brk #2338", "{x0}"(i64 %{{[0-9]+}}) +// KHWASAN-RECOVER-NOT: unreachable +// KHWASAN-RECOVER: } +// KHWASAN-RECOVER: declare void @__hwasan_load4_noabort(i64) + +#[no_mangle] +pub unsafe fn penguin(p: *mut i32) -> i32 { + *p +} diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs new file mode 100644 index 0000000000000..c0e23f5f596ba --- /dev/null +++ b/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs @@ -0,0 +1,38 @@ +// Verifies that the `#[sanitize(hwaddress = "off")]` attribute also turns off +// the kernel hardware-assisted address sanitizer. +// +//@ add-minicore +//@ compile-flags: -Zsanitizer=kernel-hwaddress -Ctarget-feature=-crt-static -Copt-level=0 +//@ revisions: aarch64 aarch64v8r +//@[aarch64] compile-flags: --target aarch64-unknown-none +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64v8r] compile-flags: --target aarch64v8r-unknown-none +//@[aarch64v8r] needs-llvm-components: aarch64 + +#![crate_type = "rlib"] +#![feature(no_core, sanitize, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-NOT: sanitize_hwaddress +// CHECK-LABEL: define {{.*}} @unsanitized +// CHECK: start: +// CHECK-NOT: call void @llvm.hwasan.check.memaccess +// CHECK: } +#[sanitize(hwaddress = "off")] +#[no_mangle] +pub fn unsanitized(b: &mut u8) -> u8 { + *b +} + +// CHECK: sanitize_hwaddress +// CHECK-LABEL: define {{.*}} @sanitized +// CHECK: start: +// CHECK: call void @llvm.hwasan.check.memaccess +// CHECK: } +#[no_mangle] +pub fn sanitized(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-khwasan-hwasan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-khwasan-hwasan.rs new file mode 100644 index 0000000000000..a4491eb9f785d --- /dev/null +++ b/tests/codegen-llvm/sanitizer/sanitize-off-khwasan-hwasan.rs @@ -0,0 +1,31 @@ +// Verifies that the `#[sanitize(kernel_hwaddress = "off")]` attribute also turns off +// the hardware-assisted address sanitizer. +// +//@ needs-sanitizer-hwaddress +//@ compile-flags: -Cunsafe-allow-abi-mismatch=sanitizer +//@ compile-flags: -Ctarget-feature=-crt-static +//@ compile-flags: -Zsanitizer=hwaddress -Copt-level=0 + +#![crate_type = "lib"] +#![feature(sanitize)] + +// CHECK-NOT: sanitize_hwaddress +// CHECK-LABEL: define {{.*}} @unsanitized +// CHECK: start: +// CHECK-NOT: call void @llvm.hwasan.check.memaccess +// CHECK: } +#[sanitize(kernel_hwaddress = "off")] +#[no_mangle] +pub fn unsanitized(b: &mut u8) -> u8 { + *b +} + +// CHECK: sanitize_hwaddress +// CHECK-LABEL: define {{.*}} @sanitized +// CHECK: start: +// CHECK: call void @llvm.hwasan.check.memaccess +// CHECK: } +#[no_mangle] +pub fn sanitized(b: &mut u8) -> u8 { + *b +} diff --git a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs index b8a24e31c30bb..5e05b92f3b100 100644 --- a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs +++ b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs @@ -5,7 +5,7 @@ //@ needs-sanitizer-memory //@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO //@ no-prefer-dynamic -//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +//@ compile-flags: -Cunsafe-allow-abi-mismatch=sanitizer //@ compile-flags: -Ctarget-feature=-crt-static //@[ASAN] compile-flags: -Zsanitizer=address -Copt-level=0 //@[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index efa0a7f4af9ac..0ba2f0b0f2096 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -120,7 +120,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `realtime`, `safestack`, `shadow-call-stack`, and `thread` + = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `realtime`, `safestack`, `shadow-call-stack`, and `thread` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr index 00bb7746d05f3..b35c2f9976f0e 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.stderr +++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr @@ -4,7 +4,7 @@ error[E0539]: malformed `sanitize` attribute input LL | #[sanitize(brontosaurus = "off")] | ^^^^^^^^^^^------------^^^^^^^^^^ | | - | valid arguments are "address", "kernel_address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress" or "realtime" + | valid arguments are "address", "kernel_address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread", "hwaddress", "kernel_hwaddress" or "realtime" error: multiple `sanitize` attributes --> $DIR/invalid-sanitize.rs:7:1 diff --git a/tests/ui/sanitizer/cfg-khwasan.rs b/tests/ui/sanitizer/cfg-khwasan.rs new file mode 100644 index 0000000000000..c2b0505a34c26 --- /dev/null +++ b/tests/ui/sanitizer/cfg-khwasan.rs @@ -0,0 +1,22 @@ +// Verifies that when compiling with -Zsanitizer=kernel-hwaddress, +// the `#[cfg(sanitize = "hwaddress")]` attribute is configured. + +//@ add-minicore +//@ check-pass +//@ compile-flags: -Zsanitizer=kernel-hwaddress +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-none +//@[aarch64] needs-llvm-components: aarch64 +//@ ignore-backends: gcc + +#![crate_type = "rlib"] +#![feature(cfg_sanitize, no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +const _: fn() -> () = main; + +#[cfg(sanitize = "hwaddress")] +fn main() {} diff --git a/tests/ui/sanitizer/incompatible-khwasan.rs b/tests/ui/sanitizer/incompatible-khwasan.rs new file mode 100644 index 0000000000000..eb6a5d33a472b --- /dev/null +++ b/tests/ui/sanitizer/incompatible-khwasan.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Z sanitizer=kernel-hwaddress -Z sanitizer=kernel-address --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc + +#![feature(no_core)] +#![no_core] +#![no_main] + +//~? ERROR `-Zsanitizer=kernel-address` is incompatible with `-Zsanitizer=kernel-hwaddress` diff --git a/tests/ui/sanitizer/incompatible-khwasan.stderr b/tests/ui/sanitizer/incompatible-khwasan.stderr new file mode 100644 index 0000000000000..35246fb266230 --- /dev/null +++ b/tests/ui/sanitizer/incompatible-khwasan.stderr @@ -0,0 +1,4 @@ +error: `-Zsanitizer=kernel-address` is incompatible with `-Zsanitizer=kernel-hwaddress` + +error: aborting due to 1 previous error + diff --git a/tests/ui/sanitizer/unsupported-target-khwasan.rs b/tests/ui/sanitizer/unsupported-target-khwasan.rs new file mode 100644 index 0000000000000..bef6d95e57b21 --- /dev/null +++ b/tests/ui/sanitizer/unsupported-target-khwasan.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Z sanitizer=kernel-hwaddress --target x86_64-unknown-none +//@ needs-llvm-components: x86 +//@ ignore-backends: gcc + +#![feature(no_core)] +#![no_core] +#![no_main] + +//~? ERROR kernel-hwaddress sanitizer is not supported for this target diff --git a/tests/ui/sanitizer/unsupported-target-khwasan.stderr b/tests/ui/sanitizer/unsupported-target-khwasan.stderr new file mode 100644 index 0000000000000..8b122a610ee40 --- /dev/null +++ b/tests/ui/sanitizer/unsupported-target-khwasan.stderr @@ -0,0 +1,4 @@ +error: kernel-hwaddress sanitizer is not supported for this target + +error: aborting due to 1 previous error + From e41bbfaaa6b4bfde2130add801ec3bf392d74539 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 6 Mar 2026 17:07:14 +0000 Subject: [PATCH 07/40] Explain why __hwasan_tls is present in LLVM codegen --- tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs index fd3aacee5af2c..b059f6bbefb4a 100644 --- a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs +++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -17,9 +17,19 @@ extern crate minicore; // hwasan: call void @llvm.hwasan.check.memaccess.shortgranules // hwasan: declare void @__hwasan_init() +// The `__hwasan_tls` symbol is unconditionally declared by LLVM's `HWAddressSanitizer` pass. +// However, in kernel mode KHWASAN does not actually use it (because shadow mapping is fixed +// and the stack frame ring buffer is disabled). It remains an unused declaration in the LLVM IR +// and is optimized out before the final assembly/object file is generated, so it does not end +// up in the final binary. Thus, assert that it appears in the output, but not inside `test`. +// +// khwasan: @__hwasan_tls // khwasan-LABEL: define {{.*}} @test +// khwasan-NOT: @__hwasan_tls +// +// Also test a few other things appear under the LABEL. +// // khwasan-NOT: @__hwasan_init -// khwasan: @__hwasan_tls // khwasan: call void @llvm.hwasan.check.memaccess.shortgranules #[no_mangle] pub fn test(b: &mut u8) -> u8 { From ec03f4ef294d3a75ed12b36662d1a40441b0a726 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 16 Mar 2026 14:23:24 +0000 Subject: [PATCH 08/40] Adjust lifetime markers comment --- compiler/rustc_session/src/session.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3da2d891e19db..96f54481350db 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -527,8 +527,11 @@ impl Session { pub fn emit_lifetime_markers(&self) -> bool { self.opts.optimize != config::OptLevel::No // AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs. + // // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. - // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. + // + // HWAddressSanitizer and KernelHWAddressSanitizer will use lifetimes to detect use after + // scope bugs in the future. || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) } From c679e3daf2166e2bcd56e8acc2cacfe6dc9757a8 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 17 Mar 2026 07:49:28 +0000 Subject: [PATCH 09/40] Simplify tests and fix test tidy issue --- tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs | 2 ++ tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs | 2 ++ tests/codegen-llvm/sanitizer/kasan-recover.rs | 8 +++----- tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs | 5 ++--- tests/codegen-llvm/sanitizer/khwasan-recover.rs | 9 +++------ .../sanitizer/sanitize-off-hwasan-khwasan.rs | 9 +++------ tests/ui/sanitizer/cfg-khwasan.rs | 6 ++---- 7 files changed, 17 insertions(+), 24 deletions(-) diff --git a/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs index bcb2fbc613dff..a4362b3621326 100644 --- a/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs +++ b/tests/assembly-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -4,7 +4,9 @@ //@ assembly-output: emit-asm //@ revisions: hwasan khwasan //@[hwasan] compile-flags: --target aarch64-unknown-linux-gnu -Zsanitizer=hwaddress +//@[hwasan] needs-llvm-components: aarch64 //@[khwasan] compile-flags: --target aarch64-unknown-none -Zsanitizer=kernel-hwaddress +//@[khwasan] needs-llvm-components: aarch64 //@ compile-flags: -Copt-level=1 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs index b059f6bbefb4a..93932d86582fa 100644 --- a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs +++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -3,7 +3,9 @@ //@ add-minicore //@ revisions: hwasan khwasan //@[hwasan] compile-flags: --target aarch64-unknown-linux-gnu -Zsanitizer=hwaddress +//@[hwasan] needs-llvm-components: aarch64 //@[khwasan] compile-flags: --target aarch64-unknown-none -Zsanitizer=kernel-hwaddress +//@[khwasan] needs-llvm-components: aarch64 //@ compile-flags: -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/kasan-recover.rs b/tests/codegen-llvm/sanitizer/kasan-recover.rs index 8f0e6eb3a605d..f0f9180ae595e 100644 --- a/tests/codegen-llvm/sanitizer/kasan-recover.rs +++ b/tests/codegen-llvm/sanitizer/kasan-recover.rs @@ -4,11 +4,9 @@ //@ add-minicore //@ revisions: KASAN KASAN-RECOVER //@ compile-flags: -Copt-level=0 -//@[KASAN] compile-flags: -Zsanitizer=kernel-address --target x86_64-unknown-none -//@[KASAN] needs-llvm-components: x86 -//@[KASAN-RECOVER] compile-flags: -Zsanitizer=kernel-address -//@[KASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-address --target x86_64-unknown-none -//@[KASAN-RECOVER] needs-llvm-components: x86 +//@ needs-llvm-components: x86 +//@ compile-flags: -Zsanitizer=kernel-address --target x86_64-unknown-none +//@[KASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-address #![feature(no_core, sanitize, lang_items)] #![no_core] diff --git a/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs b/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs index 01b129cb69207..26dc7983d7314 100644 --- a/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs +++ b/tests/codegen-llvm/sanitizer/khwasan-lifetime-markers.rs @@ -2,9 +2,8 @@ //@ add-minicore //@ compile-flags: -Zsanitizer=kernel-hwaddress -Copt-level=0 -//@ revisions: aarch64 -//@[aarch64] compile-flags: --target aarch64-unknown-none -//@[aarch64] needs-llvm-components: aarch64 +//@ compile-flags: --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 #![crate_type = "rlib"] #![feature(no_core, lang_items)] diff --git a/tests/codegen-llvm/sanitizer/khwasan-recover.rs b/tests/codegen-llvm/sanitizer/khwasan-recover.rs index 957b867a61ad9..452a0f579fc72 100644 --- a/tests/codegen-llvm/sanitizer/khwasan-recover.rs +++ b/tests/codegen-llvm/sanitizer/khwasan-recover.rs @@ -2,15 +2,12 @@ // with -Zsanitizer-recover=kernel-hwaddress. // //@ add-minicore -//@[KHWASAN] needs-llvm-components: aarch64 -//@[KHWASAN-RECOVER] needs-llvm-components: aarch64 +//@ needs-llvm-components: aarch64 //@ revisions: KHWASAN KHWASAN-RECOVER //@ no-prefer-dynamic //@ compile-flags: -Copt-level=0 -//@[KHWASAN] compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none -//@[KHWASAN-RECOVER] compile-flags: -Zsanitizer=kernel-hwaddress -//@[KHWASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-hwaddress -//@[KHWASAN-RECOVER] compile-flags: --target aarch64-unknown-none +//@ compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none +//@[KHWASAN-RECOVER] compile-flags: -Zsanitizer-recover=kernel-hwaddress #![feature(no_core, sanitize, lang_items)] #![no_core] diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs index c0e23f5f596ba..313f48031e4ab 100644 --- a/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs +++ b/tests/codegen-llvm/sanitizer/sanitize-off-hwasan-khwasan.rs @@ -2,12 +2,9 @@ // the kernel hardware-assisted address sanitizer. // //@ add-minicore -//@ compile-flags: -Zsanitizer=kernel-hwaddress -Ctarget-feature=-crt-static -Copt-level=0 -//@ revisions: aarch64 aarch64v8r -//@[aarch64] compile-flags: --target aarch64-unknown-none -//@[aarch64] needs-llvm-components: aarch64 -//@[aarch64v8r] compile-flags: --target aarch64v8r-unknown-none -//@[aarch64v8r] needs-llvm-components: aarch64 +//@ compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none +//@ compile-flags: -Ctarget-feature=-crt-static -Copt-level=0 +//@ needs-llvm-components: aarch64 #![crate_type = "rlib"] #![feature(no_core, sanitize, lang_items)] diff --git a/tests/ui/sanitizer/cfg-khwasan.rs b/tests/ui/sanitizer/cfg-khwasan.rs index c2b0505a34c26..27a2f6030d0ba 100644 --- a/tests/ui/sanitizer/cfg-khwasan.rs +++ b/tests/ui/sanitizer/cfg-khwasan.rs @@ -3,10 +3,8 @@ //@ add-minicore //@ check-pass -//@ compile-flags: -Zsanitizer=kernel-hwaddress -//@ revisions: aarch64 -//@[aarch64] compile-flags: --target aarch64-unknown-none -//@[aarch64] needs-llvm-components: aarch64 +//@ compile-flags: -Zsanitizer=kernel-hwaddress --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 //@ ignore-backends: gcc #![crate_type = "rlib"] From adacd90f29c381c2e3876f356dda7575a96ffef5 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 19 Mar 2026 14:37:13 +0000 Subject: [PATCH 10/40] move many `ui/macros` tests from `run-` to `check-pass` --- tests/ui/macros/issue-2804.rs | 2 +- tests/ui/macros/issue-33185.rs | 2 +- tests/ui/macros/issue-40469.rs | 2 +- tests/ui/macros/issue-40770.rs | 2 +- tests/ui/macros/macro-attribute-expansion.rs | 2 +- tests/ui/macros/macro-attributes.rs | 2 +- tests/ui/macros/macro-delimiter-significance.rs | 2 +- tests/ui/macros/macro-doc-comments.rs | 2 +- tests/ui/macros/macro-doc-escapes.rs | 2 +- tests/ui/macros/macro-follow-rpass.rs | 2 +- tests/ui/macros/macro-followed-by-seq.rs | 2 +- tests/ui/macros/macro-in-fn.rs | 2 +- .../macros/macro-invocation-in-count-expr-fixed-array-type.rs | 2 +- tests/ui/macros/macro-multiple-items.rs | 2 +- tests/ui/macros/macro-named-default.rs | 2 +- tests/ui/macros/macro-nt-list.rs | 2 +- tests/ui/macros/macro-pat-follow-2018.rs | 2 +- tests/ui/macros/macro-pub-matcher.rs | 2 +- tests/ui/macros/macro-seq-followed-by-seq.rs | 2 +- tests/ui/macros/macro-use-all-and-none.rs | 2 +- tests/ui/macros/macro-use-all.rs | 2 +- tests/ui/macros/macro-use-both.rs | 2 +- tests/ui/macros/macro-use-one.rs | 2 +- tests/ui/macros/parse-complex-macro-invoc-op.rs | 2 +- tests/ui/macros/pub-item-inside-macro.rs | 2 +- tests/ui/macros/pub-method-inside-macro.rs | 2 +- tests/ui/macros/semi-after-macro-ty.rs | 2 +- tests/ui/macros/two-macro-use.rs | 2 +- tests/ui/macros/type-macros-simple.rs | 2 +- tests/ui/macros/use-macro-self.rs | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/ui/macros/issue-2804.rs b/tests/ui/macros/issue-2804.rs index 0b6f9487ece2a..9f45df4a3178a 100644 --- a/tests/ui/macros/issue-2804.rs +++ b/tests/ui/macros/issue-2804.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(non_camel_case_types)] #![allow(dead_code)] diff --git a/tests/ui/macros/issue-33185.rs b/tests/ui/macros/issue-33185.rs index 8d7e305f1e359..5771b40809dc3 100644 --- a/tests/ui/macros/issue-33185.rs +++ b/tests/ui/macros/issue-33185.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #[macro_export] diff --git a/tests/ui/macros/issue-40469.rs b/tests/ui/macros/issue-40469.rs index faa4c6581af7f..4529e44e267de 100644 --- a/tests/ui/macros/issue-40469.rs +++ b/tests/ui/macros/issue-40469.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] diff --git a/tests/ui/macros/issue-40770.rs b/tests/ui/macros/issue-40770.rs index d90294acd2510..028bd48b1be74 100644 --- a/tests/ui/macros/issue-40770.rs +++ b/tests/ui/macros/issue-40770.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_macros)] macro_rules! m { ($e:expr) => { diff --git a/tests/ui/macros/macro-attribute-expansion.rs b/tests/ui/macros/macro-attribute-expansion.rs index be682b38865d3..255400e2679e0 100644 --- a/tests/ui/macros/macro-attribute-expansion.rs +++ b/tests/ui/macros/macro-attribute-expansion.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! descriptions { ($name:ident is $desc:expr) => { // Check that we will correctly expand attributes diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 976d2cbcccdbb..a25ed2ba7ef6a 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! compiles_fine { (#[$at:meta]) => { diff --git a/tests/ui/macros/macro-delimiter-significance.rs b/tests/ui/macros/macro-delimiter-significance.rs index 8b532e19196b3..1947ecf9b22ea 100644 --- a/tests/ui/macros/macro-delimiter-significance.rs +++ b/tests/ui/macros/macro-delimiter-significance.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass fn main() { vec![1_usize, 2, 3].len(); } diff --git a/tests/ui/macros/macro-doc-comments.rs b/tests/ui/macros/macro-doc-comments.rs index 47740e26fb6fa..4622c3710e93e 100644 --- a/tests/ui/macros/macro-doc-comments.rs +++ b/tests/ui/macros/macro-doc-comments.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(non_snake_case)] macro_rules! doc { diff --git a/tests/ui/macros/macro-doc-escapes.rs b/tests/ui/macros/macro-doc-escapes.rs index 81c8d3383b579..77d9a5c048fa1 100644 --- a/tests/ui/macros/macro-doc-escapes.rs +++ b/tests/ui/macros/macro-doc-escapes.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // When expanding a macro, documentation attributes (including documentation comments) must be // passed "as is" without being parsed. Otherwise, some text will be incorrectly interpreted as // escape sequences, leading to an ICE. diff --git a/tests/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs index 8551b1887708e..dfaacefc528ae 100644 --- a/tests/ui/macros/macro-follow-rpass.rs +++ b/tests/ui/macros/macro-follow-rpass.rs @@ -1,5 +1,5 @@ //@ edition:2015..2021 -//@ run-pass +//@ check-pass #![allow(unused_macros)] // Check the macro follow sets (see corresponding cfail test). diff --git a/tests/ui/macros/macro-followed-by-seq.rs b/tests/ui/macros/macro-followed-by-seq.rs index f4756d42088ad..3643836fa031f 100644 --- a/tests/ui/macros/macro-followed-by-seq.rs +++ b/tests/ui/macros/macro-followed-by-seq.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_macros)] // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. diff --git a/tests/ui/macros/macro-in-fn.rs b/tests/ui/macros/macro-in-fn.rs index 2ffa6b2e4572e..48085b8b221ba 100644 --- a/tests/ui/macros/macro-in-fn.rs +++ b/tests/ui/macros/macro-in-fn.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![feature(decl_macro)] pub fn moo() { diff --git a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs index e80c712b03dc5..ed8974c23e714 100644 --- a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs +++ b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! four { () => (4) diff --git a/tests/ui/macros/macro-multiple-items.rs b/tests/ui/macros/macro-multiple-items.rs index c746d1bc51881..46b561af4467e 100644 --- a/tests/ui/macros/macro-multiple-items.rs +++ b/tests/ui/macros/macro-multiple-items.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! make_foo { () => ( struct Foo; diff --git a/tests/ui/macros/macro-named-default.rs b/tests/ui/macros/macro-named-default.rs index bca0e005083d2..c7eac831cffb8 100644 --- a/tests/ui/macros/macro-named-default.rs +++ b/tests/ui/macros/macro-named-default.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! default { ($($x:tt)*) => { $($x)* } } diff --git a/tests/ui/macros/macro-nt-list.rs b/tests/ui/macros/macro-nt-list.rs index b7b260c5398cb..56ea917c3be99 100644 --- a/tests/ui/macros/macro-nt-list.rs +++ b/tests/ui/macros/macro-nt-list.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! list { ( ($($id:ident),*) ) => (()); diff --git a/tests/ui/macros/macro-pat-follow-2018.rs b/tests/ui/macros/macro-pat-follow-2018.rs index 6dcb841fec15f..b2a556fce6f9e 100644 --- a/tests/ui/macros/macro-pat-follow-2018.rs +++ b/tests/ui/macros/macro-pat-follow-2018.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ edition:2018 macro_rules! pat_bar { diff --git a/tests/ui/macros/macro-pub-matcher.rs b/tests/ui/macros/macro-pub-matcher.rs index e0b03dbbeb1b3..20cacab390d5a 100644 --- a/tests/ui/macros/macro-pub-matcher.rs +++ b/tests/ui/macros/macro-pub-matcher.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code, unused_imports, unused_macro_rules)] /** diff --git a/tests/ui/macros/macro-seq-followed-by-seq.rs b/tests/ui/macros/macro-seq-followed-by-seq.rs index 3661744284eef..cf5a1c1170313 100644 --- a/tests/ui/macros/macro-seq-followed-by-seq.rs +++ b/tests/ui/macros/macro-seq-followed-by-seq.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Test of allowing two sequences repetitions in a row, // functionality added as byproduct of RFC amendment #1384 // https://github.com/rust-lang/rfcs/pull/1384 diff --git a/tests/ui/macros/macro-use-all-and-none.rs b/tests/ui/macros/macro-use-all-and-none.rs index f1acff4840382..53d450ed8d581 100644 --- a/tests/ui/macros/macro-use-all-and-none.rs +++ b/tests/ui/macros/macro-use-all-and-none.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros-rpass.rs #![warn(unused_attributes)] diff --git a/tests/ui/macros/macro-use-all.rs b/tests/ui/macros/macro-use-all.rs index a7fd3dfa5ce60..06b96da7f8b17 100644 --- a/tests/ui/macros/macro-use-all.rs +++ b/tests/ui/macros/macro-use-all.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use] diff --git a/tests/ui/macros/macro-use-both.rs b/tests/ui/macros/macro-use-both.rs index e49f346c8e3e8..c41797513f6a3 100644 --- a/tests/ui/macros/macro-use-both.rs +++ b/tests/ui/macros/macro-use-both.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_one, macro_two)] diff --git a/tests/ui/macros/macro-use-one.rs b/tests/ui/macros/macro-use-one.rs index 2b048651ccccf..93f7c212e0012 100644 --- a/tests/ui/macros/macro-use-one.rs +++ b/tests/ui/macros/macro-use-one.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_two)] diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs index 2c384bdb42efe..bbb01facc6242 100644 --- a/tests/ui/macros/parse-complex-macro-invoc-op.rs +++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_must_use)] #![allow(dead_code)] #![allow(unused_assignments)] diff --git a/tests/ui/macros/pub-item-inside-macro.rs b/tests/ui/macros/pub-item-inside-macro.rs index c37945a2d672a..679987ac1f4a3 100644 --- a/tests/ui/macros/pub-item-inside-macro.rs +++ b/tests/ui/macros/pub-item-inside-macro.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Issue #14660 diff --git a/tests/ui/macros/pub-method-inside-macro.rs b/tests/ui/macros/pub-method-inside-macro.rs index dd4e6fda8be9b..23d8c454d6973 100644 --- a/tests/ui/macros/pub-method-inside-macro.rs +++ b/tests/ui/macros/pub-method-inside-macro.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass // Issue #17436 diff --git a/tests/ui/macros/semi-after-macro-ty.rs b/tests/ui/macros/semi-after-macro-ty.rs index 60afc3b445061..ff026c53b1d70 100644 --- a/tests/ui/macros/semi-after-macro-ty.rs +++ b/tests/ui/macros/semi-after-macro-ty.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass macro_rules! foo { ($t:ty; $p:path;) => {} } diff --git a/tests/ui/macros/two-macro-use.rs b/tests/ui/macros/two-macro-use.rs index 8bb3c9da30512..733853f8d2347 100644 --- a/tests/ui/macros/two-macro-use.rs +++ b/tests/ui/macros/two-macro-use.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass //@ aux-build:two_macros.rs #[macro_use(macro_one)] diff --git a/tests/ui/macros/type-macros-simple.rs b/tests/ui/macros/type-macros-simple.rs index d189b881f7dda..800a796491be9 100644 --- a/tests/ui/macros/type-macros-simple.rs +++ b/tests/ui/macros/type-macros-simple.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(unused_variables)] #![allow(non_local_definitions)] diff --git a/tests/ui/macros/use-macro-self.rs b/tests/ui/macros/use-macro-self.rs index 1d15b8386af96..cf5a410c6edfc 100644 --- a/tests/ui/macros/use-macro-self.rs +++ b/tests/ui/macros/use-macro-self.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_imports)] //@ aux-build:use-macro-self.rs From 9ce6863063006951d678d0ec8a9e037731478609 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 19 Mar 2026 14:40:33 +0000 Subject: [PATCH 11/40] merge `die-macro` tests into `panic-macro-basic.rs` --- tests/ui/macros/die-macro-2.rs | 7 ------- tests/ui/macros/die-macro-pure.rs | 11 ----------- tests/ui/macros/die-macro.rs | 16 ---------------- .../{die-macro-expr.rs => panic-macro-basic.rs} | 9 ++++++++- 4 files changed, 8 insertions(+), 35 deletions(-) delete mode 100644 tests/ui/macros/die-macro-2.rs delete mode 100644 tests/ui/macros/die-macro-pure.rs delete mode 100644 tests/ui/macros/die-macro.rs rename tests/ui/macros/{die-macro-expr.rs => panic-macro-basic.rs} (53%) diff --git a/tests/ui/macros/die-macro-2.rs b/tests/ui/macros/die-macro-2.rs deleted file mode 100644 index d802f189ce1af..0000000000000 --- a/tests/ui/macros/die-macro-2.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:test -//@ needs-subprocess - -fn main() { - panic!("test"); -} diff --git a/tests/ui/macros/die-macro-pure.rs b/tests/ui/macros/die-macro-pure.rs deleted file mode 100644 index d84787705a1aa..0000000000000 --- a/tests/ui/macros/die-macro-pure.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-fail -//@ error-pattern:test -//@ needs-subprocess - -fn f() { - panic!("test"); -} - -fn main() { - f(); -} diff --git a/tests/ui/macros/die-macro.rs b/tests/ui/macros/die-macro.rs deleted file mode 100644 index b717eed3fb438..0000000000000 --- a/tests/ui/macros/die-macro.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -// Just testing that panic!() type checks in statement or expr - - -#![allow(unreachable_code)] - -fn f() { - panic!(); - - let _x: isize = panic!(); -} - -pub fn main() { - -} diff --git a/tests/ui/macros/die-macro-expr.rs b/tests/ui/macros/panic-macro-basic.rs similarity index 53% rename from tests/ui/macros/die-macro-expr.rs rename to tests/ui/macros/panic-macro-basic.rs index f4fefb0ca37dd..96ed4265ef6eb 100644 --- a/tests/ui/macros/die-macro-expr.rs +++ b/tests/ui/macros/panic-macro-basic.rs @@ -1,7 +1,14 @@ //@ run-fail //@ error-pattern:test //@ needs-subprocess +// Just testing that panic!() type checks in statement or expr -fn main() { +fn f() { let __isize: isize = panic!("test"); + + panic!(); +} + +fn main() { + f(); } From ad79aa764b28a1d8b57a431326f00a7061cc760f Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 20 Mar 2026 09:04:03 +0000 Subject: [PATCH 12/40] merge many repetitive `classes-*` tests --- tests/ui/structs-enums/auxiliary/cci_class.rs | 14 --- .../ui/structs-enums/auxiliary/cci_class_2.rs | 19 --- .../ui/structs-enums/auxiliary/cci_class_3.rs | 19 --- .../ui/structs-enums/auxiliary/cci_class_4.rs | 21 ++++ .../structs-enums/auxiliary/cci_class_cast.rs | 50 -------- .../auxiliary/cci_class_trait.rs | 5 - .../class-cast-to-trait-cross-crate-2.rs | 17 --- .../class-cast-to-trait-multiple-types.rs | 94 --------------- tests/ui/structs-enums/class-cast-to-trait.rs | 60 ---------- tests/ui/structs-enums/class-exports.rs | 31 ----- .../class-implement-trait-cross-crate.rs | 59 ---------- .../structs-enums/class-implement-traits.rs | 64 ---------- .../structs-enums/class-method-cross-crate.rs | 13 --- .../class-methods-cross-crate.rs | 14 --- tests/ui/structs-enums/class-methods.rs | 30 ----- tests/ui/structs-enums/class-separate-impl.rs | 63 ---------- tests/ui/structs-enums/class-str-field.rs | 20 ---- tests/ui/structs-enums/classes-cross-crate.rs | 109 +++++++++++++++++- .../classes-simple-cross-crate.rs | 12 -- .../ui/structs-enums/classes-simple-method.rs | 28 ----- tests/ui/structs-enums/classes-simple.rs | 23 ---- tests/ui/structs-enums/classes.rs | 51 -------- 22 files changed, 128 insertions(+), 688 deletions(-) delete mode 100644 tests/ui/structs-enums/auxiliary/cci_class.rs delete mode 100644 tests/ui/structs-enums/auxiliary/cci_class_2.rs delete mode 100644 tests/ui/structs-enums/auxiliary/cci_class_3.rs delete mode 100644 tests/ui/structs-enums/auxiliary/cci_class_cast.rs delete mode 100644 tests/ui/structs-enums/auxiliary/cci_class_trait.rs delete mode 100644 tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs delete mode 100644 tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs delete mode 100644 tests/ui/structs-enums/class-cast-to-trait.rs delete mode 100644 tests/ui/structs-enums/class-exports.rs delete mode 100644 tests/ui/structs-enums/class-implement-trait-cross-crate.rs delete mode 100644 tests/ui/structs-enums/class-implement-traits.rs delete mode 100644 tests/ui/structs-enums/class-method-cross-crate.rs delete mode 100644 tests/ui/structs-enums/class-methods-cross-crate.rs delete mode 100644 tests/ui/structs-enums/class-methods.rs delete mode 100644 tests/ui/structs-enums/class-separate-impl.rs delete mode 100644 tests/ui/structs-enums/class-str-field.rs delete mode 100644 tests/ui/structs-enums/classes-simple-cross-crate.rs delete mode 100644 tests/ui/structs-enums/classes-simple-method.rs delete mode 100644 tests/ui/structs-enums/classes-simple.rs delete mode 100644 tests/ui/structs-enums/classes.rs diff --git a/tests/ui/structs-enums/auxiliary/cci_class.rs b/tests/ui/structs-enums/auxiliary/cci_class.rs deleted file mode 100644 index de2945d746045..0000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_2.rs b/tests/ui/structs-enums/auxiliary/cci_class_2.rs deleted file mode 100644 index c3de3150e6978..0000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - - } - - impl cat { - pub fn speak(&self) {} - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_3.rs b/tests/ui/structs-enums/auxiliary/cci_class_3.rs deleted file mode 100644 index fb7fad0b5a2e7..0000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_3.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod kitties { - pub struct cat { - meows : usize, - - pub how_hungry : isize, - } - - impl cat { - pub fn speak(&mut self) { self.meows += 1; } - pub fn meow_count(&mut self) -> usize { self.meows } - } - - pub fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_4.rs b/tests/ui/structs-enums/auxiliary/cci_class_4.rs index 85aa3bc8c0df9..f8c243c9f3955 100644 --- a/tests/ui/structs-enums/auxiliary/cci_class_4.rs +++ b/tests/ui/structs-enums/auxiliary/cci_class_4.rs @@ -1,4 +1,6 @@ pub mod kitties { + use std::fmt; + #[derive(Clone)] pub struct cat { meows : usize, @@ -19,6 +21,8 @@ pub mod kitties { return false; } } + + pub fn noop(&self) {} } impl cat { @@ -29,6 +33,9 @@ pub mod kitties { self.how_hungry += 1; } } + pub fn meow_count(&self) -> usize { + self.meows + } } pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { @@ -38,4 +45,18 @@ pub mod kitties { name: in_name } } + pub fn cat_unnamed(in_x : usize, in_y : isize) -> cat { + cat { + meows: in_x, + how_hungry: in_y, + name: String::new(), + } + } + + impl fmt::Display for cat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } + } + } diff --git a/tests/ui/structs-enums/auxiliary/cci_class_cast.rs b/tests/ui/structs-enums/auxiliary/cci_class_cast.rs deleted file mode 100644 index dfc3c56ddee70..0000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_cast.rs +++ /dev/null @@ -1,50 +0,0 @@ -pub mod kitty { - use std::fmt; - - pub struct cat { - meows : usize, - pub how_hungry : isize, - pub name : String, - } - - impl fmt::Display for cat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } - } - - impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } - - } - - impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } - } - - pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } - } -} diff --git a/tests/ui/structs-enums/auxiliary/cci_class_trait.rs b/tests/ui/structs-enums/auxiliary/cci_class_trait.rs deleted file mode 100644 index 2d02b591c5559..0000000000000 --- a/tests/ui/structs-enums/auxiliary/cci_class_trait.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod animals { - pub trait noisy { - fn speak(&mut self); - } -} diff --git a/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs b/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs deleted file mode 100644 index d4caa19135e8a..0000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_cast.rs - -extern crate cci_class_cast; - -use cci_class_cast::kitty::cat; - -fn print_out(thing: Box, expected: String) { - let actual = (*thing).to_string(); - println!("{}", actual); - assert_eq!(actual.to_string(), expected); -} - -pub fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - print_out(nyan, "nyan".to_string()); -} diff --git a/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs b/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs deleted file mode 100644 index 658e9d2117dc3..0000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait-multiple-types.rs +++ /dev/null @@ -1,94 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -trait noisy { - fn speak(&mut self) -> isize; -} - -struct dog { - barks: usize, - - volume: isize, -} - -impl dog { - fn bark(&mut self) -> isize { - println!("Woof {} {}", self.barks, self.volume); - self.barks += 1_usize; - if self.barks % 3_usize == 0_usize { - self.volume += 1; - } - if self.barks % 10_usize == 0_usize { - self.volume -= 2; - } - println!("Grrr {} {}", self.barks, self.volume); - self.volume - } -} - -impl noisy for dog { - fn speak(&mut self) -> isize { - self.bark() - } -} - -fn dog() -> dog { - dog { - volume: 0, - barks: 0_usize - } -} - -#[derive(Clone)] -struct cat { - meows: usize, - - how_hungry: isize, - name: String, -} - -impl noisy for cat { - fn speak(&mut self) -> isize { - self.meow() as isize - } -} - -impl cat { - pub fn meow_count(&self) -> usize { - self.meows - } -} - -impl cat { - fn meow(&mut self) -> usize { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - self.meows - } -} - -fn cat(in_x: usize, in_y: isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -fn annoy_neighbors(critter: &mut dyn noisy) { - for _i in 0_usize..10 { critter.speak(); } -} - -pub fn main() { - let mut nyan: cat = cat(0_usize, 2, "nyan".to_string()); - let mut whitefang: dog = dog(); - annoy_neighbors(&mut nyan); - annoy_neighbors(&mut whitefang); - assert_eq!(nyan.meow_count(), 10_usize); - assert_eq!(whitefang.volume, 1); -} diff --git a/tests/ui/structs-enums/class-cast-to-trait.rs b/tests/ui/structs-enums/class-cast-to-trait.rs deleted file mode 100644 index bbbde34ec096c..0000000000000 --- a/tests/ui/structs-enums/class-cast-to-trait.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(unused_mut)] -#![allow(non_camel_case_types)] - -//@ ignore-freebsd FIXME fails on BSD - - -trait noisy { - fn speak(&mut self); -} - -struct cat { - meows: usize, - how_hungry: isize, - name: String, -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -pub fn main() { - let mut nyan = cat(0, 2, "nyan".to_string()); - let mut nyan: &mut dyn noisy = &mut nyan; - nyan.speak(); -} diff --git a/tests/ui/structs-enums/class-exports.rs b/tests/ui/structs-enums/class-exports.rs deleted file mode 100644 index 53d0e3db6f5f4..0000000000000 --- a/tests/ui/structs-enums/class-exports.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -/* Test that exporting a class also exports its - public fields and methods */ - -use kitty::cat; - -mod kitty { - pub struct cat { - meows: usize, - name: String, - } - - impl cat { - pub fn get_name(&self) -> String { self.name.clone() } - } - - pub fn cat(in_name: String) -> cat { - cat { - name: in_name, - meows: 0 - } - } -} - -pub fn main() { - assert_eq!(cat("Spreckles".to_string()).get_name(), - "Spreckles".to_string()); -} diff --git a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs b/tests/ui/structs-enums/class-implement-trait-cross-crate.rs deleted file mode 100644 index 781ac6ad10d2c..0000000000000 --- a/tests/ui/structs-enums/class-implement-trait-cross-crate.rs +++ /dev/null @@ -1,59 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -//@ aux-build:cci_class_trait.rs -extern crate cci_class_trait; -use cci_class_trait::animals::noisy; - -struct cat { - meows: usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; - assert!(nyan.eat()); -} diff --git a/tests/ui/structs-enums/class-implement-traits.rs b/tests/ui/structs-enums/class-implement-traits.rs deleted file mode 100644 index 3a514ff9d7581..0000000000000 --- a/tests/ui/structs-enums/class-implement-traits.rs +++ /dev/null @@ -1,64 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -trait noisy { - fn speak(&mut self); -} - -#[derive(Clone)] -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -impl cat { - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } - } -} - -impl noisy for cat { - fn speak(&mut self) { self.meow(); } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name.clone() - } -} - - -fn make_speak(mut c: C) { - c.speak(); -} - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { - make_speak(nyan.clone()); - } -} diff --git a/tests/ui/structs-enums/class-method-cross-crate.rs b/tests/ui/structs-enums/class-method-cross-crate.rs deleted file mode 100644 index f73999a24501f..0000000000000 --- a/tests/ui/structs-enums/class-method-cross-crate.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_2.rs - -extern crate cci_class_2; -use cci_class_2::kitties::cat; - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); -} diff --git a/tests/ui/structs-enums/class-methods-cross-crate.rs b/tests/ui/structs-enums/class-methods-cross-crate.rs deleted file mode 100644 index b2c48248a6712..0000000000000 --- a/tests/ui/structs-enums/class-methods-cross-crate.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class_3.rs - -extern crate cci_class_3; -use cci_class_3::kitties::cat; - -pub fn main() { - let mut nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); - assert_eq!(nyan.meow_count(), 53); -} diff --git a/tests/ui/structs-enums/class-methods.rs b/tests/ui/structs-enums/class-methods.rs deleted file mode 100644 index b0dbbbec5224f..0000000000000 --- a/tests/ui/structs-enums/class-methods.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - - -struct cat { - meows : usize, - - how_hungry : isize, -} - -impl cat { - pub fn speak(&mut self) { self.meows += 1; } - pub fn meow_count(&mut self) -> usize { self.meows } -} - -fn cat(in_x: usize, in_y: isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let mut nyan: cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); - assert_eq!(nyan.meow_count(), 53); -} diff --git a/tests/ui/structs-enums/class-separate-impl.rs b/tests/ui/structs-enums/class-separate-impl.rs deleted file mode 100644 index 2768e284c1736..0000000000000 --- a/tests/ui/structs-enums/class-separate-impl.rs +++ /dev/null @@ -1,63 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -use std::fmt; - -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - -impl fmt::Display for cat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } -} - -fn print_out(thing: Box, expected: String) { - let actual = (*thing).to_string(); - println!("{}", actual); - assert_eq!(actual.to_string(), expected); -} - -pub fn main() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - print_out(nyan, "nyan".to_string()); -} diff --git a/tests/ui/structs-enums/class-str-field.rs b/tests/ui/structs-enums/class-str-field.rs deleted file mode 100644 index 24f648afc90b1..0000000000000 --- a/tests/ui/structs-enums/class-str-field.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - - -struct cat { - - name : String, - -} - -fn cat(in_name: String) -> cat { - cat { - name: in_name - } -} - -pub fn main() { - let _nyan = cat("nyan".to_string()); -} diff --git a/tests/ui/structs-enums/classes-cross-crate.rs b/tests/ui/structs-enums/classes-cross-crate.rs index 6fb5f2e3cc9d7..d859cbdc76dae 100644 --- a/tests/ui/structs-enums/classes-cross-crate.rs +++ b/tests/ui/structs-enums/classes-cross-crate.rs @@ -1,13 +1,118 @@ //@ run-pass //@ aux-build:cci_class_4.rs +#![allow(non_camel_case_types)] extern crate cci_class_4; -use cci_class_4::kitties::cat; +use cci_class_4::kitties::{cat, cat_unnamed}; -pub fn main() { +fn simple_cross_crate() { + let nyan : cat = cat_unnamed(52, 99); + let kitty = cat_unnamed(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.noop(); +} + +fn cross_crate() { let mut nyan = cat(0_usize, 2, "nyan".to_string()); nyan.eat(); assert!(!nyan.eat()); for _ in 1_usize..10_usize { nyan.speak(); }; assert!(nyan.eat()); } + + +fn print_out(thing: Box, expected: String) { + let actual = (*thing).to_string(); + println!("{}", actual); + assert_eq!(actual.to_string(), expected); +} + +fn separate_impl() { + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; + print_out(nyan, "nyan".to_string()); +} + +trait noisy { + fn speak(&mut self) -> isize; +} + +impl noisy for cat { + fn speak(&mut self) -> isize { self.meow(); 0 } +} + +fn make_speak(mut c: C) { + c.speak(); +} + +fn implement_traits() { + let mut nyan = cat(0_usize, 2, "nyan".to_string()); + nyan.eat(); + assert!(!nyan.eat()); + for _ in 1_usize..10_usize { + make_speak(nyan.clone()); + } +} + + +struct dog { + barks: usize, + + volume: isize, +} + +impl dog { + fn bark(&mut self) -> isize { + println!("Woof {} {}", self.barks, self.volume); + self.barks += 1_usize; + if self.barks % 3_usize == 0_usize { + self.volume += 1; + } + if self.barks % 10_usize == 0_usize { + self.volume -= 2; + } + println!("Grrr {} {}", self.barks, self.volume); + self.volume + } +} + +impl noisy for dog { + fn speak(&mut self) -> isize { + self.bark() + } +} + +fn dog() -> dog { + dog { + volume: 0, + barks: 0_usize + } +} + +fn annoy_neighbors(critter: &mut dyn noisy) { + for _i in 0_usize..10 { critter.speak(); } +} + +fn multiple_types() { + let mut nyan: cat = cat(0_usize, 2, "nyan".to_string()); + let mut whitefang: dog = dog(); + annoy_neighbors(&mut nyan); + annoy_neighbors(&mut whitefang); + assert_eq!(nyan.meow_count(), 10_usize); + assert_eq!(whitefang.volume, 1); +} + +fn cast_to_trait() { + let mut nyan = cat(0, 2, "nyan".to_string()); + let nyan: &mut dyn noisy = &mut nyan; + nyan.speak(); +} + +fn main() { + simple_cross_crate(); + cross_crate(); + separate_impl(); + implement_traits(); + multiple_types(); + cast_to_trait(); +} diff --git a/tests/ui/structs-enums/classes-simple-cross-crate.rs b/tests/ui/structs-enums/classes-simple-cross-crate.rs deleted file mode 100644 index 1548f768b6f3c..0000000000000 --- a/tests/ui/structs-enums/classes-simple-cross-crate.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -//@ aux-build:cci_class.rs - -extern crate cci_class; -use cci_class::kitties::cat; - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); -} diff --git a/tests/ui/structs-enums/classes-simple-method.rs b/tests/ui/structs-enums/classes-simple-method.rs deleted file mode 100644 index 562fd5909815c..0000000000000 --- a/tests/ui/structs-enums/classes-simple-method.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, -} - -impl cat { - pub fn speak(&mut self) {} -} - -fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let mut nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.speak(); -} diff --git a/tests/ui/structs-enums/classes-simple.rs b/tests/ui/structs-enums/classes-simple.rs deleted file mode 100644 index d870a3101f1ae..0000000000000 --- a/tests/ui/structs-enums/classes-simple.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, -} - -fn cat(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y - } -} - -pub fn main() { - let nyan : cat = cat(52, 99); - let kitty = cat(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); -} diff --git a/tests/ui/structs-enums/classes.rs b/tests/ui/structs-enums/classes.rs deleted file mode 100644 index 05976f6a759af..0000000000000 --- a/tests/ui/structs-enums/classes.rs +++ /dev/null @@ -1,51 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -struct cat { - meows : usize, - - how_hungry : isize, - name : String, -} - -impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } - } -} - -impl cat { - fn meow(&mut self) { - println!("Meow"); - self.meows += 1_usize; - if self.meows % 5_usize == 0_usize { - self.how_hungry += 1; - } - } -} - -fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name - } -} - -pub fn main() { - let mut nyan = cat(0_usize, 2, "nyan".to_string()); - nyan.eat(); - assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; - assert!(nyan.eat()); -} From 0941e187ef276a707025f01ce513cf594611e834 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 20 Mar 2026 09:17:48 +0000 Subject: [PATCH 13/40] reformat merged files --- .../ui/structs-enums/auxiliary/cci_class_4.rs | 90 +++++++++---------- tests/ui/structs-enums/classes-cross-crate.rs | 89 +++++++++--------- 2 files changed, 86 insertions(+), 93 deletions(-) diff --git a/tests/ui/structs-enums/auxiliary/cci_class_4.rs b/tests/ui/structs-enums/auxiliary/cci_class_4.rs index f8c243c9f3955..fff7b7809571a 100644 --- a/tests/ui/structs-enums/auxiliary/cci_class_4.rs +++ b/tests/ui/structs-enums/auxiliary/cci_class_4.rs @@ -1,62 +1,54 @@ -pub mod kitties { - use std::fmt; - #[derive(Clone)] - pub struct cat { - meows : usize, - - pub how_hungry : isize, - pub name : String, - } +use std::fmt; - impl cat { - pub fn speak(&mut self) { self.meow(); } - - pub fn eat(&mut self) -> bool { - if self.how_hungry > 0 { - println!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } else { - println!("Not hungry!"); - return false; - } - } +#[derive(Clone)] +pub struct Cat { + meows: usize, + + pub how_hungry: isize, + pub name: String, +} - pub fn noop(&self) {} +impl Cat { + pub fn speak(&mut self) { + self.meow(); } - impl cat { - pub fn meow(&mut self) { - println!("Meow"); - self.meows += 1; - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } - pub fn meow_count(&self) -> usize { - self.meows + pub fn eat(&mut self) -> bool { + if self.how_hungry > 0 { + println!("OM NOM NOM"); + self.how_hungry -= 2; + return true; + } else { + println!("Not hungry!"); + return false; } } - pub fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: in_name + pub fn noop(&self) {} +} + +impl Cat { + pub fn meow(&mut self) { + println!("Meow"); + self.meows += 1; + if self.meows % 5 == 0 { + self.how_hungry += 1; } } - pub fn cat_unnamed(in_x : usize, in_y : isize) -> cat { - cat { - meows: in_x, - how_hungry: in_y, - name: String::new(), - } + pub fn meow_count(&self) -> usize { + self.meows } +} - impl fmt::Display for cat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.name) - } - } +pub fn cat(in_x: usize, in_y: isize, in_name: String) -> Cat { + Cat { meows: in_x, how_hungry: in_y, name: in_name } +} +pub fn cat_unnamed(in_x: usize, in_y: isize) -> Cat { + Cat { meows: in_x, how_hungry: in_y, name: String::new() } +} +impl fmt::Display for Cat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } } diff --git a/tests/ui/structs-enums/classes-cross-crate.rs b/tests/ui/structs-enums/classes-cross-crate.rs index d859cbdc76dae..85454bb15a7bb 100644 --- a/tests/ui/structs-enums/classes-cross-crate.rs +++ b/tests/ui/structs-enums/classes-cross-crate.rs @@ -1,47 +1,50 @@ //@ run-pass //@ aux-build:cci_class_4.rs -#![allow(non_camel_case_types)] extern crate cci_class_4; -use cci_class_4::kitties::{cat, cat_unnamed}; +use cci_class_4::*; fn simple_cross_crate() { - let nyan : cat = cat_unnamed(52, 99); - let kitty = cat_unnamed(1000, 2); - assert_eq!(nyan.how_hungry, 99); - assert_eq!(kitty.how_hungry, 2); - nyan.noop(); + let nyan: Cat = cat_unnamed(52, 99); + let kitty = cat_unnamed(1000, 2); + assert_eq!(nyan.how_hungry, 99); + assert_eq!(kitty.how_hungry, 2); + nyan.noop(); } fn cross_crate() { let mut nyan = cat(0_usize, 2, "nyan".to_string()); nyan.eat(); assert!(!nyan.eat()); - for _ in 1_usize..10_usize { nyan.speak(); }; + for _ in 1_usize..10_usize { + nyan.speak(); + } assert!(nyan.eat()); } - fn print_out(thing: Box, expected: String) { - let actual = (*thing).to_string(); - println!("{}", actual); - assert_eq!(actual.to_string(), expected); + let actual = (*thing).to_string(); + println!("{}", actual); + assert_eq!(actual.to_string(), expected); } fn separate_impl() { - let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; - print_out(nyan, "nyan".to_string()); + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; + print_out(nyan, "nyan".to_string()); } -trait noisy { +trait Noisy { fn speak(&mut self) -> isize; } -impl noisy for cat { - fn speak(&mut self) -> isize { self.meow(); 0 } +impl Noisy for Cat { + fn speak(&mut self) -> isize { + self.meow(); + 0 + } } -fn make_speak(mut c: C) { +fn make_speak(mut c: C) { c.speak(); } @@ -54,48 +57,46 @@ fn implement_traits() { } } +struct Dog { + barks: usize, -struct dog { - barks: usize, - - volume: isize, + volume: isize, } -impl dog { +impl Dog { fn bark(&mut self) -> isize { - println!("Woof {} {}", self.barks, self.volume); - self.barks += 1_usize; - if self.barks % 3_usize == 0_usize { - self.volume += 1; - } - if self.barks % 10_usize == 0_usize { - self.volume -= 2; - } - println!("Grrr {} {}", self.barks, self.volume); - self.volume + println!("Woof {} {}", self.barks, self.volume); + self.barks += 1_usize; + if self.barks % 3_usize == 0_usize { + self.volume += 1; + } + if self.barks % 10_usize == 0_usize { + self.volume -= 2; + } + println!("Grrr {} {}", self.barks, self.volume); + self.volume } } -impl noisy for dog { +impl Noisy for Dog { fn speak(&mut self) -> isize { self.bark() } } -fn dog() -> dog { - dog { - volume: 0, - barks: 0_usize - } +fn dog() -> Dog { + Dog { volume: 0, barks: 0_usize } } -fn annoy_neighbors(critter: &mut dyn noisy) { - for _i in 0_usize..10 { critter.speak(); } +fn annoy_neighbors(critter: &mut dyn Noisy) { + for _i in 0_usize..10 { + critter.speak(); + } } fn multiple_types() { - let mut nyan: cat = cat(0_usize, 2, "nyan".to_string()); - let mut whitefang: dog = dog(); + let mut nyan: Cat = cat(0_usize, 2, "nyan".to_string()); + let mut whitefang: Dog = dog(); annoy_neighbors(&mut nyan); annoy_neighbors(&mut whitefang); assert_eq!(nyan.meow_count(), 10_usize); @@ -104,7 +105,7 @@ fn multiple_types() { fn cast_to_trait() { let mut nyan = cat(0, 2, "nyan".to_string()); - let nyan: &mut dyn noisy = &mut nyan; + let nyan: &mut dyn Noisy = &mut nyan; nyan.speak(); } From 0486281b303d838694f97d8b35531a20ed0ee1c9 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 20 Mar 2026 09:48:54 +0000 Subject: [PATCH 14/40] delete some tests that lost their meaning --- tests/ui/structs-enums/export-abstract-tag.rs | 14 -------------- tests/ui/structs-enums/export-tag-variant.rs | 8 -------- tests/ui/structs-enums/rec-auto.rs | 14 -------------- .../tag-variant-disr-type-mismatch.rs | 11 ----------- tests/ui/structs-enums/tuple-struct-trivial.rs | 7 ------- 5 files changed, 54 deletions(-) delete mode 100644 tests/ui/structs-enums/export-abstract-tag.rs delete mode 100644 tests/ui/structs-enums/export-tag-variant.rs delete mode 100644 tests/ui/structs-enums/rec-auto.rs delete mode 100644 tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs delete mode 100644 tests/ui/structs-enums/tuple-struct-trivial.rs diff --git a/tests/ui/structs-enums/export-abstract-tag.rs b/tests/ui/structs-enums/export-abstract-tag.rs deleted file mode 100644 index e6d359803856d..0000000000000 --- a/tests/ui/structs-enums/export-abstract-tag.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - -// We can export tags without exporting the variants to create a simple -// sort of ADT. - - -mod foo { - pub enum t { t1, } - - pub fn f() -> t { return t::t1; } -} - -pub fn main() { let _v: foo::t = foo::f(); } diff --git a/tests/ui/structs-enums/export-tag-variant.rs b/tests/ui/structs-enums/export-tag-variant.rs deleted file mode 100644 index c6216d1b567b3..0000000000000 --- a/tests/ui/structs-enums/export-tag-variant.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] - -mod foo { - pub enum t { t1, } -} - -pub fn main() { let _v = foo::t::t1; } diff --git a/tests/ui/structs-enums/rec-auto.rs b/tests/ui/structs-enums/rec-auto.rs deleted file mode 100644 index bf2e37a189bc8..0000000000000 --- a/tests/ui/structs-enums/rec-auto.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - - - - -// Issue #50. - -struct X { foo: String, bar: String } - -pub fn main() { - let x = X {foo: "hello".to_string(), bar: "world".to_string()}; - println!("{}", x.foo.clone()); - println!("{}", x.bar.clone()); -} diff --git a/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs b/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs deleted file mode 100644 index f4c202d91a7c1..0000000000000 --- a/tests/ui/structs-enums/tag-variant-disr-type-mismatch.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - - -enum color { - red = 1, - blue = 2, -} - -pub fn main() {} diff --git a/tests/ui/structs-enums/tuple-struct-trivial.rs b/tests/ui/structs-enums/tuple-struct-trivial.rs deleted file mode 100644 index e2395036551e4..0000000000000 --- a/tests/ui/structs-enums/tuple-struct-trivial.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct Foo(isize, isize, isize); - -pub fn main() { -} From 98a14412777fc337178fc4ee6d4b4bb7c9acd85d Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 20 Mar 2026 09:55:22 +0000 Subject: [PATCH 15/40] merge several `tuple-struct-*` tests --- tests/ui/structs-enums/tuple-struct-construct.rs | 9 --------- .../ui/structs-enums/tuple-struct-destructuring.rs | 13 +++++++++++++ tests/ui/structs-enums/tuple-struct-matching.rs | 13 ------------- 3 files changed, 13 insertions(+), 22 deletions(-) delete mode 100644 tests/ui/structs-enums/tuple-struct-construct.rs delete mode 100644 tests/ui/structs-enums/tuple-struct-matching.rs diff --git a/tests/ui/structs-enums/tuple-struct-construct.rs b/tests/ui/structs-enums/tuple-struct-construct.rs deleted file mode 100644 index 4243bccb4eb7a..0000000000000 --- a/tests/ui/structs-enums/tuple-struct-construct.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass -#[allow(dead_code)] -#[derive(Debug)] -struct Foo(isize, isize); - -pub fn main() { - let x = Foo(1, 2); - println!("{:?}", x); -} diff --git a/tests/ui/structs-enums/tuple-struct-destructuring.rs b/tests/ui/structs-enums/tuple-struct-destructuring.rs index 5213052dd7a40..36a36605ba80f 100644 --- a/tests/ui/structs-enums/tuple-struct-destructuring.rs +++ b/tests/ui/structs-enums/tuple-struct-destructuring.rs @@ -1,4 +1,5 @@ //@ run-pass +#[derive(Debug)] struct Foo(isize, isize); pub fn main() { @@ -7,4 +8,16 @@ pub fn main() { println!("{} {}", y, z); assert_eq!(y, 1); assert_eq!(z, 2); + + let x = Foo(1, 2); + match x { + Foo(a, b) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + println!("{} {}", a, b); + } + } + + let x = Foo(1, 2); + assert_eq!(format!("{x:?}"), "Foo(1, 2)"); } diff --git a/tests/ui/structs-enums/tuple-struct-matching.rs b/tests/ui/structs-enums/tuple-struct-matching.rs deleted file mode 100644 index a5436624c658a..0000000000000 --- a/tests/ui/structs-enums/tuple-struct-matching.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -struct Foo(isize, isize); - -pub fn main() { - let x = Foo(1, 2); - match x { - Foo(a, b) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - println!("{} {}", a, b); - } - } -} From ff524fdb979cdc916136ed4c98605218cb56cc82 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 20 Mar 2026 09:59:26 +0000 Subject: [PATCH 16/40] move many tests from `run-pass` to `check-pass` --- tests/ui/structs-enums/class-dtor.rs | 2 +- tests/ui/structs-enums/classes-self-referential.rs | 2 +- tests/ui/structs-enums/enum-discrim-range-overflow.rs | 2 +- tests/ui/structs-enums/foreign-struct.rs | 2 +- tests/ui/structs-enums/namespaced-enum-emulate-flat.rs | 2 +- tests/ui/structs-enums/namespaced-enum-glob-import.rs | 2 +- tests/ui/structs-enums/namespaced-enums.rs | 2 +- tests/ui/structs-enums/nested-enum-same-names.rs | 2 +- tests/ui/structs-enums/newtype-struct-with-dtor.rs | 2 +- tests/ui/structs-enums/simple-generic-tag.rs | 2 +- tests/ui/structs-enums/struct-variant-field-visibility.rs | 2 +- tests/ui/structs-enums/tag-in-block.rs | 2 +- tests/ui/structs-enums/uninstantiable-struct.rs | 2 +- tests/ui/structs-enums/variant-structs-trivial.rs | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/ui/structs-enums/class-dtor.rs b/tests/ui/structs-enums/class-dtor.rs index a08f0f0b0a47f..b7911823ef1b9 100644 --- a/tests/ui/structs-enums/class-dtor.rs +++ b/tests/ui/structs-enums/class-dtor.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/classes-self-referential.rs b/tests/ui/structs-enums/classes-self-referential.rs index f819e558aa2ee..40c51a1573cd5 100644 --- a/tests/ui/structs-enums/classes-self-referential.rs +++ b/tests/ui/structs-enums/classes-self-referential.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/enum-discrim-range-overflow.rs b/tests/ui/structs-enums/enum-discrim-range-overflow.rs index 91be8014ebdaa..641e5566bee3d 100644 --- a/tests/ui/structs-enums/enum-discrim-range-overflow.rs +++ b/tests/ui/structs-enums/enum-discrim-range-overflow.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(overflowing_literals)] diff --git a/tests/ui/structs-enums/foreign-struct.rs b/tests/ui/structs-enums/foreign-struct.rs index f339c191ae806..b710d83350abf 100644 --- a/tests/ui/structs-enums/foreign-struct.rs +++ b/tests/ui/structs-enums/foreign-struct.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs b/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs index 774cfa1a38089..2bc23d94b4d92 100644 --- a/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs +++ b/tests/ui/structs-enums/namespaced-enum-emulate-flat.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] pub use Foo::*; diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import.rs b/tests/ui/structs-enums/namespaced-enum-glob-import.rs index 82742a934c413..52bfa9d4ab723 100644 --- a/tests/ui/structs-enums/namespaced-enum-glob-import.rs +++ b/tests/ui/structs-enums/namespaced-enum-glob-import.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] mod m2 { diff --git a/tests/ui/structs-enums/namespaced-enums.rs b/tests/ui/structs-enums/namespaced-enums.rs index 3e2e0b5ffa8fd..f3f1a3bd44e50 100644 --- a/tests/ui/structs-enums/namespaced-enums.rs +++ b/tests/ui/structs-enums/namespaced-enums.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] enum Foo { diff --git a/tests/ui/structs-enums/nested-enum-same-names.rs b/tests/ui/structs-enums/nested-enum-same-names.rs index 5ff730aff4415..1d3fab4e722c3 100644 --- a/tests/ui/structs-enums/nested-enum-same-names.rs +++ b/tests/ui/structs-enums/nested-enum-same-names.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] /* diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs index 35476c5ed2d6b..c0d04932c4642 100644 --- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs +++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(unused_unsafe)] #![allow(unused_variables)] diff --git a/tests/ui/structs-enums/simple-generic-tag.rs b/tests/ui/structs-enums/simple-generic-tag.rs index b78505edd1f2b..dbb5d707b52f5 100644 --- a/tests/ui/structs-enums/simple-generic-tag.rs +++ b/tests/ui/structs-enums/simple-generic-tag.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/struct-variant-field-visibility.rs b/tests/ui/structs-enums/struct-variant-field-visibility.rs index a6528f9a2b17e..40acea956aeab 100644 --- a/tests/ui/structs-enums/struct-variant-field-visibility.rs +++ b/tests/ui/structs-enums/struct-variant-field-visibility.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] mod foo { diff --git a/tests/ui/structs-enums/tag-in-block.rs b/tests/ui/structs-enums/tag-in-block.rs index 27b48aae51f60..75691f02dd824 100644 --- a/tests/ui/structs-enums/tag-in-block.rs +++ b/tests/ui/structs-enums/tag-in-block.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] #![allow(non_camel_case_types)] diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs index 97bc7d8414e7f..def0fa00e17c2 100644 --- a/tests/ui/structs-enums/uninstantiable-struct.rs +++ b/tests/ui/structs-enums/uninstantiable-struct.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass pub struct Z(#[allow(dead_code)] &'static Z); pub fn main() {} diff --git a/tests/ui/structs-enums/variant-structs-trivial.rs b/tests/ui/structs-enums/variant-structs-trivial.rs index a7b0575118437..c1403b79c8aab 100644 --- a/tests/ui/structs-enums/variant-structs-trivial.rs +++ b/tests/ui/structs-enums/variant-structs-trivial.rs @@ -1,4 +1,4 @@ -//@ run-pass +//@ check-pass #![allow(dead_code)] enum Foo { From 9677d7a5872c5c98c73f04afa028e147b983c6f6 Mon Sep 17 00:00:00 2001 From: Scott Young Date: Fri, 20 Mar 2026 17:20:06 -0400 Subject: [PATCH 17/40] debuginfo: emit DW_TAG_call_site entries --- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 7 +++++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 3 ++- tests/codegen-llvm/debuginfo-callsite-flag.rs | 20 +++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/codegen-llvm/debuginfo-callsite-flag.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index c3fa86f8a2ad3..a667877e8e51d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -471,7 +471,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { // FIXME(eddyb) does this need to be separate from `loc.line` for some reason? let scope_line = loc.line; - let mut flags = DIFlags::FlagPrototyped; + let mut flags = DIFlags::FlagPrototyped | DIFlags::FlagAllCallsDescribed; if fn_abi.ret.layout.is_uninhabited() { flags |= DIFlags::FlagNoReturn; @@ -494,6 +494,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition. // When we use this `decl` below, the subprogram definition gets created at the CU level // with a DW_AT_specification pointing back to the type's declaration. + // FlagAllCallsDescribed cannot appear on the method declaration DIE + // because it has no body, which LLVM's verifier rejects. + let decl_flags = flags & !DIFlags::FlagAllCallsDescribed; let decl = is_method.then(|| unsafe { llvm::LLVMRustDIBuilderCreateMethod( DIB(self), @@ -505,7 +508,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_metadata, loc.line, function_type_metadata, - flags, + decl_flags, spflags & !DISPFlags::SPFlagDefinition, template_parameters, ) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 77438472644fc..813897d7d3271 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -779,6 +779,7 @@ pub(crate) mod debuginfo { const FlagNonTrivial = (1 << 26); const FlagBigEndian = (1 << 27); const FlagLittleEndian = (1 << 28); + const FlagAllCallsDescribed = (1 << 29); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 63ff0b2a0a0df..392cd0601391d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -779,6 +779,7 @@ ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25); ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26); ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27); ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28); +static_assert(DINode::DIFlags::FlagAllCallsDescribed == (1 << 29)); ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5)); #undef ASSERT_DIFLAG_VALUE @@ -791,7 +792,7 @@ ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5)); // to copying each bit/subvalue. static DINode::DIFlags fromRust(LLVMDIFlags Flags) { // Check that all set bits are covered by the static assertions above. - const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21); + const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 21); if (Flags & UNKNOWN_BITS) { report_fatal_error("bad LLVMDIFlags"); } diff --git a/tests/codegen-llvm/debuginfo-callsite-flag.rs b/tests/codegen-llvm/debuginfo-callsite-flag.rs new file mode 100644 index 0000000000000..f86adfcc36266 --- /dev/null +++ b/tests/codegen-llvm/debuginfo-callsite-flag.rs @@ -0,0 +1,20 @@ +// Check that DIFlagAllCallsDescribed is set on subprogram definitions. + +//@ ignore-msvc (CodeView does not use DIFlagAllCallsDescribed) +//@ compile-flags: -C debuginfo=2 -C opt-level=1 -C no-prepopulate-passes + +// CHECK: {{.*}}DISubprogram{{.*}}name: "foo"{{.*}}DIFlagAllCallsDescribed{{.*}} + +#[no_mangle] +#[inline(never)] +pub fn foo(x: i32) -> i32 { + bar(x + 1) +} + +#[no_mangle] +#[inline(never)] +pub fn bar(x: i32) -> i32 { + x * 2 +} + +fn main() {} From 2e30fefde60a9086ddb2d9600c87b87797da56cb Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Mon, 23 Mar 2026 10:25:45 +0100 Subject: [PATCH 18/40] move statics test files out of tests/ui/issues --- .../static-cannot-use-local-variable.fixed} | 0 .../static-cannot-use-local-variable.rs} | 0 .../static-cannot-use-local-variable.stderr} | 0 .../static-in-fn-cannot-use-param.fixed} | 0 .../issue-3668-2.rs => statics/static-in-fn-cannot-use-param.rs} | 0 .../static-in-fn-cannot-use-param.stderr} | 0 .../issue-3668.rs => statics/static-in-method-cannot-use-self.rs} | 0 .../static-in-method-cannot-use-self.stderr} | 0 .../issue-39367.rs => statics/static-lazy-init-with-arena-set.rs} | 0 .../static-lazy-init-with-arena-set.stderr} | 0 .../issue-46604.rs => statics/static-mut-borrow-of-temporary.rs} | 0 .../static-mut-borrow-of-temporary.stderr} | 0 .../static-mut-with-assoc-type-field.rs} | 0 .../static-ref-deref-non-const-trait.rs} | 0 .../static-ref-deref-non-const-trait.stderr} | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-3521-2.fixed => statics/static-cannot-use-local-variable.fixed} (100%) rename tests/ui/{issues/issue-3521-2.rs => statics/static-cannot-use-local-variable.rs} (100%) rename tests/ui/{issues/issue-3521-2.stderr => statics/static-cannot-use-local-variable.stderr} (100%) rename tests/ui/{issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed => statics/static-in-fn-cannot-use-param.fixed} (100%) rename tests/ui/{issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs => statics/static-in-fn-cannot-use-param.rs} (100%) rename tests/ui/{issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr => statics/static-in-fn-cannot-use-param.stderr} (100%) rename tests/ui/{issues/issue-3668-non-constant-value-in-constant/issue-3668.rs => statics/static-in-method-cannot-use-self.rs} (100%) rename tests/ui/{issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr => statics/static-in-method-cannot-use-self.stderr} (100%) rename tests/ui/{issues/issue-39367.rs => statics/static-lazy-init-with-arena-set.rs} (100%) rename tests/ui/{issues/issue-39367.stderr => statics/static-lazy-init-with-arena-set.stderr} (100%) rename tests/ui/{issues/issue-46604.rs => statics/static-mut-borrow-of-temporary.rs} (100%) rename tests/ui/{issues/issue-46604.stderr => statics/static-mut-borrow-of-temporary.stderr} (100%) rename tests/ui/{issues/issue-29821.rs => statics/static-mut-with-assoc-type-field.rs} (100%) rename tests/ui/{issues/issue-25901.rs => statics/static-ref-deref-non-const-trait.rs} (100%) rename tests/ui/{issues/issue-25901.stderr => statics/static-ref-deref-non-const-trait.stderr} (100%) diff --git a/tests/ui/issues/issue-3521-2.fixed b/tests/ui/statics/static-cannot-use-local-variable.fixed similarity index 100% rename from tests/ui/issues/issue-3521-2.fixed rename to tests/ui/statics/static-cannot-use-local-variable.fixed diff --git a/tests/ui/issues/issue-3521-2.rs b/tests/ui/statics/static-cannot-use-local-variable.rs similarity index 100% rename from tests/ui/issues/issue-3521-2.rs rename to tests/ui/statics/static-cannot-use-local-variable.rs diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/statics/static-cannot-use-local-variable.stderr similarity index 100% rename from tests/ui/issues/issue-3521-2.stderr rename to tests/ui/statics/static-cannot-use-local-variable.stderr diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed b/tests/ui/statics/static-in-fn-cannot-use-param.fixed similarity index 100% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.fixed rename to tests/ui/statics/static-in-fn-cannot-use-param.fixed diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs b/tests/ui/statics/static-in-fn-cannot-use-param.rs similarity index 100% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs rename to tests/ui/statics/static-in-fn-cannot-use-param.rs diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/statics/static-in-fn-cannot-use-param.stderr similarity index 100% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr rename to tests/ui/statics/static-in-fn-cannot-use-param.stderr diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs b/tests/ui/statics/static-in-method-cannot-use-self.rs similarity index 100% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs rename to tests/ui/statics/static-in-method-cannot-use-self.rs diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/statics/static-in-method-cannot-use-self.stderr similarity index 100% rename from tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr rename to tests/ui/statics/static-in-method-cannot-use-self.stderr diff --git a/tests/ui/issues/issue-39367.rs b/tests/ui/statics/static-lazy-init-with-arena-set.rs similarity index 100% rename from tests/ui/issues/issue-39367.rs rename to tests/ui/statics/static-lazy-init-with-arena-set.rs diff --git a/tests/ui/issues/issue-39367.stderr b/tests/ui/statics/static-lazy-init-with-arena-set.stderr similarity index 100% rename from tests/ui/issues/issue-39367.stderr rename to tests/ui/statics/static-lazy-init-with-arena-set.stderr diff --git a/tests/ui/issues/issue-46604.rs b/tests/ui/statics/static-mut-borrow-of-temporary.rs similarity index 100% rename from tests/ui/issues/issue-46604.rs rename to tests/ui/statics/static-mut-borrow-of-temporary.rs diff --git a/tests/ui/issues/issue-46604.stderr b/tests/ui/statics/static-mut-borrow-of-temporary.stderr similarity index 100% rename from tests/ui/issues/issue-46604.stderr rename to tests/ui/statics/static-mut-borrow-of-temporary.stderr diff --git a/tests/ui/issues/issue-29821.rs b/tests/ui/statics/static-mut-with-assoc-type-field.rs similarity index 100% rename from tests/ui/issues/issue-29821.rs rename to tests/ui/statics/static-mut-with-assoc-type-field.rs diff --git a/tests/ui/issues/issue-25901.rs b/tests/ui/statics/static-ref-deref-non-const-trait.rs similarity index 100% rename from tests/ui/issues/issue-25901.rs rename to tests/ui/statics/static-ref-deref-non-const-trait.rs diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/statics/static-ref-deref-non-const-trait.stderr similarity index 100% rename from tests/ui/issues/issue-25901.stderr rename to tests/ui/statics/static-ref-deref-non-const-trait.stderr From af6324a90f502d18cebcf5d10fe90ae613007a42 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 23 Mar 2026 22:25:09 -0400 Subject: [PATCH 19/40] Fix typo in doc comment for `char::to_titlecase` --- library/core/src/char/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index e9c3b040dc50b..46d48afbf5a14 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1212,7 +1212,7 @@ impl char { /// returned by [`Self::to_uppercase`]. Prefer this method when seeking to capitalize /// Only The First Letter of a word, but use [`Self::to_uppercase`] for ALL CAPS. /// - /// If this `char` does not have an titlecase mapping, the iterator yields the same `char`. + /// If this `char` does not have a titlecase mapping, the iterator yields the same `char`. /// /// If this `char` has a one-to-one titlecase mapping given by the [Unicode Character /// Database][ucd] [`UnicodeData.txt`], the iterator yields that `char`. From 5f680443579ae914c005cc40485a1c029cbe4cdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2026 18:37:52 +0100 Subject: [PATCH 20/40] miri recursive checking: only check one layer deep --- .../rustc_const_eval/src/interpret/validity.rs | 14 +++++++++++--- src/tools/miri/README.md | 5 +++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 62ee653000dca..9310cda8450b6 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1512,6 +1512,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// The internal core entry point for all validation operations. fn validate_operand_internal( &mut self, val: &PlaceTy<'tcx, M::Provenance>, @@ -1519,6 +1520,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ref_tracking: Option<&mut RefTracking, Vec>>, ctfe_mode: Option, reset_provenance_and_padding: bool, + start_in_may_dangle: bool, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); @@ -1536,7 +1538,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ecx, reset_provenance_and_padding, data_bytes: reset_padding.then_some(RangeSet(Vec::new())), - may_dangle: false, + may_dangle: start_in_may_dangle, }; v.visit_value(val)?; v.reset_padding(val)?; @@ -1579,6 +1581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(ref_tracking), Some(ctfe_mode), /*reset_provenance*/ false, + /*start_in_may_dangle*/ false, ) } @@ -1610,6 +1613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { None, None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, ); } // Do a recursive check. @@ -1620,15 +1624,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(&mut ref_tracking), None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, )?; while let Some((mplace, path)) = ref_tracking.todo.pop() { - // Things behind reference do *not* have the provenance reset. + // Things behind reference do *not* have the provenance reset. In fact + // we treat the entire thing as being inside MaybeDangling, i.e., references + // do not have to be dereferenceable. self.validate_operand_internal( &mplace.into(), path, - Some(&mut ref_tracking), + None, // no further recursion None, /*reset_provenance_and_padding*/ false, + /*start_in_may_dangle*/ true, )?; } interp_ok(()) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 97f385ad755bc..f51cd96486b4f 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -476,8 +476,9 @@ to Miri failing to detect cases of undefined behavior in a program. but reports to the program that it did actually write. This is useful when you are not interested in the actual program's output, but only want to see Miri's errors and warnings. -* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking - recurse below references. +* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking recurse + *one level* below references. The in-memory value is treated as-if it was inside a + `MaybeDangling`, i.e., nested references do not even have to be dereferenceable. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. Note that even without preemption, the schedule is still non-deterministic: From 422906d57e99eaf8a27c0aa2696cac3286c2594f Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 24 Mar 2026 17:39:46 +0000 Subject: [PATCH 21/40] Do not check for LEAK & KERNELHWADDRESS because they are incompatible --- compiler/rustc_codegen_ssa/src/back/link.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index be7da2e81add8..7a3d5a6bb2248 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1341,7 +1341,6 @@ fn add_sanitizer_libraries( if sanitizer.contains(SanitizerSet::LEAK) && !sanitizer.contains(SanitizerSet::ADDRESS) && !sanitizer.contains(SanitizerSet::HWADDRESS) - && !sanitizer.contains(SanitizerSet::KERNELHWADDRESS) { link_sanitizer_runtime(sess, flavor, linker, "lsan"); } From 4d86840bf153fa62e92db3065e7b02b117823a52 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 24 Mar 2026 17:46:20 +0000 Subject: [PATCH 22/40] Document kernel-hwaddress in Unstable Book --- .../unstable-book/src/compiler-flags/sanitizer.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 1771d1382f073..eb070c22dc288 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -22,6 +22,8 @@ This feature allows for use of one of following sanitizers: * [AddressSanitizer](#addresssanitizer) a fast memory error detector. * [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to AddressSanitizer, but based on partial hardware assistance. + * [KernelHWAddressSanitizer](#kernelhwaddresssanitizer) variant of + HWAddressSanitizer that is designed for bare metal environments. * [LeakSanitizer](#leaksanitizer) a run-time memory leak detector. * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. * [RealtimeSanitizer](#realtimesanitizer) a detector of calls to function with @@ -622,6 +624,16 @@ Registers where the failure occurred (pc 0xaaaae0ae4a98): SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94) ``` +# KernelHWAddressSanitizer + +KernelHWAddressSanitizer is the kernel version of [HWAddressSanitizer](#hwaddresssanitizer), +which achieves the same purpose but is designed for bare-metal environments. + +HWAddressSanitizer is supported on the `aarch64*-unknown-none` and +`aarch64*-unknown-none-softfloat` targets. + +See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details. + # KernelControlFlowIntegrity The LLVM Kernel Control Flow Integrity (CFI) support to the Rust compiler From 283d705b314d8b393134f694ce005b5b5959ad60 Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 25 Mar 2026 07:32:01 +0800 Subject: [PATCH 23/40] Update LLVM to 22.1.2 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 41f177ed26a52..05918363362b4 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 41f177ed26a5252a30ea6090a4da66ce0a96bf44 +Subproject commit 05918363362b439b9b0bced3daa14badd75da790 From 62ba3c1022f2070125f070dadeb6d6dae694b3a0 Mon Sep 17 00:00:00 2001 From: kyleecodes Date: Wed, 25 Mar 2026 00:35:04 +0000 Subject: [PATCH 24/40] Move ui/issues tests to relevant subdirectories * tests(ui): migrate issues/issue-17546 to ui/resolve * tests(ui): add gh issue link * tests(ui/issues): move tests to variants dir --- .../variant-result-noresult-used-as-type.rs} | 1 + .../variant-result-noresult-used-as-type.stderr} | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) rename tests/ui/{issues/issue-17546.rs => variants/variant-result-noresult-used-as-type.rs} (94%) rename tests/ui/{issues/issue-17546.stderr => variants/variant-result-noresult-used-as-type.stderr} (89%) diff --git a/tests/ui/issues/issue-17546.rs b/tests/ui/variants/variant-result-noresult-used-as-type.rs similarity index 94% rename from tests/ui/issues/issue-17546.rs rename to tests/ui/variants/variant-result-noresult-used-as-type.rs index 1f0afc368a2eb..14433c1460ebb 100644 --- a/tests/ui/issues/issue-17546.rs +++ b/tests/ui/variants/variant-result-noresult-used-as-type.rs @@ -1,5 +1,6 @@ //@ edition:2015 //@ ignore-sgx std::os::fortanix_sgx::usercalls::raw::Result changes compiler suggestions +// https://github.com/rust-lang/rust/issues/17546 use foo::MyEnum::Result; use foo::NoResult; // Through a re-export diff --git a/tests/ui/issues/issue-17546.stderr b/tests/ui/variants/variant-result-noresult-used-as-type.stderr similarity index 89% rename from tests/ui/issues/issue-17546.stderr rename to tests/ui/variants/variant-result-noresult-used-as-type.stderr index d4aa354491fe1..511cb3562f947 100644 --- a/tests/ui/issues/issue-17546.stderr +++ b/tests/ui/variants/variant-result-noresult-used-as-type.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:15:17 + --> $DIR/variant-result-noresult-used-as-type.rs:16:17 | LL | fn new() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL + fn new() -> Result { | error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:25:17 + --> $DIR/variant-result-noresult-used-as-type.rs:26:17 | LL | fn new() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type @@ -36,7 +36,7 @@ LL + use std::thread::Result; | error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:31:13 + --> $DIR/variant-result-noresult-used-as-type.rs:32:13 | LL | fn new() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type @@ -53,7 +53,7 @@ LL + use std::thread::Result; | error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:36:15 + --> $DIR/variant-result-noresult-used-as-type.rs:37:15 | LL | fn newer() -> NoResult { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 8ab0c4cbf39916f4860b2bae376d0d4ca18e2112 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 13:53:53 +1100 Subject: [PATCH 25/40] Remove unused `Erasable` impls. There are many! --- compiler/rustc_middle/src/query/erase.rs | 115 +---------------------- 1 file changed, 1 insertion(+), 114 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 036aa2ed05a4a..a28e8f23e045f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -108,10 +108,6 @@ impl Erasable for &'_ [T] { type Storage = [u8; size_of::<&'static [()]>()]; } -impl Erasable for &'_ OsStr { - type Storage = [u8; size_of::<&'static OsStr>()]; -} - impl Erasable for &'_ ty::List { type Storage = [u8; size_of::<&'static ty::List<()>>()]; } @@ -120,26 +116,14 @@ impl Erasable for &'_ ty::ListWithCachedTypeInfo { type Storage = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()]; } -impl Erasable for &'_ rustc_index::IndexSlice { - type Storage = [u8; size_of::<&'static rustc_index::IndexSlice>()]; -} - impl Erasable for Result<&'_ T, traits::query::NoSolution> { type Storage = [u8; size_of::>()]; } -impl Erasable for Result<&'_ [T], traits::query::NoSolution> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Result<&'_ T, rustc_errors::ErrorGuaranteed> { type Storage = [u8; size_of::>()]; } -impl Erasable for Result<&'_ [T], rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Result<&'_ T, traits::CodegenObligationError> { type Storage = [u8; size_of::>()]; } @@ -229,10 +213,6 @@ impl Erasable for Option<&'_ OsStr> { type Storage = [u8; size_of::>()]; } -impl Erasable for Option> { - type Storage = [u8; size_of::>>()]; -} - impl Erasable for ty::ImplTraitHeader<'_> { type Storage = [u8; size_of::>()]; } @@ -262,10 +242,6 @@ impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes>> { [u8; size_of::>>>()]; } -impl Erasable for ty::Binder<'_, &'_ ty::List>> { - type Storage = [u8; size_of::>>>()]; -} - impl Erasable for (&'_ T0, &'_ T1) { type Storage = [u8; size_of::<(&'static (), &'static ())>()]; } @@ -274,14 +250,6 @@ impl Erasable for (solve::QueryResult<'_>, &'_ T0) { type Storage = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()]; } -impl Erasable for (&'_ T0, &'_ [T1]) { - type Storage = [u8; size_of::<(&'static (), &'static [()])>()]; -} - -impl Erasable for (&'_ [T0], &'_ [T1]) { - type Storage = [u8; size_of::<(&'static [()], &'static [()])>()]; -} - impl Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) { type Storage = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()]; } @@ -308,109 +276,54 @@ impl_erasable_for_simple_types! { Option, Option, Option, - Option, Option, - Option, Option, Option, Option, - Option, Option, Option, Option, Option, Option, - Option, Option, Option, Option, Option, Result<(), rustc_errors::ErrorGuaranteed>, - Result<(), rustc_middle::traits::query::NoSolution>, Result, Result, Result, - rustc_abi::ReprOptions, - rustc_ast::expand::allocator::AllocatorKind, - rustc_hir::DefaultBodyStability, - rustc_hir::attrs::Deprecation, - rustc_hir::attrs::EiiDecl, - rustc_hir::attrs::EiiImpl, rustc_data_structures::svh::Svh, - rustc_errors::ErrorGuaranteed, rustc_hir::Constness, - rustc_hir::ConstStability, rustc_hir::def_id::DefId, - rustc_hir::def_id::DefIndex, - rustc_hir::def_id::LocalDefId, - rustc_hir::def_id::LocalModDefId, rustc_hir::def::DefKind, rustc_hir::Defaultness, - rustc_hir::definitions::DefKey, - rustc_hir::CoroutineKind, rustc_hir::HirId, - rustc_hir::IsAsync, - rustc_hir::ItemLocalId, - rustc_hir::LangItem, rustc_hir::OpaqueTyOrigin, - rustc_hir::OwnerId, - rustc_hir::Stability, - rustc_hir::Upvar, - rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs, - rustc_middle::middle::dependency_format::Linkage, - rustc_middle::middle::exported_symbols::SymbolExportInfo, rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, - rustc_middle::middle::resolve_bound_vars::ResolvedArg, - rustc_middle::middle::stability::DeprecationEntry, rustc_middle::mir::ConstQualifs, rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::AllocId, - rustc_middle::mir::interpret::CtfeProvenance, - rustc_middle::mir::interpret::ErrorHandled, - rustc_middle::thir::ExprId, - rustc_middle::traits::CodegenObligationError, - rustc_middle::traits::EvaluationResult, - rustc_middle::traits::OverflowError, - rustc_middle::traits::query::NoSolution, - rustc_middle::traits::WellFormedLoc, - rustc_middle::ty::adjustment::CoerceUnsizedInfo, rustc_middle::ty::AssocItem, - rustc_middle::ty::AssocContainer, rustc_middle::ty::Asyncness, - rustc_middle::ty::AsyncDestructor, rustc_middle::ty::AnonConstKind, - rustc_middle::ty::Destructor, - rustc_middle::ty::fast_reject::SimplifiedType, - rustc_middle::ty::ImplPolarity, - rustc_middle::ty::util::AlwaysRequiresDrop, rustc_middle::ty::Visibility, rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs, - rustc_session::config::CrateType, - rustc_session::config::EntryFnType, rustc_session::config::OptLevel, rustc_session::config::SymbolManglingVersion, rustc_session::cstore::CrateDepKind, - rustc_session::cstore::ExternCrate, - rustc_session::cstore::LinkagePreference, rustc_session::Limits, - rustc_session::lint::LintExpectationId, - rustc_span::def_id::CrateNum, - rustc_span::def_id::DefPathHash, - rustc_span::ExpnHash, rustc_span::ExpnId, rustc_span::Span, rustc_span::Symbol, - rustc_span::Ident, rustc_target::spec::PanicStrategy, - rustc_type_ir::Variance, - u32, usize, } macro_rules! impl_erasable_for_single_lifetime_types { ($($($fake_path:ident)::+),+ $(,)?) => { $( - impl<'tcx> Erasable for $($fake_path)::+<'tcx> { + impl Erasable for $($fake_path)::+<'_> { type Storage = [u8; size_of::<$($fake_path)::+<'static>>()]; } )* @@ -424,43 +337,17 @@ macro_rules! impl_erasable_for_single_lifetime_types { // lifetime can probably be migrated here. impl_erasable_for_single_lifetime_types! { // FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this. - rustc_middle::middle::exported_symbols::ExportedSymbol, - rustc_middle::mir::Const, - rustc_middle::mir::DestructuredConstant, - rustc_middle::mir::ConstAlloc, - rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::mir::mono::MonoItemPartitions, rustc_middle::traits::query::MethodAutoderefStepsResult, - rustc_middle::traits::query::type_op::AscribeUserType, - rustc_middle::traits::query::type_op::Eq, - rustc_middle::traits::query::type_op::ProvePredicate, - rustc_middle::traits::query::type_op::Subtype, rustc_middle::ty::AdtDef, - rustc_middle::ty::AliasTy, - rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, - rustc_middle::ty::DestructuredAdtConst, - rustc_middle::ty::ExistentialTraitRef, - rustc_middle::ty::FnSig, - rustc_middle::ty::GenericArg, rustc_middle::ty::GenericPredicates, rustc_middle::ty::ConstConditions, rustc_middle::ty::inhabitedness::InhabitedPredicate, - rustc_middle::ty::Instance, - rustc_middle::ty::BoundVariableKind, - rustc_middle::ty::InstanceKind, - rustc_middle::ty::layout::FnAbiError, - rustc_middle::ty::layout::LayoutError, - rustc_middle::ty::LitToConstInput, rustc_middle::ty::ParamEnv, rustc_middle::ty::TypingEnv, - rustc_middle::ty::Predicate, rustc_middle::ty::SymbolName, - rustc_middle::ty::TraitRef, rustc_middle::ty::Ty, - rustc_middle::ty::UnevaluatedConst, - rustc_middle::ty::ValTree, - rustc_middle::ty::VtblEntry, } From 833bf3c375b2931826f65a8bad31658aa9b5ac5f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 14:16:33 +1100 Subject: [PATCH 26/40] Sort `impl_erasable_*` macro calls. --- compiler/rustc_middle/src/query/erase.rs | 36 +++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a28e8f23e045f..66b0f01196d4a 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -267,57 +267,58 @@ macro_rules! impl_erasable_for_simple_types { // For concrete types with no lifetimes, the erased storage for `Foo` is // `[u8; size_of::()]`. impl_erasable_for_simple_types! { - // FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this. + // tidy-alphabetical-start (), - bool, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, + Option, Option, + Option, Option, + Option, Option, Option, - Option, - Option, Option, Option, Option, + Option, Option, + Option, Option, Option, Option, - Option, Option, Option, - Option, - Option, Result<(), rustc_errors::ErrorGuaranteed>, + Result, Result, Result, - Result, + bool, rustc_data_structures::svh::Svh, rustc_hir::Constness, - rustc_hir::def_id::DefId, - rustc_hir::def::DefKind, rustc_hir::Defaultness, rustc_hir::HirId, rustc_hir::OpaqueTyOrigin, + rustc_hir::def::DefKind, + rustc_hir::def_id::DefId, + rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs, rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, rustc_middle::mir::ConstQualifs, rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::AllocId, + rustc_middle::ty::AnonConstKind, rustc_middle::ty::AssocItem, rustc_middle::ty::Asyncness, - rustc_middle::ty::AnonConstKind, rustc_middle::ty::Visibility, - rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs, + rustc_session::Limits, rustc_session::config::OptLevel, rustc_session::config::SymbolManglingVersion, rustc_session::cstore::CrateDepKind, - rustc_session::Limits, rustc_span::ExpnId, rustc_span::Span, rustc_span::Symbol, rustc_target::spec::PanicStrategy, usize, + // tidy-alphabetical-end } macro_rules! impl_erasable_for_single_lifetime_types { @@ -336,18 +337,19 @@ macro_rules! impl_erasable_for_single_lifetime_types { // FIXME(#151565): Some of the hand-written impls above that only use one // lifetime can probably be migrated here. impl_erasable_for_single_lifetime_types! { - // FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this. + // tidy-alphabetical-start rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::mir::mono::MonoItemPartitions, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::ty::AdtDef, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, - rustc_middle::ty::GenericPredicates, rustc_middle::ty::ConstConditions, - rustc_middle::ty::inhabitedness::InhabitedPredicate, + rustc_middle::ty::GenericPredicates, rustc_middle::ty::ParamEnv, - rustc_middle::ty::TypingEnv, rustc_middle::ty::SymbolName, rustc_middle::ty::Ty, + rustc_middle::ty::TypingEnv, + rustc_middle::ty::inhabitedness::InhabitedPredicate, + // tidy-alphabetical-end } From 289932194af47f75359e3db05b910d9c9b9e9856 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 14:19:37 +1100 Subject: [PATCH 27/40] Avoid unnecessary qualification of `ErrorGuaranteed`. It's imported and can be used directly within this file, and already is in a few places. --- compiler/rustc_middle/src/query/erase.rs | 25 ++++++++++-------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 66b0f01196d4a..fce9943d105b6 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -120,8 +120,8 @@ impl Erasable for Result<&'_ T, traits::query::NoSolution> { type Storage = [u8; size_of::>()]; } -impl Erasable for Result<&'_ T, rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; +impl Erasable for Result<&'_ T, ErrorGuaranteed> { + type Storage = [u8; size_of::>()]; } impl Erasable for Result<&'_ T, traits::CodegenObligationError> { @@ -132,22 +132,17 @@ impl Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { type Storage = [u8; size_of::>>()]; } -impl Erasable for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> { - type Storage = [u8; size_of::< - Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>, - >()]; +impl Erasable for Result<(&'_ T, crate::thir::ExprId), ErrorGuaranteed> { + type Storage = [u8; size_of::>()]; } -impl Erasable for Result>, rustc_errors::ErrorGuaranteed> { - type Storage = - [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; +impl Erasable for Result>, ErrorGuaranteed> { + type Storage = [u8; size_of::>, ErrorGuaranteed>>()]; } -impl Erasable - for Result>>, rustc_errors::ErrorGuaranteed> -{ +impl Erasable for Result>>, ErrorGuaranteed> { type Storage = [u8; size_of::< - Result>>, rustc_errors::ErrorGuaranteed>, + Result>>, ErrorGuaranteed>, >()]; } @@ -288,10 +283,10 @@ impl_erasable_for_simple_types! { Option, Option, Option, - Result<(), rustc_errors::ErrorGuaranteed>, + Result<(), ErrorGuaranteed>, Result, Result, - Result, + Result, bool, rustc_data_structures::svh::Svh, rustc_hir::Constness, From 2fde4f4210b0e300e70613238769089a2cede7fd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 14:24:45 +1100 Subject: [PATCH 28/40] Adjust some `Erasable` impls. A few can be done with the `impl_erasable_for_single_lifetime_types!` macro instead of being hand-written. --- compiler/rustc_middle/src/query/erase.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fce9943d105b6..865cdecf6d804 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -12,7 +12,6 @@ use std::mem::MaybeUninit; use rustc_ast::tokenstream::TokenStream; use rustc_span::{ErrorGuaranteed, Spanned}; -use crate::mir::interpret::EvalToValTreeResult; use crate::mir::mono::{MonoItem, NormalizationErrorInMono}; use crate::traits::solve; use crate::ty::{self, Ty, TyCtxt}; @@ -172,10 +171,6 @@ impl Erasable for Option<(mir::ConstValue, Ty<'_>)> { type Storage = [u8; size_of::)>>()]; } -impl Erasable for EvalToValTreeResult<'_> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { type Storage = [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; @@ -208,10 +203,6 @@ impl Erasable for Option<&'_ OsStr> { type Storage = [u8; size_of::>()]; } -impl Erasable for ty::ImplTraitHeader<'_> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Option>> { type Storage = [u8; size_of::>>>()]; } @@ -220,10 +211,6 @@ impl Erasable for Option> { type Storage = [u8; size_of::>>()]; } -impl Erasable for rustc_hir::MaybeOwner<'_> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for ty::EarlyBinder<'_, T> { type Storage = T::Storage; } @@ -328,12 +315,11 @@ macro_rules! impl_erasable_for_single_lifetime_types { // For types containing a single lifetime and no other generics, e.g. // `Foo<'tcx>`, the erased storage is `[u8; size_of::>()]`. -// -// FIXME(#151565): Some of the hand-written impls above that only use one -// lifetime can probably be migrated here. impl_erasable_for_single_lifetime_types! { // tidy-alphabetical-start + rustc_hir::MaybeOwner, rustc_middle::mir::interpret::EvalStaticInitializerRawResult, + rustc_middle::mir::interpret::EvalToValTreeResult, rustc_middle::mir::mono::MonoItemPartitions, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::ty::AdtDef, @@ -341,6 +327,7 @@ impl_erasable_for_single_lifetime_types! { rustc_middle::ty::Const, rustc_middle::ty::ConstConditions, rustc_middle::ty::GenericPredicates, + rustc_middle::ty::ImplTraitHeader, rustc_middle::ty::ParamEnv, rustc_middle::ty::SymbolName, rustc_middle::ty::Ty, From efd36a4897b643882ad037c77fc6ddd84fff4f4b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 14:29:10 +1100 Subject: [PATCH 29/40] Avoid 'static in `Erasable` impls. Using '_ removes unnecessary differences between the impl type and the associated `Storage` type. --- compiler/rustc_middle/src/query/erase.rs | 62 ++++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 865cdecf6d804..59853e8cc4640 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -100,71 +100,71 @@ pub fn restore_val(erased_value: Erased) -> T { // FIXME(#151565): Using `T: ?Sized` here should let us remove the separate // impls for fat reference types. impl Erasable for &'_ T { - type Storage = [u8; size_of::<&'static ()>()]; + type Storage = [u8; size_of::<&'_ ()>()]; } impl Erasable for &'_ [T] { - type Storage = [u8; size_of::<&'static [()]>()]; + type Storage = [u8; size_of::<&'_ [()]>()]; } impl Erasable for &'_ ty::List { - type Storage = [u8; size_of::<&'static ty::List<()>>()]; + type Storage = [u8; size_of::<&'_ ty::List<()>>()]; } impl Erasable for &'_ ty::ListWithCachedTypeInfo { - type Storage = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()]; + type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()]; } impl Erasable for Result<&'_ T, traits::query::NoSolution> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Result<&'_ T, ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Result<&'_ T, traits::CodegenObligationError> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { - type Storage = [u8; size_of::>>()]; + type Storage = [u8; size_of::>>()]; } impl Erasable for Result<(&'_ T, crate::thir::ExprId), ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Result>, ErrorGuaranteed> { - type Storage = [u8; size_of::>, ErrorGuaranteed>>()]; + type Storage = [u8; size_of::>, ErrorGuaranteed>>()]; } impl Erasable for Result>>, ErrorGuaranteed> { type Storage = [u8; size_of::< - Result>>, ErrorGuaranteed>, + Result>>, ErrorGuaranteed>, >()]; } impl Erasable for Result, traits::query::NoSolution> { - type Storage = [u8; size_of::, traits::query::NoSolution>>()]; + type Storage = [u8; size_of::, traits::query::NoSolution>>()]; } impl Erasable for Result> { - type Storage = [u8; size_of::>>()]; + type Storage = [u8; size_of::>>()]; } impl Erasable for Result>, &ty::layout::LayoutError<'_>> { type Storage = [u8; size_of::< Result< - rustc_abi::TyAndLayout<'static, Ty<'static>>, - &'static ty::layout::LayoutError<'static>, + rustc_abi::TyAndLayout<'_, Ty<'_>>, + &'_ ty::layout::LayoutError<'_>, >, >()]; } impl Erasable for Result, mir::interpret::ErrorHandled> { type Storage = - [u8; size_of::, mir::interpret::ErrorHandled>>()]; + [u8; size_of::, mir::interpret::ErrorHandled>>()]; } impl Erasable for Option<(mir::ConstValue, Ty<'_>)> { @@ -173,7 +173,7 @@ impl Erasable for Option<(mir::ConstValue, Ty<'_>)> { impl Erasable for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { type Storage = - [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; + [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; } impl Erasable @@ -181,34 +181,34 @@ impl Erasable { type Storage = [u8; size_of::< Result< - (&'static [Spanned>], &'static [Spanned>]), + (&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono, >, >()]; } impl Erasable for Result<&'_ TokenStream, ()> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Option<&'_ T> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Option<&'_ [T]> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Option<&'_ OsStr> { - type Storage = [u8; size_of::>()]; + type Storage = [u8; size_of::>()]; } impl Erasable for Option>> { - type Storage = [u8; size_of::>>>()]; + type Storage = [u8; size_of::>>>()]; } impl Erasable for Option> { - type Storage = [u8; size_of::>>()]; + type Storage = [u8; size_of::>>()]; } impl Erasable for ty::EarlyBinder<'_, T> { @@ -216,24 +216,24 @@ impl Erasable for ty::EarlyBinder<'_, T> { } impl Erasable for ty::Binder<'_, ty::FnSig<'_>> { - type Storage = [u8; size_of::>>()]; + type Storage = [u8; size_of::>>()]; } impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes>> { type Storage = - [u8; size_of::>>>()]; + [u8; size_of::>>>()]; } impl Erasable for (&'_ T0, &'_ T1) { - type Storage = [u8; size_of::<(&'static (), &'static ())>()]; + type Storage = [u8; size_of::<(&'_ (), &'_ ())>()]; } impl Erasable for (solve::QueryResult<'_>, &'_ T0) { - type Storage = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()]; + type Storage = [u8; size_of::<(solve::QueryResult<'_>, &'_ ())>()]; } impl Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) { - type Storage = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()]; + type Storage = [u8; size_of::<(&'_ (), Result<(), ErrorGuaranteed>)>()]; } macro_rules! impl_erasable_for_simple_types { @@ -307,14 +307,14 @@ macro_rules! impl_erasable_for_single_lifetime_types { ($($($fake_path:ident)::+),+ $(,)?) => { $( impl Erasable for $($fake_path)::+<'_> { - type Storage = [u8; size_of::<$($fake_path)::+<'static>>()]; + type Storage = [u8; size_of::<$($fake_path)::+<'_>>()]; } )* } } // For types containing a single lifetime and no other generics, e.g. -// `Foo<'tcx>`, the erased storage is `[u8; size_of::>()]`. +// `Foo<'tcx>`, the erased storage is `[u8; size_of::>()]`. impl_erasable_for_single_lifetime_types! { // tidy-alphabetical-start rustc_hir::MaybeOwner, From dce180559976fc3ce4d90a67541dcc724109e9ba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 14:40:46 +1100 Subject: [PATCH 30/40] Use `impl_erasable_for_simple_types!` more, and rename it. Now that 'static lifetimes aren't used, a lot of the hand-written `Erasable` impls can now be done with the macro. (The only ones that can't are those with a generic type parameter, because `size_of` doesn't work in that case.) Also, `impl_erasable_for_single_lifetime_types!` isn't needed at all. --- compiler/rustc_middle/src/query/erase.rs | 149 ++++++----------------- 1 file changed, 35 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 59853e8cc4640..54fe858e4809f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -135,62 +135,6 @@ impl Erasable for Result<(&'_ T, crate::thir::ExprId), ErrorGuaranteed> { type Storage = [u8; size_of::>()]; } -impl Erasable for Result>, ErrorGuaranteed> { - type Storage = [u8; size_of::>, ErrorGuaranteed>>()]; -} - -impl Erasable for Result>>, ErrorGuaranteed> { - type Storage = [u8; size_of::< - Result>>, ErrorGuaranteed>, - >()]; -} - -impl Erasable for Result, traits::query::NoSolution> { - type Storage = [u8; size_of::, traits::query::NoSolution>>()]; -} - -impl Erasable for Result> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for Result>, &ty::layout::LayoutError<'_>> { - type Storage = [u8; size_of::< - Result< - rustc_abi::TyAndLayout<'_, Ty<'_>>, - &'_ ty::layout::LayoutError<'_>, - >, - >()]; -} - -impl Erasable for Result, mir::interpret::ErrorHandled> { - type Storage = - [u8; size_of::, mir::interpret::ErrorHandled>>()]; -} - -impl Erasable for Option<(mir::ConstValue, Ty<'_>)> { - type Storage = [u8; size_of::)>>()]; -} - -impl Erasable for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { - type Storage = - [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; -} - -impl Erasable - for Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono> -{ - type Storage = [u8; size_of::< - Result< - (&'_ [Spanned>], &'_ [Spanned>]), - NormalizationErrorInMono, - >, - >()]; -} - -impl Erasable for Result<&'_ TokenStream, ()> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Option<&'_ T> { type Storage = [u8; size_of::>()]; } @@ -199,31 +143,10 @@ impl Erasable for Option<&'_ [T]> { type Storage = [u8; size_of::>()]; } -impl Erasable for Option<&'_ OsStr> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Option>> { - type Storage = [u8; size_of::>>>()]; -} - -impl Erasable for Option> { - type Storage = [u8; size_of::>>()]; -} - impl Erasable for ty::EarlyBinder<'_, T> { type Storage = T::Storage; } -impl Erasable for ty::Binder<'_, ty::FnSig<'_>> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes>> { - type Storage = - [u8; size_of::>>>()]; -} - impl Erasable for (&'_ T0, &'_ T1) { type Storage = [u8; size_of::<(&'_ (), &'_ ())>()]; } @@ -236,7 +159,7 @@ impl Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) { type Storage = [u8; size_of::<(&'_ (), Result<(), ErrorGuaranteed>)>()]; } -macro_rules! impl_erasable_for_simple_types { +macro_rules! impl_erasable_for_types_with_no_type_params { ($($ty:ty),+ $(,)?) => { $( impl Erasable for $ty { @@ -246,11 +169,13 @@ macro_rules! impl_erasable_for_simple_types { } } -// For concrete types with no lifetimes, the erased storage for `Foo` is -// `[u8; size_of::()]`. -impl_erasable_for_simple_types! { +// For types with no type parameters the erased storage for `Foo` is +// `[u8; size_of::()]`. ('_ lifetimes are allowed.) +impl_erasable_for_types_with_no_type_params! { // tidy-alphabetical-start (), + Option<&'_ OsStr>, + Option<(mir::ConstValue, Ty<'_>)>, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option, Option, @@ -269,16 +194,29 @@ impl_erasable_for_simple_types! { Option, Option, Option, + Option>>, + Option>, Option, + Result<&'_ TokenStream, ()>, + Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop>, + Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono>, Result<(), ErrorGuaranteed>, + Result>>, ErrorGuaranteed>, + Result>, ErrorGuaranteed>, + Result>, + Result, mir::interpret::ErrorHandled>, Result, + Result>, &ty::layout::LayoutError<'_>>, Result, Result, + Result, traits::query::NoSolution>, + Ty<'_>, bool, rustc_data_structures::svh::Svh, rustc_hir::Constness, rustc_hir::Defaultness, rustc_hir::HirId, + rustc_hir::MaybeOwner<'_>, rustc_hir::OpaqueTyOrigin, rustc_hir::def::DefKind, rustc_hir::def_id::DefId, @@ -287,10 +225,26 @@ impl_erasable_for_simple_types! { rustc_middle::mir::ConstQualifs, rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::AllocId, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'_>, + rustc_middle::mir::interpret::EvalToValTreeResult<'_>, + rustc_middle::mir::mono::MonoItemPartitions<'_>, + rustc_middle::traits::query::MethodAutoderefStepsResult<'_>, + rustc_middle::ty::AdtDef<'_>, rustc_middle::ty::AnonConstKind, rustc_middle::ty::AssocItem, rustc_middle::ty::Asyncness, + rustc_middle::ty::Binder<'_, ty::CoroutineWitnessTypes>>, + rustc_middle::ty::Binder<'_, ty::FnSig<'_>>, + rustc_middle::ty::ClosureTypeInfo<'_>, + rustc_middle::ty::Const<'_>, + rustc_middle::ty::ConstConditions<'_>, + rustc_middle::ty::GenericPredicates<'_>, + rustc_middle::ty::ImplTraitHeader<'_>, + rustc_middle::ty::ParamEnv<'_>, + rustc_middle::ty::SymbolName<'_>, + rustc_middle::ty::TypingEnv<'_>, rustc_middle::ty::Visibility, + rustc_middle::ty::inhabitedness::InhabitedPredicate<'_>, rustc_session::Limits, rustc_session::config::OptLevel, rustc_session::config::SymbolManglingVersion, @@ -302,36 +256,3 @@ impl_erasable_for_simple_types! { usize, // tidy-alphabetical-end } - -macro_rules! impl_erasable_for_single_lifetime_types { - ($($($fake_path:ident)::+),+ $(,)?) => { - $( - impl Erasable for $($fake_path)::+<'_> { - type Storage = [u8; size_of::<$($fake_path)::+<'_>>()]; - } - )* - } -} - -// For types containing a single lifetime and no other generics, e.g. -// `Foo<'tcx>`, the erased storage is `[u8; size_of::>()]`. -impl_erasable_for_single_lifetime_types! { - // tidy-alphabetical-start - rustc_hir::MaybeOwner, - rustc_middle::mir::interpret::EvalStaticInitializerRawResult, - rustc_middle::mir::interpret::EvalToValTreeResult, - rustc_middle::mir::mono::MonoItemPartitions, - rustc_middle::traits::query::MethodAutoderefStepsResult, - rustc_middle::ty::AdtDef, - rustc_middle::ty::ClosureTypeInfo, - rustc_middle::ty::Const, - rustc_middle::ty::ConstConditions, - rustc_middle::ty::GenericPredicates, - rustc_middle::ty::ImplTraitHeader, - rustc_middle::ty::ParamEnv, - rustc_middle::ty::SymbolName, - rustc_middle::ty::Ty, - rustc_middle::ty::TypingEnv, - rustc_middle::ty::inhabitedness::InhabitedPredicate, - // tidy-alphabetical-end -} From 4f03262c8ac4b977cc3dd716bf2a6ffaf8864c49 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 15:30:34 +1100 Subject: [PATCH 31/40] Use `impl_erasable_for_types_with_no_type_params!` even more. Some of the hand-written `Erasable` impls only match a single type in practice. It's easier to just list the concrete types in `impl_erasable_for_types_with_no_type_params!`. --- compiler/rustc_middle/src/query/erase.rs | 34 ++++++------------------ 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 54fe858e4809f..53ec0584ae599 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -10,12 +10,12 @@ use std::intrinsics::transmute_unchecked; use std::mem::MaybeUninit; use rustc_ast::tokenstream::TokenStream; +use rustc_data_structures::steal::Steal; use rustc_span::{ErrorGuaranteed, Spanned}; use crate::mir::mono::{MonoItem, NormalizationErrorInMono}; -use crate::traits::solve; use crate::ty::{self, Ty, TyCtxt}; -use crate::{mir, traits}; +use crate::{mir, thir, traits}; /// Internal implementation detail of [`Erased`]. #[derive(Copy, Clone)] @@ -123,26 +123,10 @@ impl Erasable for Result<&'_ T, ErrorGuaranteed> { type Storage = [u8; size_of::>()]; } -impl Erasable for Result<&'_ T, traits::CodegenObligationError> { - type Storage = [u8; size_of::>()]; -} - -impl Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { - type Storage = [u8; size_of::>>()]; -} - -impl Erasable for Result<(&'_ T, crate::thir::ExprId), ErrorGuaranteed> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for Option<&'_ T> { type Storage = [u8; size_of::>()]; } -impl Erasable for Option<&'_ [T]> { - type Storage = [u8; size_of::>()]; -} - impl Erasable for ty::EarlyBinder<'_, T> { type Storage = T::Storage; } @@ -151,14 +135,6 @@ impl Erasable for (&'_ T0, &'_ T1) { type Storage = [u8; size_of::<(&'_ (), &'_ ())>()]; } -impl Erasable for (solve::QueryResult<'_>, &'_ T0) { - type Storage = [u8; size_of::<(solve::QueryResult<'_>, &'_ ())>()]; -} - -impl Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) { - type Storage = [u8; size_of::<(&'_ (), Result<(), ErrorGuaranteed>)>()]; -} - macro_rules! impl_erasable_for_types_with_no_type_params { ($($ty:ty),+ $(,)?) => { $( @@ -173,8 +149,11 @@ macro_rules! impl_erasable_for_types_with_no_type_params { // `[u8; size_of::()]`. ('_ lifetimes are allowed.) impl_erasable_for_types_with_no_type_params! { // tidy-alphabetical-start + (&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>), (), + (traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe>), Option<&'_ OsStr>, + Option<&'_ [rustc_hir::PreciseCapturingArgKind]>, Option<(mir::ConstValue, Ty<'_>)>, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option, @@ -198,7 +177,10 @@ impl_erasable_for_types_with_no_type_params! { Option>, Option, Result<&'_ TokenStream, ()>, + Result<&'_ rustc_target::callconv::FnAbi<'_, Ty<'_>>, &'_ ty::layout::FnAbiError<'_>>, + Result<&'_ traits::ImplSource<'_, ()>, traits::CodegenObligationError>, Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop>, + Result<(&'_ Steal>, thir::ExprId), ErrorGuaranteed>, Result<(&'_ [Spanned>], &'_ [Spanned>]), NormalizationErrorInMono>, Result<(), ErrorGuaranteed>, Result>>, ErrorGuaranteed>, From 735c3e457e54f3c152c46047af2d9aff676ec4f8 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Wed, 25 Mar 2026 09:27:46 +0300 Subject: [PATCH 32/40] Add const type ICE test --- tests/ui/delegation/generics/const-type-ice-154334.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ui/delegation/generics/const-type-ice-154334.rs diff --git a/tests/ui/delegation/generics/const-type-ice-154334.rs b/tests/ui/delegation/generics/const-type-ice-154334.rs new file mode 100644 index 0000000000000..91cf1d3a0a639 --- /dev/null +++ b/tests/ui/delegation/generics/const-type-ice-154334.rs @@ -0,0 +1,11 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib + +#![feature(min_generic_const_args)] +#![feature(fn_delegation)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] +trait Trait<'a, T, const N: str> { + fn foo<'v, A, B>(&self) {} +} +reuse Trait::foo; From 86aac98cfcc709b989d1355e48d6210dac5b2b08 Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Wed, 25 Mar 2026 07:30:12 +0000 Subject: [PATCH 33/40] install-template.sh: Optimize by using Bourne shell builtins. This replaces forking separate processes and using "cut" with Bourne shell builtin operations for "remove largest suffix pattern" and "remove smallest prefix pattern" operations. --- src/tools/rust-installer/install-template.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh index c4f0c618a52de..7079e29eefff9 100644 --- a/src/tools/rust-installer/install-template.sh +++ b/src/tools/rust-installer/install-template.sh @@ -433,8 +433,8 @@ uninstall_components() { local _directive while read _directive; do - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` + local _command="${_directive%%:*}" + local _file="${_directive#*:}" # Sanity checks if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi @@ -541,8 +541,8 @@ install_components() { local _directive while read _directive; do - local _command=`echo $_directive | cut -f1 -d:` - local _file=`echo $_directive | cut -f2 -d:` + local _command="${_directive%%:*}" + local _file="${_directive#*:}" # Sanity checks if [ ! -n "$_command" ]; then critical_err "malformed installation directive"; fi From 7cb28c980dc5893c33a51be816f625cf695e4755 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 25 Mar 2026 16:59:43 +0800 Subject: [PATCH 34/40] fromrangeiter-overflow-checks: accept optional `signext` for argument On some targets such as LoongArch64 and RISCV64, the ABI requires sign-extension for 32-bit integer arguments, so LLVM may emit the `signext` attribute for the `%range` parameter. The existing CHECK pattern required the argument to be exactly `i32 noundef %range`, causing the test to fail on those targets. Allow an optional `signext` attribute in the CHECK pattern so the test passes consistently across architectures without affecting the intended codegen validation. --- tests/codegen-llvm/fromrangeiter-overflow-checks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs index 455c81c633407..e1e521103b574 100644 --- a/tests/codegen-llvm/fromrangeiter-overflow-checks.rs +++ b/tests/codegen-llvm/fromrangeiter-overflow-checks.rs @@ -19,7 +19,7 @@ pub unsafe fn rangefrom_increments(range: RangeFrom) -> RangeFrom { // Iterator is contained entirely within this function, so the optimizer should // be able to see that `exhausted` is never set and optimize out any branches. - // CHECK: i32 noundef %range + // CHECK: i32 noundef {{(signext )?}}%range // DEBUG: switch i32 %range // DEBUG: call core::panicking::panic_const::panic_const_add_overflow // DEBUG: unreachable From 11a338deb6884f72f3d3558d810e9b025de23167 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Wed, 25 Mar 2026 12:08:31 +0300 Subject: [PATCH 35/40] Fix nested zero-args delegation ICE --- compiler/rustc_ast_lowering/src/delegation.rs | 11 +++++ tests/ui/delegation/explicit-paths-pass.rs | 4 -- tests/ui/delegation/inner-attr.rs | 1 + tests/ui/delegation/inner-attr.stderr | 22 +++++++++- .../zero-args-delegations-ice-154332.rs | 30 +++++++++++++ .../zero-args-delegations-ice-154332.stderr | 43 +++++++++++++++++++ 6 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 tests/ui/delegation/zero-args-delegations-ice-154332.rs create mode 100644 tests/ui/delegation/zero-args-delegations-ice-154332.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 03acf40ef5fee..022f9e3c83f18 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -432,6 +432,17 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { args.push(arg); } + // If we have no params in signature function but user still wrote some code in + // delegation body, then add this code as first arg, eventually an error will be shown, + // also nested delegations may need to access information about this code (#154332), + // so it is better to leave this code as opposed to bodies of extern functions, + // which are completely erased from existence. + if param_count == 0 + && let Some(block) = block + { + args.push(this.lower_target_expr(&block)); + } + let final_expr = this.finalize_body_lowering(delegation, args, generics, span); (this.arena.alloc_from_iter(parameters), final_expr) diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index dd0ee2c732f59..7efbb37951856 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -17,11 +17,8 @@ impl Trait for F {} mod to_reuse { pub fn foo(x: i32) -> i32 { x + 1 } - pub fn zero_args() -> i32 { 15 } } -reuse to_reuse::zero_args { self } - struct S(F); impl Trait for S { reuse Trait::bar { self.0 } @@ -49,5 +46,4 @@ fn main() { #[inline] reuse to_reuse::foo; assert_eq!(43, foo(42)); - assert_eq!(15, zero_args()); } diff --git a/tests/ui/delegation/inner-attr.rs b/tests/ui/delegation/inner-attr.rs index 6c996807d6ba8..501118713d123 100644 --- a/tests/ui/delegation/inner-attr.rs +++ b/tests/ui/delegation/inner-attr.rs @@ -4,5 +4,6 @@ fn a() {} reuse a as b { #![rustc_dummy] self } //~ ERROR an inner attribute is not permitted in this context +//~^ ERROR: this function takes 0 arguments but 1 argument was supplied fn main() {} diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr index 257ab760ffc1a..226a48ecf9a4b 100644 --- a/tests/ui/delegation/inner-attr.stderr +++ b/tests/ui/delegation/inner-attr.stderr @@ -3,11 +3,29 @@ error: an inner attribute is not permitted in this context | LL | reuse a as b { #![rustc_dummy] self } | ^^^^^^^^^^^^^^^ -LL | +... LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -error: aborting due to 1 previous error +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/inner-attr.rs:6:7 + | +LL | reuse a as b { #![rustc_dummy] self } + | ^ ---- unexpected argument + | +note: function defined here + --> $DIR/inner-attr.rs:4:4 + | +LL | fn a() {} + | ^ +help: remove the extra argument + | +LL - reuse a as b { #![rustc_dummy] self } +LL + reuse self } + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/zero-args-delegations-ice-154332.rs b/tests/ui/delegation/zero-args-delegations-ice-154332.rs new file mode 100644 index 0000000000000..c684803014ad7 --- /dev/null +++ b/tests/ui/delegation/zero-args-delegations-ice-154332.rs @@ -0,0 +1,30 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod test_ice { + fn a() {} + + reuse a as b { //~ ERROR: this function takes 0 arguments but 1 argument was supplied + let closure = || { + fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} + + reuse foo:: as bar; + bar(&"".to_string(), &"".to_string()); + }; + + closure(); + } +} + +mod test_2 { + mod to_reuse { + pub fn zero_args() -> i32 { + 15 + } + } + + reuse to_reuse::zero_args { self } + //~^ ERROR: this function takes 0 arguments but 1 argument was supplied +} + +fn main() {} diff --git a/tests/ui/delegation/zero-args-delegations-ice-154332.stderr b/tests/ui/delegation/zero-args-delegations-ice-154332.stderr new file mode 100644 index 0000000000000..dcac56e0b2ba9 --- /dev/null +++ b/tests/ui/delegation/zero-args-delegations-ice-154332.stderr @@ -0,0 +1,43 @@ +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/zero-args-delegations-ice-154332.rs:7:11 + | +LL | reuse a as b { + | ___________^______- +LL | | let closure = || { +LL | | fn foo<'a, 'b, T: Clone, const N: usize, U: Clone>(_t: &'a T, _u: &'b U) {} +... | +LL | | closure(); +LL | | } + | |_____- unexpected argument of type `()` + | +note: function defined here + --> $DIR/zero-args-delegations-ice-154332.rs:5:8 + | +LL | fn a() {} + | ^ +help: remove the extra argument + | +LL - reuse a as b { +LL + reuse { + | + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/zero-args-delegations-ice-154332.rs:26:21 + | +LL | reuse to_reuse::zero_args { self } + | ^^^^^^^^^ ---- unexpected argument + | +note: function defined here + --> $DIR/zero-args-delegations-ice-154332.rs:21:16 + | +LL | pub fn zero_args() -> i32 { + | ^^^^^^^^^ +help: remove the extra argument + | +LL - reuse to_reuse::zero_args { self } +LL + reuse to_reuse::zero_argself } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0061`. From bca30d482866d6f1471f7585fe2875b29a6e4f64 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Mon, 23 Mar 2026 10:46:50 +0100 Subject: [PATCH 36/40] add issue link comments and bless --- .../static-cannot-use-local-variable.fixed | 2 ++ .../static-cannot-use-local-variable.rs | 2 ++ .../static-cannot-use-local-variable.stderr | 2 +- .../static-in-fn-cannot-use-param.fixed | 4 +++- .../statics/static-in-fn-cannot-use-param.rs | 4 +++- .../static-in-fn-cannot-use-param.stderr | 2 +- .../static-in-method-cannot-use-self.rs | 18 +++++++++------- .../static-in-method-cannot-use-self.stderr | 10 ++++----- .../static-lazy-init-with-arena-set.rs | 21 ++++++++++++------- .../static-lazy-init-with-arena-set.stderr | 8 +++---- .../statics/static-mut-borrow-of-temporary.rs | 2 ++ .../static-mut-borrow-of-temporary.stderr | 4 ++-- .../static-mut-with-assoc-type-field.rs | 4 +++- .../static-ref-deref-non-const-trait.rs | 9 ++++++-- .../static-ref-deref-non-const-trait.stderr | 2 +- 15 files changed, 60 insertions(+), 34 deletions(-) diff --git a/tests/ui/statics/static-cannot-use-local-variable.fixed b/tests/ui/statics/static-cannot-use-local-variable.fixed index 2a6e0829bc0f5..df9dfb7a33173 100644 --- a/tests/ui/statics/static-cannot-use-local-variable.fixed +++ b/tests/ui/statics/static-cannot-use-local-variable.fixed @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3521 +//! //@ run-rustfix fn main() { let foo = 100; diff --git a/tests/ui/statics/static-cannot-use-local-variable.rs b/tests/ui/statics/static-cannot-use-local-variable.rs index bd82202006545..0269f9e6e8964 100644 --- a/tests/ui/statics/static-cannot-use-local-variable.rs +++ b/tests/ui/statics/static-cannot-use-local-variable.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3521 +//! //@ run-rustfix fn main() { let foo = 100; diff --git a/tests/ui/statics/static-cannot-use-local-variable.stderr b/tests/ui/statics/static-cannot-use-local-variable.stderr index ecf1ad0403d3e..350c38480ed7e 100644 --- a/tests/ui/statics/static-cannot-use-local-variable.stderr +++ b/tests/ui/statics/static-cannot-use-local-variable.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3521-2.rs:5:23 + --> $DIR/static-cannot-use-local-variable.rs:7:23 | LL | static y: isize = foo + 1; | ^^^ non-constant value diff --git a/tests/ui/statics/static-in-fn-cannot-use-param.fixed b/tests/ui/statics/static-in-fn-cannot-use-param.fixed index bf100755b9068..bf6df45a25798 100644 --- a/tests/ui/statics/static-in-fn-cannot-use-param.fixed +++ b/tests/ui/statics/static-in-fn-cannot-use-param.fixed @@ -1,6 +1,8 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! //@ run-rustfix #![allow(unused_variables, dead_code)] -fn f(x:isize) { +fn f(x: isize) { let child: isize = x + 1; //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/statics/static-in-fn-cannot-use-param.rs b/tests/ui/statics/static-in-fn-cannot-use-param.rs index 375178172bb08..bd121a7045dd8 100644 --- a/tests/ui/statics/static-in-fn-cannot-use-param.rs +++ b/tests/ui/statics/static-in-fn-cannot-use-param.rs @@ -1,6 +1,8 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! //@ run-rustfix #![allow(unused_variables, dead_code)] -fn f(x:isize) { +fn f(x: isize) { static child: isize = x + 1; //~^ ERROR attempt to use a non-constant value in a constant } diff --git a/tests/ui/statics/static-in-fn-cannot-use-param.stderr b/tests/ui/statics/static-in-fn-cannot-use-param.stderr index f87514ba83b04..67890de71af6c 100644 --- a/tests/ui/statics/static-in-fn-cannot-use-param.stderr +++ b/tests/ui/statics/static-in-fn-cannot-use-param.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3668-2.rs:4:27 + --> $DIR/static-in-fn-cannot-use-param.rs:6:27 | LL | static child: isize = x + 1; | ^ non-constant value diff --git a/tests/ui/statics/static-in-method-cannot-use-self.rs b/tests/ui/statics/static-in-method-cannot-use-self.rs index 0e1f19a75baeb..a5d6feae7e913 100644 --- a/tests/ui/statics/static-in-method-cannot-use-self.rs +++ b/tests/ui/statics/static-in-method-cannot-use-self.rs @@ -1,14 +1,18 @@ -struct P { child: Option> } +//! Regression test for https://github.com/rust-lang/rust/issues/3668 +//! +struct P { + child: Option>, +} trait PTrait { - fn getChildOption(&self) -> Option>; + fn getChildOption(&self) -> Option>; } impl PTrait for P { - fn getChildOption(&self) -> Option> { - static childVal: Box

= self.child.get(); - //~^ ERROR attempt to use a non-constant value in a constant - panic!(); - } + fn getChildOption(&self) -> Option> { + static childVal: Box

= self.child.get(); + //~^ ERROR attempt to use a non-constant value in a constant + panic!(); + } } fn main() {} diff --git a/tests/ui/statics/static-in-method-cannot-use-self.stderr b/tests/ui/statics/static-in-method-cannot-use-self.stderr index 06e0192d9574c..d5db956cf16f3 100644 --- a/tests/ui/statics/static-in-method-cannot-use-self.stderr +++ b/tests/ui/statics/static-in-method-cannot-use-self.stderr @@ -1,13 +1,13 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/issue-3668.rs:8:34 + --> $DIR/static-in-method-cannot-use-self.rs:12:35 | -LL | static childVal: Box

= self.child.get(); - | ^^^^ non-constant value +LL | static childVal: Box

= self.child.get(); + | ^^^^ non-constant value | help: consider using `let` instead of `static` | -LL - static childVal: Box

= self.child.get(); -LL + let childVal: Box

= self.child.get(); +LL - static childVal: Box

= self.child.get(); +LL + let childVal: Box

= self.child.get(); | error: aborting due to 1 previous error diff --git a/tests/ui/statics/static-lazy-init-with-arena-set.rs b/tests/ui/statics/static-lazy-init-with-arena-set.rs index 68b4d28aae3ba..009d1d9393605 100644 --- a/tests/ui/statics/static-lazy-init-with-arena-set.rs +++ b/tests/ui/statics/static-lazy-init-with-arena-set.rs @@ -1,11 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/39367 +//! +//! Tests that lazy static initialization using `Once` and `transmute` +//! works correctly with a struct that has a default type parameter. //@ run-pass use std::ops::Deref; -struct ArenaSet::Target>(U, &'static V) - where V: 'static + ?Sized; +struct ArenaSet::Target>(U, &'static V) +where + V: 'static + ?Sized; -static Z: [u8; 4] = [1,2,3,4]; +static Z: [u8; 4] = [1, 2, 3, 4]; fn arena() -> &'static ArenaSet> { fn __static_ref_initialize() -> ArenaSet> { @@ -13,17 +18,17 @@ fn arena() -> &'static ArenaSet> { } unsafe { use std::sync::Once; - fn require_sync(_: &T) { } + fn require_sync(_: &T) {} unsafe fn __stability() -> &'static ArenaSet> { use std::mem::transmute; static mut DATA: *const ArenaSet> = std::ptr::null_mut(); static mut ONCE: Once = Once::new(); ONCE.call_once(|| { - //~^ WARN creating a shared reference to mutable static [static_mut_refs] - DATA = transmute - ::>>, *const ArenaSet>> - (Box::new(__static_ref_initialize())); + //~^ WARN creating a shared reference to mutable static [static_mut_refs] + DATA = transmute::>>, *const ArenaSet>>(Box::new( + __static_ref_initialize(), + )); }); &*DATA diff --git a/tests/ui/statics/static-lazy-init-with-arena-set.stderr b/tests/ui/statics/static-lazy-init-with-arena-set.stderr index e94c961f431d1..134129f814aa7 100644 --- a/tests/ui/statics/static-lazy-init-with-arena-set.stderr +++ b/tests/ui/statics/static-lazy-init-with-arena-set.stderr @@ -1,11 +1,11 @@ warning: creating a shared reference to mutable static - --> $DIR/issue-39367.rs:22:13 + --> $DIR/static-lazy-init-with-arena-set.rs:27:13 | LL | / ONCE.call_once(|| { LL | | -LL | | DATA = transmute -LL | | ::>>, *const ArenaSet>> -LL | | (Box::new(__static_ref_initialize())); +LL | | DATA = transmute::>>, *const ArenaSet>>(Box::new( +LL | | __static_ref_initialize(), +LL | | )); LL | | }); | |______________^ shared reference to mutable static | diff --git a/tests/ui/statics/static-mut-borrow-of-temporary.rs b/tests/ui/statics/static-mut-borrow-of-temporary.rs index e15f0b52da2f4..8f679d27059a9 100644 --- a/tests/ui/statics/static-mut-borrow-of-temporary.rs +++ b/tests/ui/statics/static-mut-borrow-of-temporary.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/46604 +//! static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR mutable borrows of temporaries fn write>(buffer: T) { } diff --git a/tests/ui/statics/static-mut-borrow-of-temporary.stderr b/tests/ui/statics/static-mut-borrow-of-temporary.stderr index 21abc498de120..a3d06011bbfb3 100644 --- a/tests/ui/statics/static-mut-borrow-of-temporary.stderr +++ b/tests/ui/statics/static-mut-borrow-of-temporary.stderr @@ -1,5 +1,5 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed - --> $DIR/issue-46604.rs:1:25 + --> $DIR/static-mut-borrow-of-temporary.rs:3:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | ^^^^^^^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary @@ -9,7 +9,7 @@ LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; = help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut` error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item - --> $DIR/issue-46604.rs:6:5 + --> $DIR/static-mut-borrow-of-temporary.rs:8:5 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | --------------------- this `static` cannot be written to diff --git a/tests/ui/statics/static-mut-with-assoc-type-field.rs b/tests/ui/statics/static-mut-with-assoc-type-field.rs index 508009337a5a5..347c50e1e3b61 100644 --- a/tests/ui/statics/static-mut-with-assoc-type-field.rs +++ b/tests/ui/statics/static-mut-with-assoc-type-field.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/29821 +//! //@ build-pass pub trait Foo { @@ -5,7 +7,7 @@ pub trait Foo { } pub struct Bar { - id: F::FooAssoc + id: F::FooAssoc, } pub struct Baz; diff --git a/tests/ui/statics/static-ref-deref-non-const-trait.rs b/tests/ui/statics/static-ref-deref-non-const-trait.rs index d40b869cd0cd8..6d7b375ecb101 100644 --- a/tests/ui/statics/static-ref-deref-non-const-trait.rs +++ b/tests/ui/statics/static-ref-deref-non-const-trait.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/25901 +//! struct A; struct B; @@ -8,7 +10,10 @@ use std::ops::Deref; impl Deref for A { type Target = B; - fn deref(&self)->&B { static B_: B = B; &B_ } + fn deref(&self) -> &B { + static B_: B = B; + &B_ + } } -fn main(){} +fn main() {} diff --git a/tests/ui/statics/static-ref-deref-non-const-trait.stderr b/tests/ui/statics/static-ref-deref-non-const-trait.stderr index 9b65366b969a5..88ddffecc928b 100644 --- a/tests/ui/statics/static-ref-deref-non-const-trait.stderr +++ b/tests/ui/statics/static-ref-deref-non-const-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `A: const Deref` is not satisfied - --> $DIR/issue-25901.rs:4:24 + --> $DIR/static-ref-deref-non-const-trait.rs:6:24 | LL | static S: &'static B = &A; | ^^ From c2383b53a26fe3f0108d20c94dd171c1faf4cfd2 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Wed, 25 Mar 2026 13:04:03 +0300 Subject: [PATCH 37/40] Don't propagate synthetic params, remove lifetime hacks --- .../src/delegation/generics.rs | 3 +-- compiler/rustc_hir_analysis/src/delegation.rs | 10 +------ .../generics/mapping/free-to-free-pass.rs | 22 +++++++-------- .../generics/synth-params-ice-143498.rs | 27 +++++++++++++++++++ .../generics/synth-params-ice-143498.stderr | 27 +++++++++++++++++++ 5 files changed, 66 insertions(+), 23 deletions(-) create mode 100644 tests/ui/delegation/generics/synth-params-ice-143498.rs create mode 100644 tests/ui/delegation/generics/synth-params-ice-143498.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index ee1ac9aa5cd8d..4e960e3b9290c 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -337,7 +337,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // HACK: for now we generate predicates such that all lifetimes are early bound, // we can not not generate early-bound lifetimes, but we can't know which of them // are late-bound at this level of compilation. - // FIXME(fn_delegation): proper support for late bound lifetimes. let predicates = self.arena.alloc_from_iter(params.iter().filter_map(|p| { p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span)) @@ -391,7 +390,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { self.arena.alloc(hir::GenericArgs { args: self.arena.alloc_from_iter(params.iter().filter_map(|p| { // Skip self generic arg, we do not need to propagate it. - if p.name.ident().name == kw::SelfUpper { + if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() { return None; } diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 0b142c0b76860..730288574e762 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -138,7 +138,6 @@ fn create_mapping<'tcx>( tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId, - args: &[ty::GenericArg<'tcx>], ) -> FxHashMap { let mut mapping: FxHashMap = Default::default(); @@ -176,13 +175,6 @@ fn create_mapping<'tcx>( } } - // If there are still unmapped lifetimes left and we are to map types and maybe self - // then skip them, now it is the case when we generated more lifetimes then needed. - // FIXME(fn_delegation): proper support for late bound lifetimes. - while args_index < args.len() && args[args_index].as_region().is_some() { - args_index += 1; - } - // If self after lifetimes insert mapping, relying that self is at 0 in sig parent. if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes) { mapping.insert(0, args_index as u32); @@ -511,7 +503,7 @@ fn create_folder_and_args<'tcx>( child_args: &'tcx [ty::GenericArg<'tcx>], ) -> (ParamIndexRemapper<'tcx>, Vec>) { let args = create_generic_args(tcx, sig_id, def_id, parent_args, child_args); - let remap_table = create_mapping(tcx, sig_id, def_id, &args); + let remap_table = create_mapping(tcx, sig_id, def_id); (ParamIndexRemapper { tcx, remap_table }, args) } diff --git a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs index aafdd5617d023..c67e4c02a1b78 100644 --- a/tests/ui/delegation/generics/mapping/free-to-free-pass.rs +++ b/tests/ui/delegation/generics/mapping/free-to-free-pass.rs @@ -78,18 +78,16 @@ mod test_6 { } } -// FIXME(fn_delegation): Uncomment this test when impl Traits in function params are supported - -// mod test_7 { -// fn foo(t: T, u: U, f: impl FnOnce(T, U) -> U) -> U { -// f(t, u) -// } +mod test_7 { + fn foo(t: T, u: U, f: impl FnOnce(T, U) -> U) -> U { + f(t, u) + } -// pub fn check() { -// reuse foo as bar; -// assert_eq!(bar::(1, 2, |x, y| y), 2); -// } -// } + pub fn check() { + reuse foo as bar; + assert_eq!(bar::(1, 2, |_, y| y), 2); + } +} // Testing reuse of local fn with delegation parent generic params specified, // late-bound lifetimes + types + consts, reusing with user args, @@ -126,7 +124,7 @@ pub fn main() { test_4::check::(); test_5::check::(); test_6::check::(); - // test_7::check(); + test_7::check(); test_8::check::(); test_9::check::(); } diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.rs b/tests/ui/delegation/generics/synth-params-ice-143498.rs new file mode 100644 index 0000000000000..652059b37ec6c --- /dev/null +++ b/tests/ui/delegation/generics/synth-params-ice-143498.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes +//@ edition:2024 + +#![feature(fn_delegation)] +#![feature(iter_advance_by)] +#![feature(iter_array_chunks)] +#![feature(iterator_try_collect)] +#![feature(iterator_try_reduce)] +#![feature(iter_collect_into)] +#![feature(iter_intersperse)] +#![feature(iter_is_partitioned)] +#![feature(iter_map_windows)] +#![feature(iter_next_chunk)] +#![feature(iter_order_by)] +#![feature(iter_partition_in_place)] +#![feature(trusted_random_access)] +#![feature(try_find)] +#![allow(incomplete_features)] + +impl X { +//~^ ERROR: cannot find type `X` in this scope + reuse< std::fmt::Debug as Iterator >::*; + //~^ ERROR: expected method or associated constant, found associated type `Iterator::Item` + //~| ERROR: expected a type, found a trait +} + +pub fn main() {} diff --git a/tests/ui/delegation/generics/synth-params-ice-143498.stderr b/tests/ui/delegation/generics/synth-params-ice-143498.stderr new file mode 100644 index 0000000000000..14b03991d9e62 --- /dev/null +++ b/tests/ui/delegation/generics/synth-params-ice-143498.stderr @@ -0,0 +1,27 @@ +error[E0425]: cannot find type `X` in this scope + --> $DIR/synth-params-ice-143498.rs:20:6 + | +LL | impl X { + | ^ not found in this scope + +error[E0575]: expected method or associated constant, found associated type `Iterator::Item` + --> $DIR/synth-params-ice-143498.rs:22:10 + | +LL | reuse< std::fmt::Debug as Iterator >::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a method or associated constant + +error[E0782]: expected a type, found a trait + --> $DIR/synth-params-ice-143498.rs:22:12 + | +LL | reuse< std::fmt::Debug as Iterator >::*; + | ^^^^^^^^^^^^^^^ + | +help: you can add the `dyn` keyword if you want a trait object + | +LL | reuse< dyn std::fmt::Debug as Iterator >::*; + | +++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0575, E0782. +For more information about an error, try `rustc --explain E0425`. From 2a543acbaf7739b547ca95c1d8d49758cfd510f4 Mon Sep 17 00:00:00 2001 From: Aryan Dubey Date: Wed, 25 Mar 2026 10:13:13 +0000 Subject: [PATCH 38/40] Moved and rename issue-50411 to tests/ui/mir/inliner-double-elaborate * Move issue-50411 to tests/ui/mir/inliner-double-elaborate * Addded the link for the issue to inliner-double-elaborate.rs * Fix tidy issues * Renamed to inliner-double-elaborate.rs --- .../{issues/issue-50411.rs => mir/inliner-double-elaborate.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/ui/{issues/issue-50411.rs => mir/inliner-double-elaborate.rs} (73%) diff --git a/tests/ui/issues/issue-50411.rs b/tests/ui/mir/inliner-double-elaborate.rs similarity index 73% rename from tests/ui/issues/issue-50411.rs rename to tests/ui/mir/inliner-double-elaborate.rs index 7fbbadac1e2bb..c6af573a58697 100644 --- a/tests/ui/issues/issue-50411.rs +++ b/tests/ui/mir/inliner-double-elaborate.rs @@ -1,4 +1,4 @@ -// Regression test for #50411: the MIR inliner was causing problems +// Regression test for https://github.com/rust-lang/rust/issues/50411: the MIR inliner was causing problems // here because it would inline promoted code (which had already had // elaborate-drops invoked on it) and then try to elaboate drops a // second time. Uncool. From 988633d72cedaf3d56bb9a77589fc08bb15b62b3 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 25 Mar 2026 12:37:03 +0100 Subject: [PATCH 39/40] re-enable enzyme/autodiff builds on dist-aarch64-apple --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index bff0046c97cb4..5909f29d52c14 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -509,7 +509,7 @@ auto: - name: dist-aarch64-apple env: SCRIPT: >- - ./x.py dist bootstrap + ./x.py dist bootstrap enzyme --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin From 01795c3eabbeca6e2a80c02385867ec055e3b7c7 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 24 Mar 2026 20:07:23 +0800 Subject: [PATCH 40/40] Init self_decl with a correct vis --- compiler/rustc_resolve/src/lib.rs | 33 +++++++++++---- tests/ui/use/pub-use-self-super-crate.rs | 24 +++++++++++ tests/ui/use/pub-use-self-super-crate.stderr | 43 ++++++++++++++++++++ tests/ui/use/use-path-segment-kw.rs | 2 +- 4 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 tests/ui/use/pub-use-self-super-crate.rs create mode 100644 tests/ui/use/pub-use-self-super-crate.stderr diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 10aa1b4019b3c..72d5cdcf1f3b6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -547,6 +547,13 @@ impl ModuleKind { ModuleKind::Def(.., name) => name, } } + + fn opt_def_id(&self) -> Option { + match self { + ModuleKind::Def(_, def_id, _) => Some(*def_id), + _ => None, + } + } } /// Combination of a symbol and its macros 2.0 normalized hygiene context. @@ -784,10 +791,7 @@ impl<'ra> Module<'ra> { } fn opt_def_id(self) -> Option { - match self.kind { - ModuleKind::Def(_, def_id, _) => Some(def_id), - _ => None, - } + self.kind.opt_def_id() } // `self` resolves to the first module ancestor that `is_normal`. @@ -1450,14 +1454,19 @@ impl<'ra> ResolverArenas<'ra> { &'ra self, parent: Option>, kind: ModuleKind, + vis: Visibility, expn_id: ExpnId, span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { let self_decl = match kind { - ModuleKind::Def(def_kind, def_id, _) => { - Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) - } + ModuleKind::Def(def_kind, def_id, _) => Some(self.new_def_decl( + Res::Def(def_kind, def_id), + vis, + span, + LocalExpnId::ROOT, + None, + )), ModuleKind::Block => None, }; Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( @@ -1639,6 +1648,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let graph_root = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), + Visibility::Public, ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), @@ -1648,6 +1658,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let empty_module = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), + Visibility::Public, ExpnId::root(), DUMMY_SP, true, @@ -1749,7 +1760,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + let vis = + kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); + let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude); self.local_modules.push(module); if let Some(def_id) = module.opt_def_id() { self.local_module_map.insert(def_id.expect_local(), module); @@ -1765,7 +1778,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + let vis = + kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); + let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude); self.extern_module_map.borrow_mut().insert(module.def_id(), module); module } diff --git a/tests/ui/use/pub-use-self-super-crate.rs b/tests/ui/use/pub-use-self-super-crate.rs new file mode 100644 index 0000000000000..1a799acb50fb9 --- /dev/null +++ b/tests/ui/use/pub-use-self-super-crate.rs @@ -0,0 +1,24 @@ +mod foo { + pub use self as this; + //~^ ERROR `self` is only public within the crate, and cannot be re-exported outside + + pub mod bar { + pub use super as parent; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use self::super as parent2; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use super::{self as parent3}; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + pub use self::{super as parent4}; + //~^ ERROR `super` is only public within the crate, and cannot be re-exported outside + + pub use crate as root; + pub use crate::{self as root2}; + pub use super::super as root3; + } +} + +pub use foo::*; +pub use foo::bar::*; + +pub fn main() {} diff --git a/tests/ui/use/pub-use-self-super-crate.stderr b/tests/ui/use/pub-use-self-super-crate.stderr new file mode 100644 index 0000000000000..3b336800a1800 --- /dev/null +++ b/tests/ui/use/pub-use-self-super-crate.stderr @@ -0,0 +1,43 @@ +error[E0365]: `self` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:2:13 + | +LL | pub use self as this; + | ^^^^^^^^^^^^ re-export of crate public `self` + | + = note: consider declaring type or module `self` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:6:17 + | +LL | pub use super as parent; + | ^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:8:17 + | +LL | pub use self::super as parent2; + | ^^^^^^^^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:10:25 + | +LL | pub use super::{self as parent3}; + | ^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error[E0365]: `super` is only public within the crate, and cannot be re-exported outside + --> $DIR/pub-use-self-super-crate.rs:12:24 + | +LL | pub use self::{super as parent4}; + | ^^^^^^^^^^^^^^^^ re-export of crate public `super` + | + = note: consider declaring type or module `super` with `pub` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0365`. diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs index be64f239b9fc3..164f645dc5c54 100644 --- a/tests/ui/use/use-path-segment-kw.rs +++ b/tests/ui/use/use-path-segment-kw.rs @@ -70,7 +70,7 @@ macro_rules! macro_dollar_crate { fn outer() {} -mod foo { +pub mod foo { pub mod bar { pub mod foobar { pub mod qux {