From e7d56c6d01a11cddc94d2f12edeb381bf4f0f579 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 14 Jan 2026 19:03:30 -0500 Subject: [PATCH 01/39] 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 9729bb2558d6e3a3e430304b18d7f5211ffc2427 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 11 Mar 2026 09:37:35 +0000 Subject: [PATCH 02/39] 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 03/39] 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 04/39] 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 05/39] 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 06/39] 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 07/39] 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 08/39] 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 09/39] 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 10/39] 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 11/39] 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 12/39] 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 13/39] 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 14/39] 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 1223441926fa226e55520f72ee0307ab32c783d9 Mon Sep 17 00:00:00 2001 From: Tayfun Bocek Date: Sun, 22 Mar 2026 17:18:47 +0300 Subject: [PATCH 15/39] Constify `NonNull::with_exposed_provenance` --- library/core/src/ptr/non_null.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8be7d3a9ae925..7399ee569eb3a 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -139,8 +139,9 @@ impl NonNull { /// /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[stable(feature = "nonnull_provenance", since = "1.89.0")] + #[rustc_const_unstable(feature = "const_nonnull_with_exposed_provenance", issue = "154215")] #[inline] - pub fn with_exposed_provenance(addr: NonZero) -> Self { + pub const fn with_exposed_provenance(addr: NonZero) -> Self { // SAFETY: we know `addr` is non-zero. unsafe { let ptr = crate::ptr::with_exposed_provenance_mut(addr.get()); From 2e30fefde60a9086ddb2d9600c87b87797da56cb Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Mon, 23 Mar 2026 10:25:45 +0100 Subject: [PATCH 16/39] 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 c0e6c763a94e440b247f4f23d3c2be289f313f21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2026 17:43:12 +0100 Subject: [PATCH 17/39] interpret: when passing an argument fails, point at that argument --- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/interpret/call.rs | 286 +++++++++--------- .../rustc_const_eval/src/interpret/stack.rs | 15 +- compiler/rustc_const_eval/src/lib.rs | 1 - .../libc_pthread_create_too_few_args.rs | 2 +- .../libc_pthread_create_too_few_args.stderr | 11 +- .../libc_pthread_create_too_many_args.rs | 2 +- .../libc_pthread_create_too_many_args.stderr | 11 +- .../arg_inplace_locals_alias.rs | 4 +- .../arg_inplace_locals_alias.stack.stderr | 13 +- .../arg_inplace_locals_alias.tree.stderr | 17 +- .../arg_inplace_locals_alias_ret.rs | 4 +- .../arg_inplace_locals_alias_ret.stack.stderr | 13 +- .../arg_inplace_locals_alias_ret.tree.stderr | 17 +- .../arg_inplace_mutate.stack.stderr | 4 +- .../arg_inplace_mutate.tree.stderr | 8 +- .../arg_inplace_observe_during.stack.stderr | 4 +- .../arg_inplace_observe_during.tree.stderr | 8 +- .../exported_symbol_wrong_arguments.rs | 4 +- .../exported_symbol_wrong_arguments.stderr | 9 +- .../return_pointer_aliasing_read.stack.stderr | 4 +- .../return_pointer_aliasing_read.tree.stderr | 8 +- ...return_pointer_aliasing_write.stack.stderr | 4 +- .../return_pointer_aliasing_write.tree.stderr | 8 +- ...nter_aliasing_write_tail_call.stack.stderr | 4 +- ...inter_aliasing_write_tail_call.tree.stderr | 8 +- .../abi_mismatch_array_vs_struct.rs | 4 +- .../abi_mismatch_array_vs_struct.stderr | 9 +- .../abi_mismatch_int_vs_float.rs | 4 +- .../abi_mismatch_int_vs_float.stderr | 9 +- .../abi_mismatch_raw_pointer.rs | 4 +- .../abi_mismatch_raw_pointer.stderr | 9 +- .../function_pointers/abi_mismatch_repr_C.rs | 2 +- .../abi_mismatch_repr_C.stderr | 9 +- .../abi_mismatch_return_type.rs | 4 +- .../abi_mismatch_return_type.stderr | 9 +- .../function_pointers/abi_mismatch_simple.rs | 4 +- .../abi_mismatch_simple.stderr | 9 +- .../abi_mismatch_too_few_args.rs | 4 +- .../abi_mismatch_too_few_args.stderr | 9 +- .../abi_mismatch_too_many_args.rs | 4 +- .../abi_mismatch_too_many_args.stderr | 9 +- .../function_pointers/abi_mismatch_vector.rs | 4 +- .../abi_mismatch_vector.stderr | 9 +- .../tests/fail/shims/ctor_wrong_ret_type.rs | 2 +- .../fail/shims/ctor_wrong_ret_type.stderr | 17 +- .../fail/tail_calls/signature-mismatch-arg.rs | 8 +- .../tail_calls/signature-mismatch-arg.stderr | 9 +- .../cast_fn_ptr_invalid_callee_arg.rs | 2 +- .../cast_fn_ptr_invalid_callee_arg.stderr | 9 +- .../cast_fn_ptr_invalid_caller_arg.rs | 4 +- .../cast_fn_ptr_invalid_caller_arg.stderr | 10 +- 52 files changed, 366 insertions(+), 281 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 2dbf2cc910580..d799e376e8bdf 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -88,7 +88,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( &ret.clone().into(), ReturnContinuation::Stop { cleanup: false }, )?; - ecx.storage_live_for_always_live_locals()?; + ecx.push_stack_frame_done()?; // The main interpreter loop. while ecx.step()? { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 0381571ef6dae..802aa9ef4645a 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -404,166 +404,158 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Push the "raw" frame -- this leaves locals uninitialized. self.push_stack_frame_raw(instance, body, destination, cont)?; + let preamble_span = self.frame().loc.unwrap_right(); // the span used for preamble errors + + trace!( + "caller ABI: {:#?}, args: {:#?}", + caller_fn_abi, + args.iter() + .map(|arg| ( + arg.layout().ty, + match arg { + FnArg::Copy(op) => format!("copy({op:?})"), + FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), + } + )) + .collect::>() + ); + trace!( + "spread_arg: {:?}, locals: {:#?}", + body.spread_arg, + body.args_iter() + .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,)) + .collect::>() + ); - // If an error is raised here, pop the frame again to get an accurate backtrace. - // To this end, we wrap it all in a `try` block. - let res: InterpResult<'tcx> = try { - trace!( - "caller ABI: {:#?}, args: {:#?}", - caller_fn_abi, - args.iter() - .map(|arg| ( - arg.layout().ty, - match arg { - FnArg::Copy(op) => format!("copy({op:?})"), - FnArg::InPlace(mplace) => format!("in-place({mplace:?})"), - } - )) - .collect::>() - ); - trace!( - "spread_arg: {:?}, locals: {:#?}", - body.spread_arg, - body.args_iter() - .map(|local| ( - local, - self.layout_of_local(self.frame(), local, None).unwrap().ty, - )) - .collect::>() - ); - - // In principle, we have two iterators: Where the arguments come from, and where - // they go to. - - // The "where they come from" part is easy, we expect the caller to do any special handling - // that might be required here (e.g. for untupling). - // If `with_caller_location` is set we pretend there is an extra argument (that - // we will not pass; our `caller_location` intrinsic implementation walks the stack instead). - assert_eq!( - args.len() + if with_caller_location { 1 } else { 0 }, - caller_fn_abi.args.len(), - "mismatch between caller ABI and caller arguments", - ); - let mut caller_args = args - .iter() - .zip(caller_fn_abi.args.iter()) - .filter(|arg_and_abi| !arg_and_abi.1.is_ignore()); - - // Now we have to spread them out across the callee's locals, - // taking into account the `spread_arg`. If we could write - // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ignored arguments. - let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); - // Determine whether there is a special VaList argument. This is always the - // last argument, and since arguments start at index 1 that's `arg_count`. - let va_list_arg = - callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); - for local in body.args_iter() { - // Construct the destination place for this argument. At this point all - // locals are still dead, so we cannot construct a `PlaceTy`. - let dest = mir::Place::from(local); - // `layout_of_local` does more than just the instantiation we need to get the - // type, but the result gets cached so this avoids calling the instantiation - // query *again* the next time this local is accessed. - let ty = self.layout_of_local(self.frame(), local, None)?.ty; - if Some(local) == va_list_arg { - // This is the last callee-side argument of a variadic function. - // This argument is a VaList holding the remaining caller-side arguments. - self.storage_live(local)?; - - let place = self.eval_place(dest)?; - let mplace = self.force_allocation(&place)?; - - // Consume the remaining arguments by putting them into the variable argument - // list. - let varargs = self.allocate_varargs( - &mut caller_args, - // "Ignored" arguments aren't actually passed, so the callee should also - // ignore them. (`pass_argument` does this for regular arguments.) - (&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()), - )?; - // When the frame is dropped, these variable arguments are deallocated. - self.frame_mut().va_list = varargs.clone(); - let key = self.va_list_ptr(varargs.into()); - - // Zero the VaList, so it is fully initialized. - self.write_bytes_ptr( - mplace.ptr(), - (0..mplace.layout.size.bytes()).map(|_| 0u8), - )?; + // In principle, we have two iterators: Where the arguments come from, and where + // they go to. - // Store the "key" pointer in the right field. - let key_mplace = self.va_list_key_field(&mplace)?; - self.write_pointer(key, &key_mplace)?; - } else if Some(local) == body.spread_arg { - // Make the local live once, then fill in the value field by field. - self.storage_live(local)?; - // Must be a tuple - let ty::Tuple(fields) = ty.kind() else { - span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") - }; - for (i, field_ty) in fields.iter().enumerate() { - let dest = dest.project_deeper( - &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], - *self.tcx, - ); - let (idx, callee_abi) = callee_args_abis.next().unwrap(); - self.pass_argument( - &mut caller_args, - callee_abi, - idx, - &dest, - field_ty, - /* already_live */ true, - )?; - } - } else { - // Normal argument. Cannot mark it as live yet, it might be unsized! + // The "where they come from" part is easy, we expect the caller to do any special handling + // that might be required here (e.g. for untupling). + // If `with_caller_location` is set we pretend there is an extra argument (that + // we will not pass; our `caller_location` intrinsic implementation walks the stack instead). + assert_eq!( + args.len() + if with_caller_location { 1 } else { 0 }, + caller_fn_abi.args.len(), + "mismatch between caller ABI and caller arguments", + ); + let mut caller_args = args + .iter() + .zip(caller_fn_abi.args.iter()) + .filter(|arg_and_abi| !arg_and_abi.1.is_ignore()); + + // Now we have to spread them out across the callee's locals, + // taking into account the `spread_arg`. If we could write + // this is a single iterator (that handles `spread_arg`), then + // `pass_argument` would be the loop body. It takes care to + // not advance `caller_iter` for ignored arguments. + let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); + // Determine whether there is a special VaList argument. This is always the + // last argument, and since arguments start at index 1 that's `arg_count`. + let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); + for local in body.args_iter() { + // Update the span that we show in case of an error to point to this argument. + self.frame_mut().loc = Right(body.local_decls[local].source_info.span); + // Construct the destination place for this argument. At this point all + // locals are still dead, so we cannot construct a `PlaceTy`. + let dest = mir::Place::from(local); + // `layout_of_local` does more than just the instantiation we need to get the + // type, but the result gets cached so this avoids calling the instantiation + // query *again* the next time this local is accessed. + let ty = self.layout_of_local(self.frame(), local, None)?.ty; + if Some(local) == va_list_arg { + // This is the last callee-side argument of a variadic function. + // This argument is a VaList holding the remaining caller-side arguments. + self.storage_live(local)?; + + let place = self.eval_place(dest)?; + let mplace = self.force_allocation(&place)?; + + // Consume the remaining arguments by putting them into the variable argument + // list. + let varargs = self.allocate_varargs( + &mut caller_args, + // "Ignored" arguments aren't actually passed, so the callee should also + // ignore them. (`pass_argument` does this for regular arguments.) + (&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()), + )?; + // When the frame is dropped, these variable arguments are deallocated. + self.frame_mut().va_list = varargs.clone(); + let key = self.va_list_ptr(varargs.into()); + + // Zero the VaList, so it is fully initialized. + self.write_bytes_ptr(mplace.ptr(), (0..mplace.layout.size.bytes()).map(|_| 0u8))?; + + // Store the "key" pointer in the right field. + let key_mplace = self.va_list_key_field(&mplace)?; + self.write_pointer(key, &key_mplace)?; + } else if Some(local) == body.spread_arg { + // Make the local live once, then fill in the value field by field. + self.storage_live(local)?; + // Must be a tuple + let ty::Tuple(fields) = ty.kind() else { + span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}") + }; + for (i, field_ty) in fields.iter().enumerate() { + let dest = dest.project_deeper( + &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], + *self.tcx, + ); let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, idx, &dest, - ty, - /* already_live */ false, + field_ty, + /* already_live */ true, )?; } + } else { + // Normal argument. Cannot mark it as live yet, it might be unsized! + let (idx, callee_abi) = callee_args_abis.next().unwrap(); + self.pass_argument( + &mut caller_args, + callee_abi, + idx, + &dest, + ty, + /* already_live */ false, + )?; } - // If the callee needs a caller location, pretend we consume one more argument from the ABI. - if instance.def.requires_caller_location(*self.tcx) { - callee_args_abis.next().unwrap(); - } - // Now we should have no more caller args or callee arg ABIs. - assert!( - callee_args_abis.next().is_none(), - "mismatch between callee ABI and callee body arguments" - ); - if caller_args.next().is_some() { - throw_ub_format!("calling a function with more arguments than it expected"); - } - // Don't forget to check the return type! - if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { - throw_ub!(AbiMismatchReturn { - caller_ty: caller_fn_abi.ret.layout.ty, - callee_ty: callee_fn_abi.ret.layout.ty - }); - } + } - // Protect return place for in-place return value passing. - // We only need to protect anything if this is actually an in-memory place. - if let Some(mplace) = destination_mplace { - M::protect_in_place_function_argument(self, &mplace)?; - } + // Don't forget to check the return type! + self.frame_mut().loc = Right(body.local_decls[mir::RETURN_PLACE].source_info.span); + if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { + throw_ub!(AbiMismatchReturn { + caller_ty: caller_fn_abi.ret.layout.ty, + callee_ty: callee_fn_abi.ret.layout.ty + }); + } + // Protect return place for in-place return value passing. + // We only need to protect anything if this is actually an in-memory place. + if let Some(mplace) = destination_mplace { + M::protect_in_place_function_argument(self, &mplace)?; + } - // Don't forget to mark "initially live" locals as live. - self.storage_live_for_always_live_locals()?; - }; - res.inspect_err_kind(|_| { - // Don't show the incomplete stack frame in the error stacktrace. - self.stack_mut().pop(); - }) + // For the final checks, use same span as preamble since it is unclear what else to do. + self.frame_mut().loc = Right(preamble_span); + // If the callee needs a caller location, pretend we consume one more argument from the ABI. + if instance.def.requires_caller_location(*self.tcx) { + callee_args_abis.next().unwrap(); + } + // Now we should have no more caller args or callee arg ABIs. + assert!( + callee_args_abis.next().is_none(), + "mismatch between callee ABI and callee body arguments" + ); + if caller_args.next().is_some() { + throw_ub_format!("calling a function with more arguments than it expected"); + } + + // Done! + self.push_stack_frame_done() } /// Initiate a call to this function -- pushing the stack frame and initializing the arguments. diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index b0f34264ad841..a73767264daba 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -381,7 +381,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let locals = IndexVec::from_elem(dead_local, &body.local_decls); let pre_frame = Frame { body, - loc: Right(body.span), // Span used for errors caused during preamble. + loc: Right(self.tcx.def_span(body.source.def_id())), // Span used for errors caused during preamble. return_cont, return_place: return_place.clone(), locals, @@ -408,7 +408,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Finish things up. M::after_stack_push(self)?; - self.frame_mut().loc = Left(mir::Location::START); // `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri // to put the "frame" span on a separate trace thread/line than other spans, to make the // visualization in easier to interpret. It is set to a value of @@ -466,9 +465,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - /// In the current stack frame, mark all locals as live that are not arguments and don't have - /// `Storage*` annotations (this includes the return place). - pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> { + /// Call this after `push_stack_frame_raw` and when all the other setup that needs to be done + /// is completed. + pub(crate) fn push_stack_frame_done(&mut self) -> InterpResult<'tcx> { + // Mark all locals as live that are not arguments and don't have `Storage*` annotations + // (this includes the return place, but not the arguments). self.storage_live(mir::RETURN_PLACE)?; let body = self.body(); @@ -478,6 +479,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.storage_live(local)?; } } + + // Get ready to execute the first instruction in the stack frame. + self.frame_mut().loc = Left(mir::Location::START); + interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index a9fff6d593261..33da1c5ecf738 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -5,7 +5,6 @@ #![feature(never_type)] #![feature(slice_ptr_get)] #![feature(trait_alias)] -#![feature(try_blocks)] #![feature(unqualified_local_imports)] #![feature(yeet_expr)] #![warn(unqualified_local_imports)] diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs index 6fec6500cc961..024537633383a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs @@ -5,6 +5,7 @@ use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { + //~^ERROR: calling a function with more arguments than it expected panic!() } @@ -16,7 +17,6 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - //~^ERROR: calling a function with more arguments than it expected 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr index 979a1a8337b52..e3509a2a6ee84 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr @@ -1,14 +1,17 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC | -LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code +LL | extern "C" fn thread_start() -> *mut libc::c_void { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: this is on thread `unnamed-ID` - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs index cb55b0f92ee6b..28fdb1d01384f 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs @@ -5,6 +5,7 @@ use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + //~^ERROR: calling a function with fewer arguments than it requires panic!() } @@ -16,7 +17,6 @@ fn main() { mem::transmute(thread_start); assert_eq!( libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - //~^ERROR: calling a function with fewer arguments than it requires 0 ); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr index e8ad65a74ac8e..d6504f6b97878 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr @@ -1,14 +1,17 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC | -LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code +LL | extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: this is on thread `unnamed-ID` - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC + | +LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs index b6cda6007536f..1fb597fdc02af 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs @@ -21,8 +21,6 @@ fn main() { // This specifically uses a type with scalar representation to tempt Miri to use the // efficient way of storing local variables (outside adressable memory). Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - //~[stack]^ ERROR: not granting access - //~[tree]| ERROR: /read access .* forbidden/ } after_call = { Return() @@ -32,6 +30,8 @@ fn main() { #[expect(unused_variables, unused_assignments)] fn callee(x: S, mut y: S) { + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /read access .* forbidden/ // With the setup above, if `x` and `y` are both moved, // then writing to `y` will change the value stored in `x`! y.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr index a86c68cebd233..14df4ebd11f57 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S, mut y: S) { + | ^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -14,8 +14,13 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a help: is this argument --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr index d62adeeb84200..7012c4f8aeada 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: read access through (root of the allocation) at ALLOC[0x0] is forbidden --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S, mut y: S) { + | ^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information @@ -17,14 +17,19 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | -LL | y.0 = 0; - | ^^^^^^^ +LL | fn callee(x: S, mut y: S) { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs index 3cb8ee2b407c4..b3d43ca63cb07 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs @@ -20,8 +20,6 @@ fn main() { // This specifically uses a type with scalar representation to tempt Miri to use the // efficient way of storing local variables (outside adressable memory). Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - //~[stack]^ ERROR: not granting access - //~[tree]| ERROR: /reborrow .* forbidden/ } after_call = { Return() @@ -30,5 +28,7 @@ fn main() { } fn callee(x: S) -> S { + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /reborrow .* forbidden/ x } diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr index 491d01cf42841..21fcfb96fd17d 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S) -> S { + | ^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -14,8 +14,13 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), help: is this argument --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr index 3c1038d364bb4..e4d4e87625a9e 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: reborrow through (root of the allocation) at ALLOC[0x0] is forbidden --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(x: S) -> S { + | ^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information @@ -17,14 +17,19 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | -LL | x - | ^ +LL | fn callee(x: S) -> S { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: stack backtrace: + 0: callee + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + 1: main + at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr index 952f2272f3bf6..c754acdd5ea1a 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: is this argument --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ = note: stack backtrace: 0: callee at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 095dc7e1a1fb5..c210d5c00524a 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | -LL | unsafe { ptr.write(S(0)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn callee(x: S, ptr: *mut S) { + | ^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: callee diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr index d625d1d1d034c..b7eb3c5e9cab1 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: is this argument --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ = note: stack backtrace: 0: change_arg at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index a01c040fe6f81..e79cf08b15bf4 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | -LL | x.0 = 0; - | ^^^^^^^ +LL | fn change_arg(mut x: S, ptr: *mut S) { + | ^^^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: change_arg diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs index a108944c5e434..81fa672d5229f 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.rs @@ -1,9 +1,9 @@ #[no_mangle] -fn foo() {} +fn foo() {} //~ ERROR: calling a function with more arguments than it expected fn main() { extern "Rust" { fn foo(_: i32); } - unsafe { foo(1) } //~ ERROR: calling a function with more arguments than it expected + unsafe { foo(1) } } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index 75c060ea51d4e..4c481e8d3cb96 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC | -LL | unsafe { foo(1) } - | ^^^^^^ Undefined Behavior occurred here +LL | fn foo() {} + | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: foo + at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC + 1: main + at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 73c562c94e951..5cf0fd40b58c1 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index 0dc137843c91c..cc5f4a812eebf 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 6654ddc12c29b..133aa8ca35a1f 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 6472dfd4f995a..fb87eea63102a 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index 79f4d2c69f3c2..07ed6d128215f 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -19,8 +19,8 @@ LL | | } help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | become myfun2(ptr) - | ^^^^^^^^^^^^^^^^^^ +LL | fn myfun(ptr: *mut i32) -> i32 { + | ^^^ = note: stack backtrace: 0: myfun2 at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index 82b898df45b2e..e3c5d6baf89f9 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -22,13 +22,13 @@ LL | | } help: the protected tag was created here, in the initial state Reserved --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^ help: the protected tag later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn myfun2(ptr: *mut i32) -> i32 { + | ^^^ = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference = note: stack backtrace: 0: myfun2 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs index 26f2e73dd7520..beb0f726568f1 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs @@ -12,10 +12,10 @@ struct S( type A = [i32; 4]; fn main() { - fn f(_: S) {} + fn f(_: S) {} //~ ERROR: type S passing argument of type [i32; 4] // These two types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::(f) }; - g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4] + g(Default::default()) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index 56e69e8466960..62ba807d7a952 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4] --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC | -LL | g(Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: S) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs index 0cca4a1323339..a40e5b44660df 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: f32) {} + fn f(_: f32) {} //~ ERROR: type f32 passing argument of type i32 let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: type f32 passing argument of type i32 + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index cbef9d27cdf9b..8147d009ff853 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f(_: f32) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs index 053a4a5f28459..8c2d0648cbf1d 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: *const [i32]) {} + fn f(_: *const [i32]) {} //~ ERROR: type *const [i32] passing argument of type *const i32 let g = unsafe { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32 + g(&42 as *const i32) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index cd14ea156a47f..f9195a869798c 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32 --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC | -LL | g(&42 as *const i32) - | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: *const [i32]) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs index f3dffcc4e8673..79485a27ee138 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs @@ -7,10 +7,10 @@ struct S1(NonZero); struct S2(i32); fn callee(_s: S2) {} +//~^ ERROR: type S2 passing argument of type S1 fn main() { let fnptr: fn(S2) = callee; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; fnptr(S1(NonZero::new(1).unwrap())); - //~^ ERROR: type S2 passing argument of type S1 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index 0e52dc02884ca..3e4be1e39fd94 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1 --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC | -LL | fnptr(S1(NonZero::new(1).unwrap())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn callee(_s: S2) {} + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: callee + at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs index 05b645cf75afa..8bf46af71e821 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { + fn f() -> u32 { //~ ERROR: type u32 passing return place of type () 42 } let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR: type u32 passing return place of type () + g() } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr index ba940902c8ce3..9f206189b6e03 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function with return type u32 passing return place of type () --> tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC | -LL | g() - | ^^^ Undefined Behavior occurred here +LL | fn f() -> u32 { + | ^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs index ca43c06008fd7..0b06496b2bfd8 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: (i32, i32)) {} + fn f(_: (i32, i32)) {} //~ ERROR: type (i32, i32) passing argument of type i32 let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: type (i32, i32) passing argument of type i32 + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr index ab9c0e720304b..b85ac39faa8f4 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f(_: (i32, i32)) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs index 920fb51abb644..fc9a107f0c734 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.rs @@ -1,7 +1,7 @@ fn main() { - fn f(_: (i32, i32)) {} + fn f(_: (i32, i32)) {} //~ ERROR: calling a function with fewer arguments than it requires let g = unsafe { std::mem::transmute::(f) }; - g() //~ ERROR: calling a function with fewer arguments than it requires + g() } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr index 06e6ccbd7bf25..271ec64475eef 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires --> tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC | -LL | g() - | ^^^ Undefined Behavior occurred here +LL | fn f(_: (i32, i32)) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs index c0e96a43cc522..744c5289e018d 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.rs @@ -1,7 +1,7 @@ fn main() { - fn f() {} + fn f() {} //~ ERROR: calling a function with more arguments than it expected let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR: calling a function with more arguments than it expected + g(42) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr index d343eb8f25994..1721f0f9428cc 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: calling a function with more arguments than it expected --> tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC | -LL | g(42) - | ^^^^^ Undefined Behavior occurred here +LL | fn f() {} + | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs index dedcaac614272..ed5b4696dd0f4 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs @@ -2,10 +2,10 @@ use std::simd; fn main() { - fn f(_: simd::u32x8) {} + fn f(_: simd::u32x8) {} //~ ERROR: type std::simd::Simd passing argument of type std::simd::Simd // These two vector types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::(f) }; - g(Default::default()) //~ ERROR: type std::simd::Simd passing argument of type std::simd::Simd + g(Default::default()) } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr index 1176589a5f4a7..59823fad522b1 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd passing argument of type std::simd::Simd --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC | -LL | g(Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_: simd::u32x8) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::f + at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC + 1: main + at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs index 3629e4387e7fd..1e10f682e71e6 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.rs @@ -1,4 +1,5 @@ unsafe extern "C" fn ctor() -> i32 { + //~^ERROR: calling a function with return type i32 passing return place of type () 0 } @@ -30,7 +31,6 @@ macro_rules! ctor { )] #[used] static $ident: unsafe extern "C" fn() -> i32 = $ctor; - //~^ERROR: calling a function with return type i32 passing return place of type () }; } diff --git a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr index 1b4cd23e41a8e..4e474dbadcb69 100644 --- a/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr +++ b/src/tools/miri/tests/fail/shims/ctor_wrong_ret_type.stderr @@ -1,18 +1,21 @@ error: Undefined Behavior: calling a function with return type i32 passing return place of type () --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC | -LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code -... -LL | ctor! { CTOR = ctor } - | --------------------- in this macro invocation +LL | unsafe extern "C" fn ctor() -> i32 { + | ^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri - = note: this error occurred while pushing a call frame onto an empty stack - = note: the span indicates which code caused the function to be called, but may not be the literal call site +note: the current function got called indirectly due to this code + --> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC + | +LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | ctor! { CTOR = ctor } + | --------------------- in this macro invocation = note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs index 36bd1e99cfbc3..e747bfdbf5207 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs @@ -2,16 +2,14 @@ #![allow(incomplete_features)] fn main() { - // FIXME(explicit_tail_calls): - // the error should point to `become g(x)`, - // but tail calls mess up the backtrace it seems like... f(0); - //~^ error: type i32 passing argument of type u32 } fn f(x: u32) { let g = unsafe { std::mem::transmute::(g) }; - become g(x); + become g(x); // FIXME ideally this should also be involved in the error somehow, + // but by the time we pass the argument, `f`'s stackframe has already been popped. } fn g(_: i32) {} +//~^ error: type i32 passing argument of type u32 diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr index f5eccaeba666d..9c10db8e5fe41 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -1,13 +1,18 @@ error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC | -LL | f(0); - | ^^^^ Undefined Behavior occurred here +LL | fn g(_: i32) {} + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: g + at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC + 1: main + at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs index 6ab73569c6347..8657e3ad679d3 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs @@ -5,9 +5,9 @@ fn main() { // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f(_x: &i32) {} + //~^ ERROR: encountered a null reference let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR: encountered a null reference } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index 02e0ebe8abe68..aa797f64ce20b 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,11 +1,16 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference --> tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(_x: &i32) {} + | ^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::f + at tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC + 1: main + at tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs index 7ca26bffc14fd..7bc26237576a3 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -5,7 +5,7 @@ use std::intrinsics::mir::*; use std::num::NonZero; use std::ptr; -fn f(c: u32) { +fn f(c: u32) { //~ERROR: expected something greater or equal to 1 println!("{c}"); } @@ -20,7 +20,7 @@ fn call(f: fn(NonZero)) { let tmp = ptr::addr_of!(c); let ptr = tmp as *const NonZero; // The call site now is a `NonZero` to `u32` transmute. - Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1 + Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) } retblock = { Return() diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index 3b23a6cc4e85f..e54210981e083 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -1,15 +1,17 @@ error: Undefined Behavior: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 --> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | -LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | fn f(c: u32) { + | ^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: stack backtrace: - 0: call + 0: f at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC - 1: main + 1: call + at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + 2: main at tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From af6324a90f502d18cebcf5d10fe90ae613007a42 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 23 Mar 2026 22:25:09 -0400 Subject: [PATCH 18/39] 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 19/39] 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 20/39] 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 21/39] 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 22/39] 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 23/39] 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 24/39] 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 25/39] 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 26/39] 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 27/39] 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 28/39] 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 29/39] 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 30/39] 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 31/39] 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 32/39] 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 33/39] 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 34/39] 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 35/39] 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 36/39] 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 37/39] 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 38/39] 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 39/39] 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 {