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 a9bdf597e128..2a850898b2d6 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1336,6 +1336,12 @@ pub fn insert(&mut self, elem: T) -> bool { 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 @@ pub fn remove(&mut self, elem: T) -> bool { 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 @@ pub fn contains(&self, elem: T) -> bool { 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 74cc1ec17e6f..024624cd3bb8 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 f82513094aa1..62ec06358517 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ pub fn from_symbol( 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 @@ fn symbol(self) -> Symbol { 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 bdf290f9a9e6..6aa8d5f38ad2 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -442,6 +442,7 @@ pub fn ctxt(&self) -> Option { 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 305df4065196..35a74a63b8e4 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -639,7 +639,7 @@ fn wrap_in_try_constructor( 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 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'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 c1c13977e103..3aadf09597ee 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -133,8 +133,11 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'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 4ba5dc541342..1f07ee71c420 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1889,12 +1889,12 @@ fn print_pat(&mut self, pat: &ast::Pat) { 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 9b4ff2b63bd4..f6db4cdef722 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 @@ fn print_arm(&mut self, arm: &ast::Arm) { 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 7ff49e040f6f..82d941a289e0 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 @@ fn add_all(&mut self, other: &Self) { // 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 09f006c3de57..dcf2cd1fa36a 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -12,7 +12,8 @@ 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 39e886227d94..b5db4e20d0d3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -565,6 +565,8 @@ pub fn internal(&self, feature: Symbol) -> bool { (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 adfc68f4bb22..79f370bb828c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ 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 @@ pub fn parse_expr_cond( /// 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 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { }) } - 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 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option PResult<'a, (Pat, Option PResult<'a, (Pat, Option 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 36ca8a7d6133..8c1c3c7025f5 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 706b454835fa..ddf1b10e5235 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -31,7 +31,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool { MetaVarKind::Item | MetaVarKind::Block - | MetaVarKind::Vis => false, + | MetaVarKind::Vis + | MetaVarKind::Guard => false, MetaVarKind::Ident | MetaVarKind::Lifetime @@ -86,7 +87,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool { | 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 @@ fn may_be_ident(kind: MetaVarKind) -> bool { 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 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN })) } } + 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 7ee7781f6be0..a21d19b6d3a2 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -6,8 +6,9 @@ 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 @@ pub fn parse_pat_allow_top_guard( 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 @@ fn maybe_add_suggestions_then_emit( } 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 453fe9d7a8e0..d5cb3aefec0f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4054,7 +4054,7 @@ fn check_consistent_bindings(&mut self, pat: &'ast Pat) { 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 @@ fn resolve_pattern_inner( 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 257ac3f51c2c..96bda60c363e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1027,6 +1027,7 @@ global_registration, globs, gt, + guard, guard_patterns, half_open_range_patterns, half_open_range_patterns_in_slices, @@ -1190,6 +1191,7 @@ 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 50cfb0ed89de..9a463d1a9d71 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 4741abbe4658..50c0db8ac06e 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 000000000000..662161f19fac --- /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 000000000000..0977f944f74f --- /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 8551b1887708..d94142365628 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 923c9bd6cedc..874bad6a7431 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 92491dc26d12..78d167added7 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 000000000000..81a4412686de --- /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 000000000000..eddb0de9c4c5 --- /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 11960db98743..a12cc9f9b416 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 a06487be3d60..9179fbc31961 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 c3754dde080a..af76e3f095f1 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 3f331b0dd5f1..af2ba7a809ad 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! 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 a8db114129ff..33fb19089ba5 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 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option 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 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option( 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 efd4e55d5a85..2125cf6383bf 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 d00e70638b45..227680947712 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 77438472644f..7355d1136792 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 7a3d5a6bb224..be7da2e81add 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 3a2f548902d1..3187876626f3 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -773,7 +773,7 @@ pub struct 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 00d03f023924..b4f6bb4583c1 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 ebbbe36878da..17fdba37b4bc 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -229,6 +229,10 @@ macro_rules! ins_sym { 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 0bc432a0ff06..d370f00d2198 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -106,6 +106,7 @@ pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool | 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(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool "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 0548380331be..3da2d891e19d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -529,7 +529,7 @@ pub fn emit_lifetime_markers(&self) -> bool { // 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 286fea7d9050..6da8974cba64 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1115,6 +1115,7 @@ 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 8683e4f51279..2b5cbd670308 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1175,9 +1175,10 @@ impl SanitizerSet: u16 { 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 @@ pub fn as_str(self) -> Option<&'static str> { 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 @@ fn from_str(s: &str) -> Result { "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 e204c6466e29..aae7af82d553 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 1c166030d5e5..13d3b77588a0 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 ed2e2fb6ab70..2e972f2fa2ac 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 19b7ebe03674..1e06d3abb723 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 8f8bbb4a41ca..680d89653db8 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 6f11f97e3d1d..731b61d6731f 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 bc94a81ba3b5..7cac7f5c0494 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 9af881b5c2f5..eaa1a39a9eee 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -179,6 +179,7 @@ "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 168d5e9eb649..e9f3d6c28d6e 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 @@ pub(super) fn load(config: &Config) -> Self { 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 000000000000..bcb2fbc613df --- /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 000000000000..fd3aacee5af2 --- /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 000000000000..8f0e6eb3a605 --- /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 000000000000..01b129cb6920 --- /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 000000000000..957b867a61ad --- /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 000000000000..c0e23f5f596b --- /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 000000000000..a4491eb9f785 --- /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 b8a24e31c30b..5e05b92f3b10 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 efa0a7f4af9a..0ba2f0b0f209 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 00bb7746d05f..b35c2f9976f0 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 000000000000..c2b0505a34c2 --- /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 000000000000..eb6a5d33a472 --- /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 000000000000..35246fb26623 --- /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 000000000000..bef6d95e57b2 --- /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 000000000000..8b122a610ee4 --- /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 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs index fd3aacee5af2..b059f6bbefb4 100644 --- a/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs +++ b/tests/codegen-llvm/sanitizer/hwasan-vs-khwasan.rs @@ -17,9 +17,19 @@ // hwasan: call void @llvm.hwasan.check.memaccess.shortgranules // hwasan: declare void @__hwasan_init() -// khwasan-LABEL: define {{.*}} @test -// khwasan-NOT: @__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: 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 3da2d891e19d..96f54481350d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -527,8 +527,11 @@ pub fn needs_plt(&self) -> bool { 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 bcb2fbc613df..a4362b362132 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 b059f6bbefb4..93932d86582f 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 8f0e6eb3a605..f0f9180ae595 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 01b129cb6920..26dc7983d731 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 957b867a61ad..452a0f579fc7 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 c0e23f5f596b..313f48031e4a 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 c2b0505a34c2..27a2f6030d0b 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 0b6f9487ece2..9f45df4a3178 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 8d7e305f1e35..5771b40809dc 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 faa4c6581af7..4529e44e267d 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 d90294acd251..028bd48b1be7 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 be682b38865d..255400e2679e 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 976d2cbcccdb..a25ed2ba7ef6 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 8b532e19196b..1947ecf9b22e 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 47740e26fb6f..4622c3710e93 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 81c8d3383b57..77d9a5c048fa 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 8551b1887708..dfaacefc528a 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 f4756d42088a..3643836fa031 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 2ffa6b2e4572..48085b8b221b 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 e80c712b03dc..ed8974c23e71 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 c746d1bc5188..46b561af4467 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 bca0e005083d..c7eac831cffb 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 b7b260c5398c..56ea917c3be9 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 6dcb841fec15..b2a556fce6f9 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 e0b03dbbeb1b..20cacab390d5 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 3661744284ee..cf5a1c117031 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 f1acff484038..53d450ed8d58 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 a7fd3dfa5ce6..06b96da7f8b1 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 e49f346c8e3e..c41797513f6a 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 2b048651cccc..93f7c212e001 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 2c384bdb42ef..bbb01facc624 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 c37945a2d672..679987ac1f4a 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 dd4e6fda8be9..23d8c454d697 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 60afc3b44506..ff026c53b1d7 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 8bb3c9da3051..733853f8d234 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 d189b881f7dd..800a796491be 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 1d15b8386af9..cf5a410c6edf 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 d802f189ce1a..000000000000 --- 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 d84787705a1a..000000000000 --- 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 b717eed3fb43..000000000000 --- 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 f4fefb0ca37d..96ed4265ef6e 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 f() { + let __isize: isize = panic!("test"); + + panic!(); +} fn main() { - let __isize: isize = panic!("test"); + 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 de2945d74604..000000000000 --- 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 c3de3150e697..000000000000 --- 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 fb7fad0b5a2e..000000000000 --- 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 85aa3bc8c0df..f8c243c9f395 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 fn eat(&mut self) -> bool { return false; } } + + pub fn noop(&self) {} } impl cat { @@ -29,6 +33,9 @@ pub fn meow(&mut self) { 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 fn cat(in_x : usize, in_y : isize, in_name: String) -> cat { 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 dfc3c56ddee7..000000000000 --- 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 2d02b591c555..000000000000 --- 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 d4caa19135e8..000000000000 --- 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 658e9d2117dc..000000000000 --- 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 bbbde34ec096..000000000000 --- 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 53d0e3db6f5f..000000000000 --- 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 781ac6ad10d2..000000000000 --- 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 3a514ff9d758..000000000000 --- 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 f73999a24501..000000000000 --- 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 b2c48248a671..000000000000 --- 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 b0dbbbec5224..000000000000 --- 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 2768e284c173..000000000000 --- 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 24f648afc90b..000000000000 --- 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 6fb5f2e3cc9d..d859cbdc76da 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 1548f768b6f3..000000000000 --- 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 562fd5909815..000000000000 --- 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 d870a3101f1a..000000000000 --- 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 05976f6a759a..000000000000 --- 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 | 110 ++++++++---------- tests/ui/structs-enums/classes-cross-crate.rs | 91 ++++++++------- 2 files changed, 97 insertions(+), 104 deletions(-) diff --git a/tests/ui/structs-enums/auxiliary/cci_class_4.rs b/tests/ui/structs-enums/auxiliary/cci_class_4.rs index f8c243c9f395..fff7b7809571 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, +use std::fmt; - pub how_hungry : isize, - pub 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; - } - } - - 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 meow_count(&self) -> usize { - self.meows - } - } - - 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) - } - } +#[derive(Clone)] +pub struct Cat { + meows: usize, + pub how_hungry: isize, + pub 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; + } + } + + 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 meow_count(&self) -> usize { + self.meows + } +} + +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 d859cbdc76da..85454bb15a7b 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 e6d359803856..000000000000 --- 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 c6216d1b567b..000000000000 --- 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 bf2e37a189bc..000000000000 --- 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 f4c202d91a7c..000000000000 --- 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 e2395036551e..000000000000 --- 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 4243bccb4eb7..000000000000 --- 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 5213052dd7a4..36a36605ba80 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 a5436624c658..000000000000 --- 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 a08f0f0b0a47..b7911823ef1b 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 f819e558aa2e..40c51a1573cd 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 91be8014ebda..641e5566bee3 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 f339c191ae80..b710d83350ab 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 774cfa1a3808..2bc23d94b4d9 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 82742a934c41..52bfa9d4ab72 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 3e2e0b5ffa8f..f3f1a3bd44e5 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 5ff730aff441..1d3fab4e722c 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 35476c5ed2d6..c0d04932c464 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 b78505edd1f2..dbb5d707b52f 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 a6528f9a2b17..40acea956aea 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 27b48aae51f6..75691f02dd82 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 97bc7d8414e7..def0fa00e17c 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 a7b057511843..c1403b79c8aa 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 c3fa86f8a2ad..a667877e8e51 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -471,7 +471,7 @@ fn dbg_scope_fn( // 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 @@ fn dbg_scope_fn( // 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 @@ fn dbg_scope_fn( 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 77438472644f..813897d7d327 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) struct DIFlags: u32 { 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 63ff0b2a0a0d..392cd0601391 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 000000000000..f86adfcc3626 --- /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 8be7d3a9ae92..7399ee569eb3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -139,8 +139,9 @@ pub const fn dangling() -> Self { /// /// 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 2dbf2cc91058..d799e376e8bd 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 0381571ef6da..802aa9ef4645 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -404,166 +404,158 @@ pub fn init_stack_frame( // 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 - // 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), - )?; - - // 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, - )?; + 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:?})"), } - } else { - // Normal argument. Cannot mark it as live yet, it might be unsized! + )) + .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() { + // 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 b0f34264ad84..a73767264dab 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -381,7 +381,7 @@ pub(crate) fn push_stack_frame_raw( 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 @@ pub(crate) fn push_stack_frame_raw( // 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 @@ pub(super) fn cleanup_stack_frame( } } - /// 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 @@ pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tc 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 a9fff6d59326..33da1c5ecf73 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 6fec6500cc96..024537633383 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 979a1a8337b5..e3509a2a6ee8 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 cb55b0f92ee6..28fdb1d01384 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 e8ad65a74ac8..d6504f6b9787 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 b6cda6007536..1fb597fdc02a 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 a86c68cebd23..14df4ebd11f5 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 d62adeeb8420..7012c4f8aead 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 3cb8ee2b407c..b3d43ca63cb0 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 491d01cf4284..21fcfb96fd17 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 3c1038d364bb..e4d4e87625a9 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 952f2272f3bf..c754acdd5ea1 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 095dc7e1a1fb..c210d5c00524 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 d625d1d1d034..b7eb3c5e9cab 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 a01c040fe6f8..e79cf08b15bf 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 a108944c5e43..81fa672d5229 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 75c060ea51d4..4c481e8d3cb9 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 73c562c94e95..5cf0fd40b58c 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 0dc137843c91..cc5f4a812eeb 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 6654ddc12c29..133aa8ca35a1 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 6472dfd4f995..fb87eea63102 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 79f4d2c69f3c..07ed6d128215 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 82b898df45b2..e3c5d6baf89f 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 26f2e73dd752..beb0f726568f 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 56e69e846696..62ba807d7a95 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 0cca4a132333..a40e5b44660d 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 cbef9d27cdf9..8147d009ff85 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 053a4a5f2845..8c2d0648cbf1 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 cd14ea156a47..f9195a869798 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 f3dffcc4e867..79485a27ee13 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 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 0e52dc02884c..3e4be1e39fd9 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 05b645cf75af..8bf46af71e82 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 ba940902c8ce..9f206189b6e0 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 ca43c06008fd..0b06496b2bfd 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 ab9c0e720304..b85ac39faa8f 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 920fb51abb64..fc9a107f0c73 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 06e6ccbd7bf2..271ec64475ee 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 c0e96a43cc52..744c5289e018 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 d343eb8f2599..1721f0f9428c 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 dedcaac61427..ed5b4696dd0f 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 1176589a5f4a..59823fad522b 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 3629e4387e7f..1e10f682e71e 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 1b4cd23e41a8..4e474dbadcb6 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 36bd1e99cfbc..e747bfdbf520 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 f5eccaeba666..9c10db8e5fe4 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 6ab73569c634..8657e3ad679d 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 02e0ebe8abe6..aa797f64ce20 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 7ca26bffc14f..7bc26237576a 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::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 3b23a6cc4e85..e54210981e08 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 e9c3b040dc50..46d48afbf5a1 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1212,7 +1212,7 @@ pub fn to_lowercase(self) -> ToLowercase { /// 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 62ee653000dc..9310cda8450b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1512,6 +1512,7 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t } 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 @@ fn validate_operand_internal( 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 @@ fn validate_operand_internal( 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 @@ pub(crate) fn const_validate_operand( Some(ref_tracking), Some(ctfe_mode), /*reset_provenance*/ false, + /*start_in_may_dangle*/ false, ) } @@ -1610,6 +1613,7 @@ pub fn validate_operand( None, None, reset_provenance_and_padding, + /*start_in_may_dangle*/ false, ); } // Do a recursive check. @@ -1620,15 +1624,19 @@ pub fn validate_operand( 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 97f385ad755b..f51cd96486b4 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 be7da2e81add..7a3d5a6bb224 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 1771d1382f07..eb070c22dc28 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 41f177ed26a5..05918363362b 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 1f0afc368a2e..14433c1460eb 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 d4aa354491fe..511cb3562f94 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 036aa2ed05a4..a28e8f23e045 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 $ty { 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 @@ impl<'tcx> Erasable for $($fake_path)::+<'tcx> { // 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 a28e8f23e045..66b0f01196d4 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -267,57 +267,58 @@ impl Erasable for $ty { // 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 @@ impl Erasable for $($fake_path)::+<'_> { // 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 66b0f01196d4..fce9943d105b 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 $ty { 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 fce9943d105b..865cdecf6d80 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -12,7 +12,6 @@ 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 @@ impl Erasable for $($fake_path)::+<'_> { // 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 $($fake_path)::+<'_> { 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 865cdecf6d80..59853e8cc464 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 59853e8cc464..54fe858e4809 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 @@ impl Erasable for $ty { } } -// 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 $ty { 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 $ty { 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 $ty { 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 54fe858e4809..53ec0584ae59 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -10,12 +10,12 @@ 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 @@ impl Erasable for $ty { // `[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 $ty { 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 000000000000..91cf1d3a0a63 --- /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 c4f0c618a52d..7079e29eefff 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 455c81c63340..e1e521103b57 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 03acf40ef5fe..022f9e3c83f1 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -432,6 +432,17 @@ fn lower_delegation_body( 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 dd0ee2c732f5..7efbb3795185 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 6c996807d6ba..501118713d12 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 257ab760ffc1..226a48ecf9a4 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 000000000000..c684803014ad --- /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 000000000000..dcac56e0b2ba --- /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 2a6e0829bc0f..df9dfb7a3317 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 bd8220200654..0269f9e6e896 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 ecf1ad0403d3..350c38480ed7 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 bf100755b906..bf6df45a2579 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 375178172bb0..bd121a7045dd 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 f87514ba83b0..67890de71af6 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 0e1f19a75bae..a5d6feae7e91 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 06e0192d9574..d5db956cf16f 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 68b4d28aae3b..009d1d939360 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 __static_ref_initialize() -> 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 e94c961f431d..134129f814aa 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 e15f0b52da2f..8f679d27059a 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 21abc498de12..a3d06011bbfb 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 508009337a5a..347c50e1e3b6 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 d40b869cd0cd..6d7b375ecb10 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 @@ 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 9b65366b969a..88ddffecc928 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 ee1ac9aa5cd8..4e960e3b9290 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -337,7 +337,6 @@ fn uplift_delegation_generic_params( // 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 @@ fn create_generics_args_from_params( 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 0b142c0b7686..730288574e76 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 aafdd5617d02..c67e4c02a1b7 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 @@ pub fn check() { } } -// 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 000000000000..652059b37ec6 --- /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 000000000000..14b03991d9e6 --- /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 7fbbadac1e2b..c6af573a5869 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 bff0046c97cb..5909f29d52c1 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 10aa1b4019b3..72d5cdcf1f3b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -547,6 +547,13 @@ fn name(&self) -> Option { 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 @@ fn def_id(self) -> DefId { } 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 @@ fn new_module( &'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 @@ pub fn new( 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 @@ pub fn new( 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 @@ fn new_local_module( 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 @@ fn new_extern_module( 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 000000000000..1a799acb50fb --- /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 000000000000..3b336800a180 --- /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 be64f239b9fc..164f645dc5c5 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 {