From 547f3cef6022980187da2744b3c6ed93368328bd Mon Sep 17 00:00:00 2001 From: Haydon Ryan Date: Mon, 11 Dec 2023 11:41:33 -0600 Subject: [PATCH 01/26] fixing error std::fs::read_to_string example documentation --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 4310e10830380..ed630ef3dc7f1 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -283,11 +283,11 @@ pub fn read>(path: P) -> io::Result> { /// /// ```no_run /// use std::fs; -/// use std::net::SocketAddr; /// use std::error::Error; /// /// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; +/// let address: String = fs::read_to_string("address.txt")?; +/// println!("{}", address); /// Ok(()) /// } /// ``` From 6e9ca489f703f055d98bf7a513b2491dbec63983 Mon Sep 17 00:00:00 2001 From: Haydon Ryan Date: Mon, 11 Dec 2023 12:00:23 -0600 Subject: [PATCH 02/26] Updating fs::read example to remove SocketAddress --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index ed630ef3dc7f1..acc0f37a688a8 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -242,10 +242,10 @@ pub struct DirBuilder { /// /// ```no_run /// use std::fs; -/// use std::net::SocketAddr; /// /// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; +/// let address: String = String::from_utf8_lossy(&fs::read("address.txt")?).to_string(); +/// println!("{}", address); /// Ok(()) /// } /// ``` From f4b65f5caf7c7ea7a2df9cfe43727a3f9dc27f69 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 3 Feb 2024 11:01:26 +0000 Subject: [PATCH 03/26] Docs for std::ptr::slice_from_raw_parts --- library/core/src/ptr/mod.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index dce7e035fc73a..6e448d90c1224 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -762,6 +762,17 @@ pub const fn from_mut(r: &mut T) -> *mut T { /// let slice = ptr::slice_from_raw_parts(raw_pointer, 3); /// assert_eq!(unsafe { &*slice }[2], 7); /// ``` +/// +/// You must ensure that the pointer is valid and not null before dereferencing +/// the raw slice. A slice reference must never have a null pointer, even if it's empty. +/// +/// ```rust,should_panic +/// use std::ptr; +/// let danger: *const [u8] = ptr::slice_from_raw_parts(ptr::null(), 0); +/// unsafe { +/// danger.as_ref().expect("references must not be null"); +/// } +/// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] @@ -771,11 +782,13 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { from_raw_parts(data.cast(), len) } +/// Forms a raw mutable slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// /// Performs the same functionality as [`slice_from_raw_parts`], except that a /// raw mutable slice is returned, as opposed to a raw immutable slice. /// -/// See the documentation of [`slice_from_raw_parts`] for more details. -/// /// This function is safe, but actually using the return value is unsafe. /// See the documentation of [`slice::from_raw_parts_mut`] for slice safety requirements. /// @@ -796,6 +809,17 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// /// assert_eq!(unsafe { &*slice }[2], 99); /// ``` +/// +/// You must ensure that the pointer is valid and not null before dereferencing +/// the raw slice. A slice reference must never have a null pointer, even if it's empty. +/// +/// ```rust,should_panic +/// use std::ptr; +/// let danger: *mut [u8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 0); +/// unsafe { +/// danger.as_mut().expect("references must not be null"); +/// } +/// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] From 9539feb2f73b1e9370e28a6dcdaf0fe51bc65465 Mon Sep 17 00:00:00 2001 From: Haydon Ryan Date: Thu, 15 Feb 2024 08:20:15 -0600 Subject: [PATCH 04/26] Update library/std/src/fs.rs Co-authored-by: Mara Bos --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index acc0f37a688a8..29b61a8d1d0bc 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -286,8 +286,8 @@ pub fn read>(path: P) -> io::Result> { /// use std::error::Error; /// /// fn main() -> Result<(), Box> { -/// let address: String = fs::read_to_string("address.txt")?; -/// println!("{}", address); +/// let message: String = fs::read_to_string("message.txt")?; +/// println!("{}", message); /// Ok(()) /// } /// ``` From b5e1ca39180e9997efef14d3b7d06a3ddff72b59 Mon Sep 17 00:00:00 2001 From: Haydon Ryan Date: Thu, 15 Feb 2024 08:20:45 -0600 Subject: [PATCH 05/26] Update library/std/src/fs.rs Co-authored-by: Mara Bos --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 29b61a8d1d0bc..5bcd92b63df95 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -244,8 +244,8 @@ pub struct DirBuilder { /// use std::fs; /// /// fn main() -> Result<(), Box> { -/// let address: String = String::from_utf8_lossy(&fs::read("address.txt")?).to_string(); -/// println!("{}", address); +/// let data: Vec = fs::read("image.jpg")?; +/// assert_eq!(data[0..3], [0xFF, 0xD8, 0xFF]); /// Ok(()) /// } /// ``` From 93fa8579c6430d54525e1905eafff4dbcf9b31b0 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 25 Dec 2023 20:53:01 +0000 Subject: [PATCH 06/26] Add asm label support to AST and HIR --- compiler/rustc_ast/src/ast.rs | 5 +- compiler/rustc_ast/src/mut_visit.rs | 1 + compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/messages.ftl | 3 + compiler/rustc_ast_lowering/src/asm.rs | 27 +++++++-- compiler/rustc_ast_lowering/src/errors.rs | 10 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 4 ++ compiler/rustc_builtin_macros/src/asm.rs | 3 + compiler/rustc_codegen_ssa/src/mono_item.rs | 3 +- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir/src/hir.rs | 14 ++++- compiler/rustc_hir/src/intravisit.rs | 1 + .../src/check/intrinsicck.rs | 2 + compiler/rustc_hir_pretty/src/lib.rs | 4 ++ compiler/rustc_hir_typeck/src/expr.rs | 3 + .../rustc_hir_typeck/src/expr_use_visitor.rs | 3 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 + compiler/rustc_monomorphize/src/collector.rs | 3 +- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 59 +++++++++++++++---- compiler/rustc_passes/src/naked_functions.rs | 3 +- compiler/rustc_resolve/src/late.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + .../clippy_lints/src/loops/never_loop.rs | 3 + .../clippy/clippy_utils/src/hir_utils.rs | 1 + 25 files changed, 142 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3fdb2a2225a58..d0287af9cd33c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2294,6 +2294,9 @@ pub enum InlineAsmOperand { Sym { sym: InlineAsmSym, }, + Label { + block: P, + }, } impl InlineAsmOperand { @@ -2303,7 +2306,7 @@ impl InlineAsmOperand { | Self::Out { reg, .. } | Self::InOut { reg, .. } | Self::SplitInOut { reg, .. } => Some(reg), - Self::Const { .. } | Self::Sym { .. } => None, + Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None, } } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c42c41999732c..c2eddef9fb7f4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1330,6 +1330,7 @@ pub fn noop_visit_inline_asm(asm: &mut InlineAsm, vis: &mut T) { } InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const), InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym), + InlineAsmOperand::Label { block } => vis.visit_block(block), } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ecf379cc2408a..7fbfe4d97c059 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -885,6 +885,7 @@ pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) try_visit!(visitor.visit_anon_const(anon_const)) } InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)), + InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)), } } V::Result::output() diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e87cf05713cd3..d91d65497e1c1 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -88,6 +88,9 @@ ast_lowering_invalid_abi_suggestion = did you mean ast_lowering_invalid_asm_template_modifier_const = asm template modifiers are not allowed for `const` arguments +ast_lowering_invalid_asm_template_modifier_label = + asm template modifiers are not allowed for `label` arguments + ast_lowering_invalid_asm_template_modifier_reg_class = invalid asm template modifier for this register class diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index fd717e82d26df..f91183e2cbf2e 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -3,9 +3,9 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringE use super::errors::{ AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, - InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, - InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, - RegisterConflict, + InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass, + InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister, + InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict, }; use super::LoweringContext; @@ -236,6 +236,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } + InlineAsmOperand::Label { block } => { + if !self.tcx.features().asm_goto { + feature_err( + sess, + sym::asm_goto, + *op_sp, + "label operands for inline assembly are unstable", + ) + .emit(); + } + hir::InlineAsmOperand::Label { block: self.lower_block(block, false) } + } }; (op, self.lower_span(*op_sp)) }) @@ -295,6 +307,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { op_span: op_sp, }); } + hir::InlineAsmOperand::Label { .. } => { + self.dcx().emit_err(InvalidAsmTemplateModifierLabel { + placeholder_span, + op_span: op_sp, + }); + } } } } @@ -334,7 +352,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } - | hir::InlineAsmOperand::SymStatic { .. } => { + | hir::InlineAsmOperand::SymStatic { .. } + | hir::InlineAsmOperand::Label { .. } => { unreachable!("{op:?} is not a register operand"); } }; diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 834409da6750a..76659216d870e 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -262,6 +262,16 @@ pub struct InvalidAsmTemplateModifierSym { pub op_span: Span, } +#[derive(Diagnostic, Clone, Copy)] +#[diag(ast_lowering_invalid_asm_template_modifier_label)] +pub struct InvalidAsmTemplateModifierLabel { + #[primary_span] + #[label(ast_lowering_template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering_argument)] + pub op_span: Span, +} + #[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_register_class_only_clobber)] pub struct RegisterClassOnlyClobber { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 7ea0078ea3bb9..8d64ecb24309a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1331,6 +1331,10 @@ impl<'a> State<'a> { s.print_path(&sym.path, true, 0); } } + InlineAsmOperand::Label { block } => { + s.head("label"); + s.print_block(block); + } } } AsmArg::ClobberAbi(abi) => { diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index c5a73c3199579..93eb3a9a43ee3 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -166,6 +166,9 @@ pub fn parse_asm_args<'a>( path: path.clone(), }; ast::InlineAsmOperand::Sym { sym } + } else if !is_global_asm && p.eat_keyword(sym::label) { + let block = p.parse_block()?; + ast::InlineAsmOperand::Label { block } } else if allow_templates { let template = p.parse_expr()?; // If it can't possibly expand to a string, provide diagnostics here to include other diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 295e27691090c..1a4795c0213a1 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -76,7 +76,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Out { .. } | hir::InlineAsmOperand::InOut { .. } - | hir::InlineAsmOperand::SplitInOut { .. } => { + | hir::InlineAsmOperand::SplitInOut { .. } + | hir::InlineAsmOperand::Label { .. } => { span_bug!(*op_sp, "invalid operand type for global_asm!") } }) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93c183a65ef3e..74ec6a9713f3c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -345,6 +345,8 @@ declare_features! ( (unstable, asm_const, "1.58.0", Some(93332)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), + /// Allows using `label` operands in inline assembly. + (unstable, asm_goto, "CURRENT_RUSTC_VERSION", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), /// Allows users to enforce equality of associated constants `TraitImpl`. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 78e7c636a3e74..2b8cd47bd1fe0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2645,6 +2645,9 @@ pub enum InlineAsmOperand<'hir> { path: QPath<'hir>, def_id: DefId, }, + Label { + block: &'hir Block<'hir>, + }, } impl<'hir> InlineAsmOperand<'hir> { @@ -2654,7 +2657,10 @@ impl<'hir> InlineAsmOperand<'hir> { | Self::Out { reg, .. } | Self::InOut { reg, .. } | Self::SplitInOut { reg, .. } => Some(reg), - Self::Const { .. } | Self::SymFn { .. } | Self::SymStatic { .. } => None, + Self::Const { .. } + | Self::SymFn { .. } + | Self::SymStatic { .. } + | Self::Label { .. } => None, } } @@ -2675,6 +2681,12 @@ pub struct InlineAsm<'hir> { pub line_spans: &'hir [Span], } +impl InlineAsm<'_> { + pub fn contains_label(&self) -> bool { + self.operands.iter().any(|x| matches!(x.0, InlineAsmOperand::Label { .. })) + } +} + /// Represents a parameter in a function header. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Param<'hir> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1c38a45d3a32f..278a0a6e6b906 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1290,6 +1290,7 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>( InlineAsmOperand::SymStatic { path, .. } => { try_visit!(visitor.visit_qpath(path, id, *op_sp)); } + InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)), } } V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index d03b02f028da1..9de660407d7aa 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -470,6 +470,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } }; } + // No special checking is needed for labels. + hir::InlineAsmOperand::Label { .. } => {} } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8f8f747339b42..b5bb063c5ed8c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1265,6 +1265,10 @@ impl<'a> State<'a> { s.space(); s.print_qpath(path, true); } + hir::InlineAsmOperand::Label { block } => { + s.head("label"); + s.print_block(block); + } }, AsmArg::Options(opts) => { s.word("options"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 81440b0562e24..614761c03bd61 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3264,6 +3264,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be well-formed. hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {} hir::InlineAsmOperand::SymStatic { .. } => {} + hir::InlineAsmOperand::Label { block } => { + self.check_block_no_value(block); + } } } if asm.options.contains(ast::InlineAsmOptions::NORETURN) { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 04fb7bcf4f3b4..ba0383d19b92a 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -293,6 +293,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => {} + hir::InlineAsmOperand::Label { block } => { + self.walk_block(block); + } } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 62762168cf420..0e64ed897537e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -656,6 +656,9 @@ impl<'tcx> Cx<'tcx> { hir::InlineAsmOperand::SymStatic { path: _, def_id } => { InlineAsmOperand::SymStatic { def_id } } + hir::InlineAsmOperand::Label { .. } => { + todo!() + } }) .collect(), options: asm.options, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 5593de607844d..3ab6c4b9b6a55 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -446,7 +446,8 @@ fn collect_items_rec<'tcx>( hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Out { .. } | hir::InlineAsmOperand::InOut { .. } - | hir::InlineAsmOperand::SplitInOut { .. } => { + | hir::InlineAsmOperand::SplitInOut { .. } + | hir::InlineAsmOperand::Label { .. } => { span_bug!(*op_sp, "invalid operand type for global_asm!") } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1bae5b3224035..9c0020f02d9c2 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -434,7 +434,7 @@ impl<'a> Parser<'a> { } /// Parses a block. No inner attributes are allowed. - pub(super) fn parse_block(&mut self) -> PResult<'a, P> { + pub fn parse_block(&mut self) -> PResult<'a, P> { let (attrs, block) = self.parse_inner_attrs_and_block()?; if let [.., last] = &*attrs { self.error_on_forbidden_inner_attr( diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 487407014d178..e5033e1f51f23 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -86,7 +86,6 @@ use crate::errors; use self::LiveNodeKind::*; use self::VarKind::*; -use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def::*; @@ -416,6 +415,12 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); } + // Inline assembly may contain labels. + hir::ExprKind::InlineAsm(asm) if asm.contains_label() => { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); + intravisit::walk_expr(self, expr); + } + // otherwise, live nodes are not required: hir::ExprKind::Index(..) | hir::ExprKind::Field(..) @@ -1045,20 +1050,53 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { | hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ), hir::ExprKind::InlineAsm(asm) => { + // + // (inputs) + // | + // v + // (outputs) + // / \ + // | | + // v v + // (labels)(fallthrough) + // | | + // v v + // ( succ / exit_ln ) + // Handle non-returning asm - let mut succ = if asm.options.contains(InlineAsmOptions::NORETURN) { - self.exit_ln - } else { - succ - }; + let mut succ = + if self.typeck_results.expr_ty(expr).is_never() { self.exit_ln } else { succ }; + + // Do a first pass for labels only + if asm.contains_label() { + let ln = self.live_node(expr.hir_id, expr.span); + self.init_from_succ(ln, succ); + for (op, _op_sp) in asm.operands.iter().rev() { + match op { + hir::InlineAsmOperand::Label { block } => { + let label_ln = self.propagate_through_block(block, succ); + self.merge_from_succ(ln, label_ln); + } + hir::InlineAsmOperand::In { .. } + | hir::InlineAsmOperand::Out { .. } + | hir::InlineAsmOperand::InOut { .. } + | hir::InlineAsmOperand::SplitInOut { .. } + | hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::SymFn { .. } + | hir::InlineAsmOperand::SymStatic { .. } => {} + } + } + succ = ln; + } - // Do a first pass for writing outputs only + // Do a second pass for writing outputs only for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } - | hir::InlineAsmOperand::SymStatic { .. } => {} + | hir::InlineAsmOperand::SymStatic { .. } + | hir::InlineAsmOperand::Label { .. } => {} hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { succ = self.write_place(expr, succ, ACC_WRITE); @@ -1075,7 +1113,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - // Then do a second pass for inputs + // Then do a third pass for inputs for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { expr, .. } => { @@ -1097,7 +1135,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } - | hir::InlineAsmOperand::SymStatic { .. } => {} + | hir::InlineAsmOperand::SymStatic { .. } + | hir::InlineAsmOperand::Label { .. } => {} } } succ diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 0455d6d4acba3..27c9c1306e6ac 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -237,7 +237,8 @@ impl<'tcx> CheckInlineAssembly<'tcx> { InlineAsmOperand::In { .. } | InlineAsmOperand::Out { .. } | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } => Some(op_sp), + | InlineAsmOperand::SplitInOut { .. } + | InlineAsmOperand::Label { .. } => Some(op_sp), }) .collect(); if !unsupported_operands.is_empty() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2f4da29133f1b..8b8d99f88165a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1246,6 +1246,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.resolve_anon_const(anon_const, AnonConstKind::InlineConst); } InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym), + InlineAsmOperand::Label { block } => self.visit_block(block), } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46472a131ff4b..0cfff1623dbd4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -399,6 +399,7 @@ symbols! { asm, asm_const, asm_experimental_arch, + asm_goto, asm_sym, asm_unwind, assert, diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 245a903f99826..65d922f03df3a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -255,6 +255,9 @@ fn never_loop_expr<'tcx>( InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => { NeverLoopResult::Normal }, + InlineAsmOperand::Label { block } => { + never_loop_block(cx, block, local_labels, main_loop_id) + } })), ExprKind::OffsetOf(_, _) | ExprKind::Yield(_, _) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index d50332e82da5b..643852c1c54fb 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -835,6 +835,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_body(anon_const.body); }, InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path), + InlineAsmOperand::Label { block } => self.hash_block(block), } } }, From 040ab7d4b604d9e70bf9c93a1af7146edf0e740e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 25 Dec 2023 21:19:04 +0000 Subject: [PATCH 07/26] Add asm label support to THIR --- compiler/rustc_middle/src/thir.rs | 3 +++ compiler/rustc_middle/src/thir/visit.rs | 1 + compiler/rustc_mir_build/src/build/expr/into.rs | 3 +++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 ++-- compiler/rustc_mir_build/src/thir/print.rs | 6 ++++++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e1e5d68148fe8..f91130ee25820 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -565,6 +565,9 @@ pub enum InlineAsmOperand<'tcx> { SymStatic { def_id: DefId, }, + Label { + block: BlockId, + }, } #[derive(Copy, Clone, Debug, PartialEq, HashStable)] diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 4847a7bea91d7..5952c296fb642 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -162,6 +162,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | Const { value: _, span: _ } | SymFn { value: _, span: _ } | SymStatic { def_id: _ } => {} + Label { block } => visitor.visit_block(&visitor.thir()[*block]), } } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 2978491d646e8..60614383cc84a 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -455,6 +455,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } + thir::InlineAsmOperand::Label { .. } => { + todo!() + } }) .collect(); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 0e64ed897537e..2318e84292b83 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -656,8 +656,8 @@ impl<'tcx> Cx<'tcx> { hir::InlineAsmOperand::SymStatic { path: _, def_id } => { InlineAsmOperand::SymStatic { def_id } } - hir::InlineAsmOperand::Label { .. } => { - todo!() + hir::InlineAsmOperand::Label { block } => { + InlineAsmOperand::Label { block: self.mirror_block(block) } } }) .collect(), diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 267ea3aa3e12c..d53704f89e79e 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -889,6 +889,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1); } + InlineAsmOperand::Label { block } => { + print_indented!(self, "InlineAsmOperand::Block {", depth_lvl); + print_indented!(self, "block:", depth_lvl + 1); + self.print_block(*block, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } } } } From 7152993aa859819d67b9f01e41e1f389e52043de Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 04:31:56 +0000 Subject: [PATCH 08/26] Use slice.chain(option) for Successors This makes more sense because most cases then second one is unwind target. --- compiler/rustc_middle/src/mir/terminator.rs | 59 ++++++++++----------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 91b7952bec5e8..381db830aea5e 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -336,8 +336,7 @@ pub struct Terminator<'tcx> { } pub type Successors<'a> = impl DoubleEndedIterator + 'a; -pub type SuccessorsMut<'a> = - iter::Chain, slice::IterMut<'a, BasicBlock>>; +pub type SuccessorsMut<'a> = impl DoubleEndedIterator + 'a; impl<'tcx> Terminator<'tcx> { #[inline] @@ -371,24 +370,24 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { - Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } - | Yield { resume: t, drop: Some(ref u), .. } - | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } - | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } - | FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) } - | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { - Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) - } - Goto { target: t } - | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } - | Call { target: Some(t), unwind: _, .. } - | Yield { resume: t, drop: None, .. } - | Drop { target: t, unwind: _, .. } - | Assert { target: t, unwind: _, .. } - | FalseUnwind { real_target: t, unwind: _ } - | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } - | InlineAsm { destination: Some(t), unwind: _, .. } => { - Some(t).into_iter().chain((&[]).into_iter().copied()) + Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. } + | Yield { resume: ref t, drop: Some(u), .. } + | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. } + | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. } + | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } + | InlineAsm { destination: Some(ref t), unwind: UnwindAction::Cleanup(u), .. } => { + slice::from_ref(t).into_iter().copied().chain(Some(u)) + } + Goto { target: ref t } + | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. } + | Call { target: Some(ref t), unwind: _, .. } + | Yield { resume: ref t, drop: None, .. } + | Drop { target: ref t, unwind: _, .. } + | Assert { target: ref t, unwind: _, .. } + | FalseUnwind { real_target: ref t, unwind: _ } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref t), .. } + | InlineAsm { destination: Some(ref t), unwind: _, .. } => { + slice::from_ref(t).into_iter().copied().chain(None) } UnwindResume | UnwindTerminate(_) @@ -397,14 +396,12 @@ impl<'tcx> TerminatorKind<'tcx> { | Unreachable | Call { target: None, unwind: _, .. } | InlineAsm { destination: None, unwind: _, .. } => { - None.into_iter().chain((&[]).into_iter().copied()) + (&[]).into_iter().copied().chain(None) } - SwitchInt { ref targets, .. } => { - None.into_iter().chain(targets.targets.iter().copied()) + SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None), + FalseEdge { ref real_target, imaginary_target } => { + slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target)) } - FalseEdge { real_target, ref imaginary_target } => Some(real_target) - .into_iter() - .chain(slice::from_ref(imaginary_target).into_iter().copied()), } } @@ -421,7 +418,7 @@ impl<'tcx> TerminatorKind<'tcx> { destination: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. - } => Some(t).into_iter().chain(slice::from_mut(u)), + } => slice::from_mut(t).into_iter().chain(Some(u)), Goto { target: ref mut t } | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } | Call { target: Some(ref mut t), unwind: _, .. } @@ -431,7 +428,7 @@ impl<'tcx> TerminatorKind<'tcx> { | FalseUnwind { real_target: ref mut t, unwind: _ } | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. } | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { - Some(t).into_iter().chain(&mut []) + slice::from_mut(t).into_iter().chain(None) } UnwindResume | UnwindTerminate(_) @@ -439,10 +436,10 @@ impl<'tcx> TerminatorKind<'tcx> { | Return | Unreachable | Call { target: None, unwind: _, .. } - | InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []), - SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets), + | InlineAsm { destination: None, unwind: _, .. } => (&mut []).into_iter().chain(None), + SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None), FalseEdge { ref mut real_target, ref mut imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) + slice::from_mut(real_target).into_iter().chain(Some(imaginary_target)) } } } From b044aaa905f8a97e67ea72b490ee46d6420c4680 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 15:28:42 +0000 Subject: [PATCH 09/26] Change InlineAsm to allow multiple targets instead --- compiler/rustc_borrowck/src/lib.rs | 2 +- .../src/polonius/loan_invalidations.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 4 +- compiler/rustc_codegen_cranelift/src/base.rs | 16 ++++- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- compiler/rustc_const_eval/messages.ftl | 3 - .../rustc_const_eval/src/interpret/machine.rs | 6 ++ .../src/interpret/terminator.rs | 12 +--- .../src/transform/validate.rs | 6 +- compiler/rustc_middle/src/mir/mod.rs | 6 +- compiler/rustc_middle/src/mir/pretty.rs | 23 ++++--- compiler/rustc_middle/src/mir/syntax.rs | 7 +- compiler/rustc_middle/src/mir/terminator.rs | 64 ++++++++++--------- compiler/rustc_middle/src/mir/visit.rs | 2 +- .../rustc_mir_build/src/build/expr/into.rs | 6 +- compiler/rustc_mir_build/src/lints.rs | 7 +- .../src/framework/direction.rs | 13 ++-- .../src/framework/graphviz.rs | 4 +- .../src/move_paths/builder.rs | 2 +- .../rustc_mir_transform/src/coverage/graph.rs | 18 ++++-- .../rustc_mir_transform/src/coverage/tests.rs | 5 +- compiler/rustc_mir_transform/src/inline.rs | 4 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 5 +- 23 files changed, 125 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index dbaa9e5bcfab0..94c1875608387 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -723,7 +723,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro operands, options: _, line_spans: _, - destination: _, + targets: _, unwind: _, } => { for op in operands { diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 10941cadcbb25..83081f83e5e80 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -161,7 +161,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { operands, options: _, line_spans: _, - destination: _, + targets: _, unwind: _, } => { for op in operands { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 75cc28bcab0bc..fecf23ad74a8d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1771,8 +1771,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, real_target, is_cleanup); self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } - TerminatorKind::InlineAsm { destination, unwind, .. } => { - if let Some(target) = destination { + TerminatorKind::InlineAsm { ref targets, unwind, .. } => { + for &target in targets { self.assert_iscleanup(body, block_data, target, is_cleanup); } self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a7e76fbc128ea..1ce920f3bdb79 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -445,7 +445,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { template, operands, options, - destination, + targets, line_spans: _, unwind: _, } => { @@ -456,13 +456,25 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } + let have_labels = if options.contains(InlineAsmOptions::NORETURN) { + !targets.is_empty() + } else { + targets.len() > 1 + }; + if have_labels { + fx.tcx.dcx().span_fatal( + source_info.span, + "cranelift doesn't support labels in inline assembly.", + ); + } + crate::inline_asm::codegen_inline_asm_terminator( fx, source_info.span, template, operands, *options, - *destination, + targets.get(0).copied(), ); } TerminatorKind::UnwindTerminate(reason) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 00007110938e0..6342802bb1960 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1285,7 +1285,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ref operands, options, line_spans, - destination, + ref targets, unwind, } => self.codegen_asm_terminator( helper, @@ -1295,7 +1295,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operands, options, line_spans, - destination, + targets.get(0).copied(), unwind, self.instance, mergeable_succ(), diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index c456e40d7c15b..52ee78570bef5 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -232,9 +232,6 @@ const_eval_non_const_fn_call = const_eval_non_const_impl = impl defined here, but it is not `const` -const_eval_noreturn_asm_returned = - returned from noreturn inline assembly - const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 0106ec425bc50..1d858dd4f5665 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -374,11 +374,17 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { kind: Option>, ) -> InterpResult<'tcx, Cow<'b, Allocation>>; + /// Evaluate the inline assembly. + /// + /// This should take care of jumping to the next block (one of `targets`) when asm goto + /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of + /// `InlineAsmOptions::NORETURN` being set. fn eval_inline_asm( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _template: &'tcx [InlineAsmTemplatePiece], _operands: &[mir::InlineAsmOperand<'tcx>], _options: InlineAsmOptions, + _targets: &[mir::BasicBlock], ) -> InterpResult<'tcx> { throw_unsup_format!("inline assembly is not supported") } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index e72ace8be3559..9b16d99d82b38 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; -use rustc_ast::ast::InlineAsmOptions; use rustc_middle::{ mir, ty::{ @@ -224,15 +223,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator.kind ), - InlineAsm { template, ref operands, options, destination, .. } => { - M::eval_inline_asm(self, template, operands, options)?; - if options.contains(InlineAsmOptions::NORETURN) { - throw_ub_custom!(fluent::const_eval_noreturn_asm_returned); - } - self.go_to_block( - destination - .expect("InlineAsm terminators without noreturn must have a destination"), - ) + InlineAsm { template, ref operands, options, ref targets, .. } => { + M::eval_inline_asm(self, template, operands, options, targets)?; } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index cc49e8ea247f7..74ba2f6039e86 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -471,9 +471,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.check_edge(location, *real_target, EdgeKind::Normal); self.check_unwind_edge(location, *unwind); } - TerminatorKind::InlineAsm { destination, unwind, .. } => { - if let Some(destination) = destination { - self.check_edge(location, *destination, EdgeKind::Normal); + TerminatorKind::InlineAsm { targets, unwind, .. } => { + for &target in targets { + self.check_edge(location, target, EdgeKind::Normal); } self.check_unwind_edge(location, *unwind); } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3017f912ef027..de18580f61ae9 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1718,13 +1718,13 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(BasicBlockData<'_>, 136); + static_assert_size!(BasicBlockData<'_>, 144); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 72); static_assert_size!(Statement<'_>, 32); static_assert_size!(StatementKind<'_>, 16); - static_assert_size!(Terminator<'_>, 104); - static_assert_size!(TerminatorKind<'_>, 88); + static_assert_size!(Terminator<'_>, 112); + static_assert_size!(TerminatorKind<'_>, 96); static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 5638b575b319c..35058458eed7c 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -7,7 +7,7 @@ use std::path::{Path, PathBuf}; use crate::mir::interpret::ConstAllocation; use super::graphviz::write_mir_fn_graphviz; -use rustc_ast::InlineAsmTemplatePiece; +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir::interpret::{ alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, @@ -868,16 +868,19 @@ impl<'tcx> TerminatorKind<'tcx> { vec!["real".into(), "unwind".into()] } FalseUnwind { unwind: _, .. } => vec!["real".into()], - InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { - vec!["return".into(), "unwind".into()] - } - InlineAsm { destination: Some(_), unwind: _, .. } => { - vec!["return".into()] - } - InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => { - vec!["unwind".into()] + InlineAsm { options, ref targets, unwind, .. } => { + let mut vec = Vec::with_capacity(targets.len() + 1); + if !options.contains(InlineAsmOptions::NORETURN) { + vec.push("return".into()); + } + vec.resize(targets.len(), "label".into()); + + if let UnwindAction::Cleanup(_) = unwind { + vec.push("unwind".into()); + } + + vec } - InlineAsm { destination: None, unwind: _, .. } => vec![], } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 5c9857b9c53d8..6f62c7186a768 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -793,9 +793,10 @@ pub enum TerminatorKind<'tcx> { /// used to map assembler errors back to the line in the source code. line_spans: &'tcx [Span], - /// Destination block after the inline assembly returns, unless it is - /// diverging (InlineAsmOptions::NORETURN). - destination: Option, + /// Valid targets for the inline assembly. + /// The first element is the fallthrough destination, unless + /// InlineAsmOptions::NORETURN is set. + targets: Vec, /// Action to be taken if the inline assembly unwinds. This is present /// if and only if InlineAsmOptions::MAY_UNWIND is set. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 381db830aea5e..fa4a494ff0b64 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -374,8 +374,7 @@ impl<'tcx> TerminatorKind<'tcx> { | Yield { resume: ref t, drop: Some(u), .. } | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. } | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. } - | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } - | InlineAsm { destination: Some(ref t), unwind: UnwindAction::Cleanup(u), .. } => { + | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => { slice::from_ref(t).into_iter().copied().chain(Some(u)) } Goto { target: ref t } @@ -384,9 +383,7 @@ impl<'tcx> TerminatorKind<'tcx> { | Yield { resume: ref t, drop: None, .. } | Drop { target: ref t, unwind: _, .. } | Assert { target: ref t, unwind: _, .. } - | FalseUnwind { real_target: ref t, unwind: _ } - | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref t), .. } - | InlineAsm { destination: Some(ref t), unwind: _, .. } => { + | FalseUnwind { real_target: ref t, unwind: _ } => { slice::from_ref(t).into_iter().copied().chain(None) } UnwindResume @@ -394,10 +391,11 @@ impl<'tcx> TerminatorKind<'tcx> { | CoroutineDrop | Return | Unreachable - | Call { target: None, unwind: _, .. } - | InlineAsm { destination: None, unwind: _, .. } => { - (&[]).into_iter().copied().chain(None) + | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None), + InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => { + targets.iter().copied().chain(Some(u)) } + InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None), SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None), FalseEdge { ref real_target, imaginary_target } => { slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target)) @@ -413,21 +411,16 @@ impl<'tcx> TerminatorKind<'tcx> { | Yield { resume: ref mut t, drop: Some(ref mut u), .. } | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } - | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } - | InlineAsm { - destination: Some(ref mut t), - unwind: UnwindAction::Cleanup(ref mut u), - .. - } => slice::from_mut(t).into_iter().chain(Some(u)), + | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } => { + slice::from_mut(t).into_iter().chain(Some(u)) + } Goto { target: ref mut t } | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } | Call { target: Some(ref mut t), unwind: _, .. } | Yield { resume: ref mut t, drop: None, .. } | Drop { target: ref mut t, unwind: _, .. } | Assert { target: ref mut t, unwind: _, .. } - | FalseUnwind { real_target: ref mut t, unwind: _ } - | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. } - | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { + | FalseUnwind { real_target: ref mut t, unwind: _ } => { slice::from_mut(t).into_iter().chain(None) } UnwindResume @@ -435,8 +428,11 @@ impl<'tcx> TerminatorKind<'tcx> { | CoroutineDrop | Return | Unreachable - | Call { target: None, unwind: _, .. } - | InlineAsm { destination: None, unwind: _, .. } => (&mut []).into_iter().chain(None), + | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None), + InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => { + targets.iter_mut().chain(Some(u)) + } + InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None), SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None), FalseEdge { ref mut real_target, ref mut imaginary_target } => { slice::from_mut(real_target).into_iter().chain(Some(imaginary_target)) @@ -511,7 +507,7 @@ pub enum TerminatorEdges<'mir, 'tcx> { Double(BasicBlock, BasicBlock), /// Special action for `Yield`, `Call` and `InlineAsm` terminators. AssignOnReturn { - return_: Option, + return_: &'mir [BasicBlock], /// The cleanup block, if it exists. cleanup: Option, place: CallReturnPlaces<'mir, 'tcx>, @@ -575,31 +571,37 @@ impl<'tcx> TerminatorKind<'tcx> { TerminatorEdges::Double(real_target, imaginary_target) } - Yield { resume: target, drop, resume_arg, value: _ } => { + Yield { resume: ref target, drop, resume_arg, value: _ } => { TerminatorEdges::AssignOnReturn { - return_: Some(target), + return_: slice::from_ref(target), cleanup: drop, place: CallReturnPlaces::Yield(resume_arg), } } - Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => { - TerminatorEdges::AssignOnReturn { - return_: target, - cleanup: unwind.cleanup_block(), - place: CallReturnPlaces::Call(destination), - } - } + Call { + unwind, + destination, + ref target, + func: _, + args: _, + fn_span: _, + call_source: _, + } => TerminatorEdges::AssignOnReturn { + return_: target.as_ref().map(slice::from_ref).unwrap_or_default(), + cleanup: unwind.cleanup_block(), + place: CallReturnPlaces::Call(destination), + }, InlineAsm { template: _, ref operands, options: _, line_spans: _, - destination, + ref targets, unwind, } => TerminatorEdges::AssignOnReturn { - return_: destination, + return_: targets, cleanup: unwind.cleanup_block(), place: CallReturnPlaces::InlineAsm(operands), }, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 2c5ca82a4cd39..a1418b41e057f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -565,7 +565,7 @@ macro_rules! make_mir_visitor { operands, options: _, line_spans: _, - destination: _, + targets: _, unwind: _, } => { for op in operands { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 60614383cc84a..a49d864701a03 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -474,10 +474,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { operands, options, line_spans, - destination: if options.contains(InlineAsmOptions::NORETURN) { - None + targets: if options.contains(InlineAsmOptions::NORETURN) { + Vec::new() } else { - Some(destination_block) + vec![destination_block] }, unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { UnwindAction::Continue diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 3f2b7c482a67f..2c817d605af2a 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -199,9 +199,10 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor ControlFlow::Break(NonRecursive), - // A diverging InlineAsm is treated as non-recursing - TerminatorKind::InlineAsm { destination, .. } => { - if destination.is_some() { + // A InlineAsm without targets (diverging and contains no labels) + // is treated as non-recursing. + TerminatorKind::InlineAsm { ref targets, .. } => { + if !targets.is_empty() { ControlFlow::Continue(()) } else { ControlFlow::Break(NonRecursive) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 4c3fadf487b3c..f57e8b8bd6f97 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -242,9 +242,9 @@ impl Direction for Backward { propagate(pred, &tmp); } - mir::TerminatorKind::InlineAsm { - destination: Some(dest), ref operands, .. - } if dest == bb => { + mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. } + if targets.contains(&bb) => + { let mut tmp = exit_state.clone(); analysis.apply_call_return_effect( &mut tmp, @@ -491,9 +491,12 @@ impl Direction for Forward { if let Some(cleanup) = cleanup { propagate(cleanup, exit_state); } - if let Some(return_) = return_ { + + if !return_.is_empty() { analysis.apply_call_return_effect(exit_state, bb, place); - propagate(return_, exit_state); + for &target in return_ { + propagate(target, exit_state); + } } } TerminatorEdges::SwitchInt { targets, discr } => { diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 0270e059a5821..a827f6a8dbd9d 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -299,7 +299,9 @@ where })?; } - mir::TerminatorKind::InlineAsm { destination: Some(_), ref operands, .. } => { + mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. } + if !targets.is_empty() => + { self.write_row(w, "", "(on successful return)", |this, w, fmt| { let state_on_unwind = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index c6ec1b5aee454..95f12301395c3 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -491,7 +491,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { ref operands, options: _, line_spans: _, - destination: _, + targets: _, unwind: _, } => { for op in operands { diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index c97192435ce48..ed8c4d8283d98 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -349,12 +349,20 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | FalseUnwind { real_target: target, .. } | Goto { target } => CoverageSuccessors::Chainable(target), - // These terminators can normally be chained, except when they have no + // A call terminator can normally be chained, except when they have no // successor because they are known to diverge. - Call { target: maybe_target, .. } | InlineAsm { destination: maybe_target, .. } => { - match maybe_target { - Some(target) => CoverageSuccessors::Chainable(target), - None => CoverageSuccessors::NotChainable(&[]), + Call { target: maybe_target, .. } => match maybe_target { + Some(target) => CoverageSuccessors::Chainable(target), + None => CoverageSuccessors::NotChainable(&[]), + }, + + // An inline asm terminator can normally be chained, except when it diverges or uses asm + // goto. + InlineAsm { ref targets, .. } => { + if targets.len() == 1 { + CoverageSuccessors::Chainable(targets[0]) + } else { + CoverageSuccessors::NotChainable(targets) } } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index d9a3c0cb162f3..569998de35e0b 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -88,7 +88,6 @@ impl<'tcx> MockBlocks<'tcx> { | TerminatorKind::FalseEdge { real_target: ref mut target, .. } | TerminatorKind::FalseUnwind { real_target: ref mut target, .. } | TerminatorKind::Goto { ref mut target } - | TerminatorKind::InlineAsm { destination: Some(ref mut target), .. } | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block, ref invalid => bug!("Invalid from_block: {:?}", invalid), } @@ -185,10 +184,12 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String { | TerminatorKind::FalseEdge { real_target: target, .. } | TerminatorKind::FalseUnwind { real_target: target, .. } | TerminatorKind::Goto { target } - | TerminatorKind::InlineAsm { destination: Some(target), .. } | TerminatorKind::Yield { resume: target, .. } => { format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), target) } + TerminatorKind::InlineAsm { targets, .. } => { + format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), targets) + } TerminatorKind::SwitchInt { targets, .. } => { format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), targets) } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 2009539d4d084..a6382584577ce 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1032,8 +1032,8 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { { bug!("False unwinds should have been removed before inlining") } - TerminatorKind::InlineAsm { ref mut destination, ref mut unwind, .. } => { - if let Some(ref mut tgt) = *destination { + TerminatorKind::InlineAsm { ref mut targets, ref mut unwind, .. } => { + for tgt in targets.iter_mut() { *tgt = self.map_block(*tgt); } *unwind = self.map_unwind(*unwind); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 501d6f7d304ef..92e86cf0ee41e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -632,14 +632,15 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { operands, options, line_spans, - destination, + targets, unwind, } => TerminatorKind::InlineAsm { template: format!("{template:?}"), operands: operands.iter().map(|operand| operand.stable(tables)).collect(), options: format!("{options:?}"), line_spans: format!("{line_spans:?}"), - destination: destination.map(|d| d.as_usize()), + // FIXME: Figure out how to do labels in SMIR + destination: targets.first().map(|d| d.as_usize()), unwind: unwind.stable(tables), }, mir::TerminatorKind::Yield { .. } From 3b1dd1bfa97aa9775109266f9932027a99362b0d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 16:07:35 +0000 Subject: [PATCH 10/26] Implement asm goto in MIR and MIR lowering --- compiler/rustc_borrowck/src/lib.rs | 3 +- .../src/polonius/loan_invalidations.rs | 3 +- .../rustc_codegen_cranelift/src/global_asm.rs | 3 +- .../rustc_codegen_cranelift/src/inline_asm.rs | 3 ++ compiler/rustc_codegen_ssa/src/mir/block.rs | 3 ++ compiler/rustc_middle/src/mir/pretty.rs | 3 ++ compiler/rustc_middle/src/mir/syntax.rs | 4 +++ compiler/rustc_middle/src/mir/visit.rs | 3 +- .../rustc_mir_build/src/build/expr/into.rs | 33 ++++++++++++++----- .../src/impls/storage_liveness.rs | 3 +- .../src/move_paths/builder.rs | 3 +- compiler/rustc_mir_transform/src/dest_prop.rs | 3 +- .../rustc_smir/src/rustc_smir/convert/mir.rs | 3 +- 13 files changed, 53 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 94c1875608387..b776643763a7e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -749,7 +749,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } InlineAsmOperand::Const { value: _ } | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } + | InlineAsmOperand::Label { target_index: _ } => {} } } } diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 83081f83e5e80..956de1dec9b2b 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -182,7 +182,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> { } InlineAsmOperand::Const { value: _ } | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } + | InlineAsmOperand::Label { target_index: _ } => {} } } } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index da07b66c762ee..44650898de897 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -78,7 +78,8 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, InlineAsmOperand::In { .. } | InlineAsmOperand::Out { .. } | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } => { + | InlineAsmOperand::SplitInOut { .. } + | InlineAsmOperand::Label { .. } => { span_bug!(op_sp, "invalid operand type for global_asm!") } } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 7793b1b70924b..171ee88a11c75 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -129,6 +129,9 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() } } + InlineAsmOperand::Label { .. } => { + span_bug!(span, "asm! label operands are not yet supported"); + } }) .collect::>(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6342802bb1960..c9a1e7789c27e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1119,6 +1119,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::InlineAsmOperand::SymStatic { def_id } => { InlineAsmOperandRef::SymStatic { def_id } } + mir::InlineAsmOperand::Label { target_index: _ } => { + todo!(); + } }) .collect(); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 35058458eed7c..e058302af312c 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -830,6 +830,9 @@ impl<'tcx> TerminatorKind<'tcx> { InlineAsmOperand::SymStatic { def_id } => { write!(fmt, "sym_static {def_id:?}")?; } + InlineAsmOperand::Label { target_index } => { + write!(fmt, "label {target_index}")?; + } } } write!(fmt, ", options({options:?}))") diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6f62c7186a768..f188923f87618 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -919,6 +919,10 @@ pub enum InlineAsmOperand<'tcx> { SymStatic { def_id: DefId, }, + Label { + /// This represents the index into the `targets` array in `TerminatorKind::InlineAsm`. + target_index: usize, + }, } /// Type for MIR `Assert` terminator error messages. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index a1418b41e057f..845b17175505d 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -595,7 +595,8 @@ macro_rules! make_mir_visitor { self.visit_constant(value, location); } InlineAsmOperand::Out { place: None, .. } - | InlineAsmOperand::SymStatic { def_id: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } + | InlineAsmOperand::Label { target_index: _ } => {} } } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a49d864701a03..09e518606e314 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -400,6 +400,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { line_spans, }) => { use rustc_middle::{mir, thir}; + + let destination_block = this.cfg.start_new_block(); + let mut targets = if options.contains(InlineAsmOptions::NORETURN) { + vec![] + } else { + vec![destination_block] + }; + let operands = operands .into_iter() .map(|op| match *op { @@ -455,17 +463,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } - thir::InlineAsmOperand::Label { .. } => { - todo!() + thir::InlineAsmOperand::Label { block } => { + let target = this.cfg.start_new_block(); + let target_index = targets.len(); + targets.push(target); + + let tmp = this.get_unit_temp(); + let target = unpack!(this.ast_block(tmp, target, block, source_info)); + this.cfg.terminate( + target, + source_info, + TerminatorKind::Goto { target: destination_block }, + ); + + mir::InlineAsmOperand::Label { target_index } } }) .collect(); - if !options.contains(InlineAsmOptions::NORETURN) { + if !expr.ty.is_never() { this.cfg.push_assign_unit(block, source_info, destination, this.tcx); } - let destination_block = this.cfg.start_new_block(); this.cfg.terminate( block, source_info, @@ -474,11 +493,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { operands, options, line_spans, - targets: if options.contains(InlineAsmOptions::NORETURN) { - Vec::new() - } else { - vec![destination_block] - }, + targets, unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { UnwindAction::Continue } else { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 595c2ff5bf7fa..29169c31263bd 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -271,7 +271,8 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { InlineAsmOperand::In { .. } | InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => {} + | InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Label { .. } => {} } } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 95f12301395c3..db48ecd702bdb 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -515,7 +515,8 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { } InlineAsmOperand::Const { value: _ } | InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { def_id: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } + | InlineAsmOperand::Label { target_index: _ } => {} } } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 2c8201b1903e6..10fea09531a65 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -648,7 +648,8 @@ impl WriteInfo { } InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => (), + | InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Label { .. } => {} } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 92e86cf0ee41e..003a9a5920018 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -559,7 +559,8 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { } InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => (None, None), + | InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Label { .. } => (None, None), }; stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") } From 27e6ee102ed359a3744ac1f2dffbfb7a60bd2371 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 04:20:35 +0000 Subject: [PATCH 11/26] Add callbr support to LLVM wrapper --- compiler/rustc_codegen_llvm/src/builder.rs | 52 +++++++++++++++++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 14 +++++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 25 +++++++++ 3 files changed, 91 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8cab2a3f27c1b..eda3c583994a0 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1547,6 +1547,58 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } } + pub(crate) fn callbr( + &mut self, + llty: &'ll Type, + fn_attrs: Option<&CodegenFnAttrs>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + llfn: &'ll Value, + args: &[&'ll Value], + default_dest: &'ll BasicBlock, + indirect_dest: &[&'ll BasicBlock], + funclet: Option<&Funclet<'ll>>, + ) -> &'ll Value { + debug!("invoke {:?} with args ({:?})", llfn, args); + + let args = self.check_call("callbr", llty, llfn, args); + let funclet_bundle = funclet.map(|funclet| funclet.bundle()); + let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); + let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); + if let Some(funclet_bundle) = funclet_bundle { + bundles.push(funclet_bundle); + } + + // Emit CFI pointer type membership test + self.cfi_type_test(fn_attrs, fn_abi, llfn); + + // Emit KCFI operand bundle + let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn); + let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); + if let Some(kcfi_bundle) = kcfi_bundle { + bundles.push(kcfi_bundle); + } + + let callbr = unsafe { + llvm::LLVMRustBuildCallBr( + self.llbuilder, + llty, + llfn, + default_dest, + indirect_dest.as_ptr(), + indirect_dest.len() as c_uint, + args.as_ptr(), + args.len() as c_uint, + bundles.as_ptr(), + bundles.len() as c_uint, + UNNAMED, + ) + }; + if let Some(fn_abi) = fn_abi { + fn_abi.apply_attrs_callsite(self, callbr); + } + callbr + } + // Emits CFI pointer type membership tests. fn cfi_type_test( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index dbf35e5f49952..22c67436d3619 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1617,6 +1617,20 @@ extern "C" { Name: *const c_char, ) -> &'a Value; + pub fn LLVMRustBuildCallBr<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + DefaultDest: &'a BasicBlock, + IndirectDests: *const &'a BasicBlock, + NumIndirectDests: c_uint, + Args: *const &'a Value, + NumArgs: c_uint, + OpBundles: *const &OperandBundleDef<'a>, + NumOpBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub fn LLVMRustSetFastMath(Instr: &Value); pub fn LLVMRustSetAlgebraicMath(Instr: &Value); pub fn LLVMRustSetAllowReassoc(Instr: &Value); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index af2353fbb19c5..63714de1fc64d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1539,6 +1539,31 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, Name)); } +extern "C" LLVMValueRef +LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, + LLVMBasicBlockRef DefaultDest, + LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, + LLVMValueRef *Args, unsigned NumArgs, + OperandBundleDef **OpBundles, unsigned NumOpBundles, + const char *Name) { + Value *Callee = unwrap(Fn); + FunctionType *FTy = unwrap(Ty); + + // FIXME: Is there a way around this? + std::vector IndirectDestsUnwrapped; + IndirectDestsUnwrapped.reserve(NumIndirectDests); + for (unsigned i = 0; i < NumIndirectDests; ++i) { + IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i])); + } + + return wrap(unwrap(B)->CreateCallBr( + FTy, Callee, unwrap(DefaultDest), + ArrayRef(IndirectDestsUnwrapped), + ArrayRef(unwrap(Args), NumArgs), + ArrayRef(*OpBundles, NumOpBundles), + Name)); +} + extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockRef BB) { auto Point = unwrap(BB)->getFirstInsertionPt(); From 5e4fd6bc2301a8e267d044a526ffb77c1a6c35d7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 27 Dec 2023 04:08:04 +0000 Subject: [PATCH 12/26] Implement asm goto for LLVM and GCC backend --- compiler/rustc_codegen_gcc/src/asm.rs | 31 ++++++++++++++-- compiler/rustc_codegen_llvm/src/asm.rs | 29 +++++++++------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 ++ compiler/rustc_codegen_ssa/src/mir/block.rs | 38 +++++++++++++++----- compiler/rustc_codegen_ssa/src/traits/asm.rs | 6 +++- 5 files changed, 84 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 78e8e32b97299..07edd26e27a42 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -107,7 +107,7 @@ enum ConstraintOrRegister { impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { - fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) { + fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, dest: Option, _catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>) { if options.contains(InlineAsmOptions::MAY_UNWIND) { self.sess().dcx() .create_err(UnwindingInlineAsm { span: span[0] }) @@ -126,6 +126,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // added to `outputs.len()` let mut inputs = vec![]; + // GCC index of a label equals its position in the array added to + // `outputs.len() + inputs.len()`. + let mut labels = vec![]; + // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _` let mut clobbers = vec![]; @@ -269,6 +273,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // some targets to add a leading underscore (Mach-O). constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); } + + InlineAsmOperandRef::Label { label } => { + labels.push(label); + } } } @@ -368,6 +376,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::Const { .. } => { // processed in the previous pass } + + InlineAsmOperandRef::Label { .. } => { + // processed in the previous pass + } } } @@ -454,6 +466,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::Const { ref string } => { template_str.push_str(string); } + + InlineAsmOperandRef::Label { label } => { + let label_gcc_index = labels.iter() + .position(|&l| l == label) + .expect("wrong rust index"); + let gcc_index = label_gcc_index + outputs.len() + inputs.len(); + push_to_template(Some('l'), gcc_index); + } } } } @@ -466,7 +486,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // 4. Generate Extended Asm block let block = self.llbb(); - let extended_asm = block.add_extended_asm(None, &template_str); + let extended_asm = if let Some(dest) = dest { + assert!(!labels.is_empty()); + block.end_with_extended_asm_goto(None, &template_str, &labels, Some(dest)) + } else { + block.add_extended_asm(None, &template_str) + }; for op in &outputs { extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var); @@ -494,7 +519,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if !options.contains(InlineAsmOptions::NOSTACK) { // TODO(@Commeownist): figure out how to align stack } - if options.contains(InlineAsmOptions::NORETURN) { + if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) { let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; self.call(self.type_void(), None, None, builtin_unreachable, &[], None); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a413466093bed..f5d0b3c465729 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -28,7 +28,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { options: InlineAsmOptions, line_spans: &[Span], instance: Instance<'_>, - dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>, + dest: Option, + catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); @@ -165,6 +166,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } // Build the template string + let mut labels = vec![]; let mut template_str = String::new(); for piece in template { match *piece { @@ -205,6 +207,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // Only emit the raw symbol name template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx])); } + InlineAsmOperandRef::Label { label } => { + template_str.push_str(&format!("${{{}:l}}", constraints.len())); + constraints.push("!i".to_owned()); + labels.push(label); + } } } } @@ -292,12 +299,14 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { &constraints.join(","), &inputs, output_type, + &labels, volatile, alignstack, dialect, line_spans, options.contains(InlineAsmOptions::MAY_UNWIND), - dest_catch_funclet, + dest, + catch_funclet, ) .unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed")); @@ -317,7 +326,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); // Switch to the 'normal' basic block if we did an `invoke` instead of a `call` - if let Some((dest, _, _)) = dest_catch_funclet { + if let Some(dest) = dest { self.switch_to_block(dest); } @@ -415,16 +424,14 @@ pub(crate) fn inline_asm_call<'ll>( cons: &str, inputs: &[&'ll Value], output: &'ll llvm::Type, + labels: &[&'ll llvm::BasicBlock], volatile: bool, alignstack: bool, dia: llvm::AsmDialect, line_spans: &[Span], unwind: bool, - dest_catch_funclet: Option<( - &'ll llvm::BasicBlock, - &'ll llvm::BasicBlock, - Option<&Funclet<'ll>>, - )>, + dest: Option<&'ll llvm::BasicBlock>, + catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>, ) -> Option<&'ll Value> { let volatile = if volatile { llvm::True } else { llvm::False }; let alignstack = if alignstack { llvm::True } else { llvm::False }; @@ -457,8 +464,10 @@ pub(crate) fn inline_asm_call<'ll>( can_throw, ); - let call = if let Some((dest, catch, funclet)) = dest_catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest, catch, funclet) + let call = if !labels.is_empty() { + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None) + } else if let Some((catch, funclet)) = catch_funclet { + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet) } else { bx.call(fty, None, None, v, inputs, None) }; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 23e6f054a7c1e..ee76038800fd3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -377,12 +377,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { constraint, inputs, self.type_void(), + &[], true, false, llvm::AsmDialect::Att, &[span], false, None, + None, ) .unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`")); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index c9a1e7789c27e..2eba489cbfbf8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mir::UnwindAction::Unreachable => None, }; - if let Some(cleanup) = unwind_target { + if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { let ret_llbb = if let Some(target) = destination { fx.llbb(target) } else { @@ -277,11 +277,29 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { options, line_spans, instance, - Some((ret_llbb, cleanup, self.funclet(fx))), + Some(ret_llbb), + None, + ); + MergingSucc::False + } else if let Some(cleanup) = unwind_target { + let ret_llbb = if let Some(target) = destination { + fx.llbb(target) + } else { + fx.unreachable_block() + }; + + bx.codegen_inline_asm( + template, + operands, + options, + line_spans, + instance, + Some(ret_llbb), + Some((cleanup, self.funclet(fx))), ); MergingSucc::False } else { - bx.codegen_inline_asm(template, operands, options, line_spans, instance, None); + bx.codegen_inline_asm(template, operands, options, line_spans, instance, None, None); if let Some(target) = destination { self.funclet_br(fx, bx, target, mergeable_succ) @@ -1067,7 +1085,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operands: &[mir::InlineAsmOperand<'tcx>], options: ast::InlineAsmOptions, line_spans: &[Span], - destination: Option, + targets: &[mir::BasicBlock], unwind: mir::UnwindAction, instance: Instance<'_>, mergeable_succ: bool, @@ -1119,8 +1137,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::InlineAsmOperand::SymStatic { def_id } => { InlineAsmOperandRef::SymStatic { def_id } } - mir::InlineAsmOperand::Label { target_index: _ } => { - todo!(); + mir::InlineAsmOperand::Label { target_index } => { + InlineAsmOperandRef::Label { label: self.llbb(targets[target_index]) } } }) .collect(); @@ -1132,7 +1150,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &operands, options, line_spans, - destination, + if options.contains(InlineAsmOptions::NORETURN) { + None + } else { + targets.get(0).copied() + }, unwind, instance, mergeable_succ, @@ -1298,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operands, options, line_spans, - targets.get(0).copied(), + targets, unwind, self.instance, mergeable_succ(), diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index c2ae74b18d81e..8d67b626bbdb5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -33,6 +33,9 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { SymStatic { def_id: DefId, }, + Label { + label: B::BasicBlock, + }, } #[derive(Debug)] @@ -51,7 +54,8 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { options: InlineAsmOptions, line_spans: &[Span], instance: Instance<'_>, - dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>, + dest: Option, + catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, ); } From 5e4e3d790bb5e53b31abf58fd0e2be557c28d496 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 04:44:01 +0000 Subject: [PATCH 13/26] Ensure asm noreturn works with labels --- compiler/rustc_hir_typeck/src/expr.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 614761c03bd61..ba74476c36dc7 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3243,6 +3243,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { + let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN); + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } => { @@ -3265,15 +3267,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {} hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Label { block } => { - self.check_block_no_value(block); + let previous_diverges = self.diverges.get(); + + // The label blocks should have unit return value or diverge. + let ty = + self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit)); + if !ty.is_never() { + self.demand_suptype(block.span, self.tcx.types.unit, ty); + diverge = false; + } + + // We need this to avoid false unreachable warning when a label diverges. + self.diverges.set(previous_diverges); } } } - if asm.options.contains(ast::InlineAsmOptions::NORETURN) { - self.tcx.types.never - } else { - Ty::new_unit(self.tcx) - } + + if diverge { self.tcx.types.never } else { self.tcx.types.unit } } fn check_offset_of( From 31f078ea9941ce89f1f5ab5fb1239bbbddfe4d49 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 26 Dec 2023 04:44:22 +0000 Subject: [PATCH 14/26] Forbid asm unwind to work with labels --- compiler/rustc_builtin_macros/messages.ftl | 2 ++ compiler/rustc_builtin_macros/src/asm.rs | 7 +++++++ compiler/rustc_builtin_macros/src/errors.rs | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index dda466b026d91..32e065ada51b1 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -19,6 +19,8 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names +builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option + builtin_macros_asm_modifier_invalid = asm template modifier must be a single character builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 93eb3a9a43ee3..85f009f7e63cd 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -245,6 +245,7 @@ pub fn parse_asm_args<'a>( let mut have_real_output = false; let mut outputs_sp = vec![]; let mut regclass_outputs = vec![]; + let mut labels_sp = vec![]; for (op, op_sp) in &args.operands { match op { ast::InlineAsmOperand::Out { reg, expr, .. } @@ -262,6 +263,9 @@ pub fn parse_asm_args<'a>( regclass_outputs.push(*op_sp); } } + ast::InlineAsmOperand::Label { .. } => { + labels_sp.push(*op_sp); + } _ => {} } } @@ -273,6 +277,9 @@ pub fn parse_asm_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } + if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() { + dcx.emit_err(errors::AsmMayUnwind { labels_sp }); + } if args.clobber_abis.len() > 0 { if is_global_asm { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f304a37be854b..51f7fcd628bc0 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -787,6 +787,13 @@ pub(crate) struct AsmNoReturn { pub(crate) outputs_sp: Vec, } +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_mayunwind)] +pub(crate) struct AsmMayUnwind { + #[primary_span] + pub(crate) labels_sp: Vec, +} + #[derive(Diagnostic)] #[diag(builtin_macros_global_asm_clobber_abi)] pub(crate) struct GlobalAsmClobberAbi { From 4677a71369f690b5aecf9380cf12074792f09a3f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 27 Dec 2023 22:57:17 +0000 Subject: [PATCH 15/26] Add tests for asm goto --- tests/codegen/asm-goto.rs | 51 ++++++++ tests/ui/asm/parse-error.rs | 2 + tests/ui/asm/parse-error.stderr | 16 ++- tests/ui/asm/x86_64/bad-options.rs | 4 + tests/ui/asm/x86_64/bad-options.stderr | 38 +++--- tests/ui/asm/x86_64/goto.mirunsafeck.stderr | 23 ++++ tests/ui/asm/x86_64/goto.rs | 111 ++++++++++++++++++ tests/ui/asm/x86_64/goto.thirunsafeck.stderr | 23 ++++ .../ui/feature-gates/feature-gate-asm_goto.rs | 10 ++ .../feature-gate-asm_goto.stderr | 13 ++ 10 files changed, 270 insertions(+), 21 deletions(-) create mode 100644 tests/codegen/asm-goto.rs create mode 100644 tests/ui/asm/x86_64/goto.mirunsafeck.stderr create mode 100644 tests/ui/asm/x86_64/goto.rs create mode 100644 tests/ui/asm/x86_64/goto.thirunsafeck.stderr create mode 100644 tests/ui/feature-gates/feature-gate-asm_goto.rs create mode 100644 tests/ui/feature-gates/feature-gate-asm_goto.stderr diff --git a/tests/codegen/asm-goto.rs b/tests/codegen/asm-goto.rs new file mode 100644 index 0000000000000..e522d0da5b405 --- /dev/null +++ b/tests/codegen/asm-goto.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -O +//@ only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm_goto)] + +use std::arch::asm; + +#[no_mangle] +pub extern "C" fn panicky() {} + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + println!(); + } +} + +// CHECK-LABEL: @asm_goto +#[no_mangle] +pub unsafe fn asm_goto() { + // CHECK: callbr void asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("jmp {}", label {}); +} + +// CHECK-LABEL: @asm_goto_with_outputs +#[no_mangle] +pub unsafe fn asm_goto_with_outputs() -> u64 { + let out: u64; + // CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]] + asm!("{} /* {} */", out(reg) out, label { return 1; }); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: [[RET:%.+]] = phi i64 [ [[RES]], %[[FALLTHROUGHBB]] ], [ 1, %start ] + // CHECK-NEXT: ret i64 [[RET]] + out +} + +// CHECK-LABEL: @asm_goto_noreturn +#[no_mangle] +pub unsafe fn asm_goto_noreturn() -> u64 { + let out: u64; + // CHECK: callbr void asm sideeffect alignstack inteldialect " + // CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]] + asm!("jmp {}", label { return 1; }, options(noreturn)); + // CHECK: [[JUMPBB]]: + // CHECK-NEXT: ret i64 1 + out +} diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs index 6f32293511bf6..a0251c6763ba4 100644 --- a/tests/ui/asm/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -142,3 +142,5 @@ global_asm!(format!("{{{}}}", 0), const FOO); //~^ ERROR asm template must be a string literal global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); //~^ ERROR asm template must be a string literal +global_asm!("{}", label {}); +//~^ ERROR expected operand, options, or additional template string diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 075d28e176ad8..80ee5191dbbe9 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -176,17 +176,17 @@ LL | asm!("{a}", a = const foo, a = const bar); | = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` --> $DIR/parse-error.rs:82:29 | LL | asm!("", options(), ""); - | ^^ expected one of 9 possible tokens + | ^^ expected one of 10 possible tokens -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"` --> $DIR/parse-error.rs:84:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); - | ^^^^ expected one of 9 possible tokens + | ^^^^ expected one of 10 possible tokens error: asm template must be a string literal --> $DIR/parse-error.rs:86:14 @@ -362,6 +362,12 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:145:19 + | +LL | global_asm!("{}", label {}); + | ^^^^^^^^ expected operand, options, or additional template string + error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 | @@ -407,6 +413,6 @@ LL | let mut bar = 0; LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value -error: aborting due to 63 previous errors +error: aborting due to 64 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/x86_64/bad-options.rs b/tests/ui/asm/x86_64/bad-options.rs index a6d5022ecf130..f9cc13cfc5a8b 100644 --- a/tests/ui/asm/x86_64/bad-options.rs +++ b/tests/ui/asm/x86_64/bad-options.rs @@ -1,5 +1,7 @@ //@ only-x86_64 +#![feature(asm_unwind, asm_goto)] + use std::arch::{asm, global_asm}; fn main() { @@ -14,6 +16,8 @@ fn main() { //~^ ERROR asm with the `pure` option must have at least one output asm!("{}", out(reg) foo, options(noreturn)); //~^ ERROR asm outputs are not allowed with the `noreturn` option + asm!("{}", label {}, options(may_unwind)); + //~^ ERROR asm labels are not allowed with the `may_unwind` option } unsafe { diff --git a/tests/ui/asm/x86_64/bad-options.stderr b/tests/ui/asm/x86_64/bad-options.stderr index e2351840eef21..aa167e7913c3e 100644 --- a/tests/ui/asm/x86_64/bad-options.stderr +++ b/tests/ui/asm/x86_64/bad-options.stderr @@ -1,35 +1,41 @@ error: the `nomem` and `readonly` options are mutually exclusive - --> $DIR/bad-options.rs:8:18 + --> $DIR/bad-options.rs:10:18 | LL | asm!("", options(nomem, readonly)); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: the `pure` and `noreturn` options are mutually exclusive - --> $DIR/bad-options.rs:10:18 + --> $DIR/bad-options.rs:12:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:10:18 + --> $DIR/bad-options.rs:12:18 | LL | asm!("", options(pure, nomem, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm with the `pure` option must have at least one output - --> $DIR/bad-options.rs:13:33 + --> $DIR/bad-options.rs:15:33 | LL | asm!("{}", in(reg) foo, options(pure, nomem)); | ^^^^^^^^^^^^^^^^^^^^ error: asm outputs are not allowed with the `noreturn` option - --> $DIR/bad-options.rs:15:20 + --> $DIR/bad-options.rs:17:20 | LL | asm!("{}", out(reg) foo, options(noreturn)); | ^^^^^^^^^^^^ +error: asm labels are not allowed with the `may_unwind` option + --> $DIR/bad-options.rs:19:20 + | +LL | asm!("{}", label {}, options(may_unwind)); + | ^^^^^^^^ + error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:22:20 + --> $DIR/bad-options.rs:26:20 | LL | asm!("{}", out(reg) foo, clobber_abi("C")); | ^^^^^^^^^^^^ ---------------- clobber_abi @@ -37,7 +43,7 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C")); | generic outputs error: asm with `clobber_abi` must specify explicit registers for outputs - --> $DIR/bad-options.rs:24:20 + --> $DIR/bad-options.rs:28:20 | LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi @@ -46,43 +52,43 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | generic outputs error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/bad-options.rs:31:25 + --> $DIR/bad-options.rs:35:25 | LL | global_asm!("", options(nomem)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` - --> $DIR/bad-options.rs:33:25 + --> $DIR/bad-options.rs:37:25 | LL | global_asm!("", options(readonly)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` - --> $DIR/bad-options.rs:35:25 + --> $DIR/bad-options.rs:39:25 | LL | global_asm!("", options(noreturn)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `pure` - --> $DIR/bad-options.rs:37:25 + --> $DIR/bad-options.rs:41:25 | LL | global_asm!("", options(pure)); | ^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` - --> $DIR/bad-options.rs:39:25 + --> $DIR/bad-options.rs:43:25 | LL | global_asm!("", options(nostack)); | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` - --> $DIR/bad-options.rs:41:25 + --> $DIR/bad-options.rs:45:25 | LL | global_asm!("", options(preserves_flags)); | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: invalid ABI for `clobber_abi` - --> $DIR/bad-options.rs:20:18 + --> $DIR/bad-options.rs:24:18 | LL | asm!("", clobber_abi("foo")); | ^^^^^^^^^^^^^^^^^^ @@ -90,12 +96,12 @@ LL | asm!("", clobber_abi("foo")); = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` error: `C` ABI specified multiple times - --> $DIR/bad-options.rs:24:52 + --> $DIR/bad-options.rs:28:52 | LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | ---------------- ^^^^^^^^^^^^^^^^ | | | previously specified here -error: aborting due to 15 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/asm/x86_64/goto.mirunsafeck.stderr b/tests/ui/asm/x86_64/goto.mirunsafeck.stderr new file mode 100644 index 0000000000000..fe189c14f0a7c --- /dev/null +++ b/tests/ui/asm/x86_64/goto.mirunsafeck.stderr @@ -0,0 +1,23 @@ +warning: unreachable statement + --> $DIR/goto.rs:99:9 + | +LL | / asm!( +LL | | "jmp {}", +LL | | label { +LL | | return; +LL | | }, +LL | | options(noreturn) +LL | | ); + | |_________- any code following this expression is unreachable +LL | unreachable!(); + | ^^^^^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/goto.rs:89:8 + | +LL | #[warn(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/asm/x86_64/goto.rs b/tests/ui/asm/x86_64/goto.rs new file mode 100644 index 0000000000000..6a567efbb2c7e --- /dev/null +++ b/tests/ui/asm/x86_64/goto.rs @@ -0,0 +1,111 @@ +//@ only-x86_64 +//@ run-pass +//@ needs-asm-support +//@ revisions: mirunsafeck thirunsafeck +//@ [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![deny(unreachable_code)] +#![feature(asm_goto)] + +use std::arch::asm; + +fn goto_fallthough() { + unsafe { + asm!( + "/* {} */", + label { + unreachable!(); + } + ) + } +} + +fn goto_jump() { + unsafe { + let mut value = false; + asm!( + "jmp {}", + label { + value = true; + } + ); + assert!(value); + } +} + +// asm goto with outputs cause miscompilation in LLVM. UB can be triggered +// when outputs are used inside the label block when optimisation is enabled. +// See: https://github.com/llvm/llvm-project/issues/74483 +/* +fn goto_out_fallthrough() { + unsafe { + let mut out: usize; + asm!( + "lea {}, [{} + 1]", + "/* {} */", + out(reg) out, + in(reg) 0x12345678usize, + label { + unreachable!(); + } + ); + assert_eq!(out, 0x12345679); + } +} + +fn goto_out_jump() { + unsafe { + let mut value = false; + let mut out: usize; + asm!( + "lea {}, [{} + 1]", + "jmp {}", + out(reg) out, + in(reg) 0x12345678usize, + label { + value = true; + assert_eq!(out, 0x12345679); + } + ); + assert!(value); + } +} +*/ + +fn goto_noreturn() { + unsafe { + let a; + asm!( + "jmp {}", + label { + a = 1; + }, + options(noreturn) + ); + assert_eq!(a, 1); + } +} + +#[warn(unreachable_code)] +fn goto_noreturn_diverge() { + unsafe { + asm!( + "jmp {}", + label { + return; + }, + options(noreturn) + ); + unreachable!(); + //~^ WARN unreachable statement + } +} + +fn main() { + goto_fallthough(); + goto_jump(); + // goto_out_fallthrough(); + // goto_out_jump(); + goto_noreturn(); + goto_noreturn_diverge(); +} diff --git a/tests/ui/asm/x86_64/goto.thirunsafeck.stderr b/tests/ui/asm/x86_64/goto.thirunsafeck.stderr new file mode 100644 index 0000000000000..fe189c14f0a7c --- /dev/null +++ b/tests/ui/asm/x86_64/goto.thirunsafeck.stderr @@ -0,0 +1,23 @@ +warning: unreachable statement + --> $DIR/goto.rs:99:9 + | +LL | / asm!( +LL | | "jmp {}", +LL | | label { +LL | | return; +LL | | }, +LL | | options(noreturn) +LL | | ); + | |_________- any code following this expression is unreachable +LL | unreachable!(); + | ^^^^^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/goto.rs:89:8 + | +LL | #[warn(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this warning originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-asm_goto.rs b/tests/ui/feature-gates/feature-gate-asm_goto.rs new file mode 100644 index 0000000000000..beac4590349f6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_goto.rs @@ -0,0 +1,10 @@ +//@ only-x86_64 + +use std::arch::asm; + +fn main() { + unsafe { + asm!("jmp {}", label {}); + //~^ ERROR label operands for inline assembly are unstable + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_goto.stderr b/tests/ui/feature-gates/feature-gate-asm_goto.stderr new file mode 100644 index 0000000000000..62fd1a320d3c0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_goto.stderr @@ -0,0 +1,13 @@ +error[E0658]: label operands for inline assembly are unstable + --> $DIR/feature-gate-asm_goto.rs:7:24 + | +LL | asm!("jmp {}", label {}); + | ^^^^^^^^ + | + = note: see issue #119364 for more information + = help: add `#![feature(asm_goto)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 84bc9e9e369ba23a244d9a6b8c047e6f1e0d6e7a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 28 Dec 2023 18:57:15 +0000 Subject: [PATCH 16/26] Add asm-goto to unstable book --- .../src/language-features/asm-goto.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/asm-goto.md diff --git a/src/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md new file mode 100644 index 0000000000000..a9ad5e837448a --- /dev/null +++ b/src/doc/unstable-book/src/language-features/asm-goto.md @@ -0,0 +1,24 @@ +# `asm_goto` + +The tracking issue for this feature is: [#119364] + +[#119364]: https://github.com/rust-lang/rust/issues/119364 + +------------------------ + +This feature adds a `label ` operand type to `asm!`. + +Example: +```rust,ignore (partial-example, x86-only) + +unsafe { + asm!( + "jmp {}", + label { + println!("Jumped from asm!"); + } + ); +} +``` + +The block must have unit type. From 626a5f589208d544537f411724f35e6b841790e4 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 24 Feb 2024 17:12:25 +0000 Subject: [PATCH 17/26] Add assertions and clarify asm-goto with noreturn --- compiler/rustc_codegen_llvm/src/asm.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + src/doc/unstable-book/src/language-features/asm-goto.md | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index f5d0b3c465729..74539d4d49570 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -465,6 +465,7 @@ pub(crate) fn inline_asm_call<'ll>( ); let call = if !labels.is_empty() { + assert!(catch_funclet.is_none()); bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None) } else if let Some((catch, funclet)) = catch_funclet { bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 2eba489cbfbf8..8a2f91c082e27 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -265,6 +265,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { }; if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { + assert!(unwind_target.is_none()); let ret_llbb = if let Some(target) = destination { fx.llbb(target) } else { diff --git a/src/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md index a9ad5e837448a..d72eb7c0c6ef1 100644 --- a/src/doc/unstable-book/src/language-features/asm-goto.md +++ b/src/doc/unstable-book/src/language-features/asm-goto.md @@ -21,4 +21,10 @@ unsafe { } ``` -The block must have unit type. +The block must have unit type or diverge. + +When `label ` is used together with `noreturn` option, it means that the +assembly will not fallthrough. It's allowed to jump to a label within the +assembly. In this case, the entire `asm!` expression will have an unit type as +opposed to diverging, if not all label blocks diverge. The `asm!` expression +still diverges if `noreturn` option is used and all label blocks diverge. From 8212fc513c66ebd9996180456305ecd6c425d5da Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Sun, 3 Mar 2024 12:57:28 +0100 Subject: [PATCH 18/26] Fix quadratic behavior of repeated vectored writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some implementations of `Write::write_vectored` in the standard library (`BufWriter`, `LineWriter`, `Stdout`, `Stderr`) check all buffers to calculate the total length. This is O(n) over the number of buffers. It's common that only a limited number of buffers is written at a time (e.g. 1024 for `writev(2)`). `write_vectored_all` will then call `write_vectored` repeatedly, leading to a runtime of O(n²) over the number of buffers. The fix is to only calculate as much as needed if it's needed. --- library/std/src/io/buffered/bufwriter.rs | 51 ++++++++++--------- library/std/src/io/buffered/linewritershim.rs | 15 ++++-- library/std/src/io/stdio.rs | 15 ++++-- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 665d8602c0800..2d13230ffbabd 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -554,35 +554,38 @@ impl Write for BufWriter { // same underlying buffer, as otherwise the buffers wouldn't fit in memory). If the // computation overflows, then surely the input cannot fit in our buffer, so we forward // to the inner writer's `write_vectored` method to let it handle it appropriately. - let saturated_total_len = - bufs.iter().fold(0usize, |acc, b| acc.saturating_add(b.len())); + let mut saturated_total_len: usize = 0; - if saturated_total_len > self.spare_capacity() { - // Flush if the total length of the input exceeds our buffer's spare capacity. - // If we would have overflowed, this condition also holds, and we need to flush. - self.flush_buf()?; + for buf in bufs { + saturated_total_len = saturated_total_len.saturating_add(buf.len()); + + if saturated_total_len > self.spare_capacity() && !self.buf.is_empty() { + // Flush if the total length of the input exceeds our buffer's spare capacity. + // If we would have overflowed, this condition also holds, and we need to flush. + self.flush_buf()?; + } + + if saturated_total_len >= self.buf.capacity() { + // Forward to our inner writer if the total length of the input is greater than or + // equal to our buffer capacity. If we would have overflowed, this condition also + // holds, and we punt to the inner writer. + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + return r; + } } - if saturated_total_len >= self.buf.capacity() { - // Forward to our inner writer if the total length of the input is greater than or - // equal to our buffer capacity. If we would have overflowed, this condition also - // holds, and we punt to the inner writer. - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r - } else { - // `saturated_total_len < self.buf.capacity()` implies that we did not saturate. + // `saturated_total_len < self.buf.capacity()` implies that we did not saturate. - // SAFETY: We checked whether or not the spare capacity was large enough above. If - // it was, then we're safe already. If it wasn't, we flushed, making sufficient - // room for any input <= the buffer size, which includes this input. - unsafe { - bufs.iter().for_each(|b| self.write_to_buffer_unchecked(b)); - }; + // SAFETY: We checked whether or not the spare capacity was large enough above. If + // it was, then we're safe already. If it wasn't, we flushed, making sufficient + // room for any input <= the buffer size, which includes this input. + unsafe { + bufs.iter().for_each(|b| self.write_to_buffer_unchecked(b)); + }; - Ok(saturated_total_len) - } + Ok(saturated_total_len) } else { let mut iter = bufs.iter(); let mut total_written = if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) { diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index 7eadfd413661d..c3ac7855d4450 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -175,6 +175,10 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { } // Find the buffer containing the last newline + // FIXME: This is overly slow if there are very many bufs and none contain + // newlines. e.g. writev() on Linux only writes up to 1024 slices, so + // scanning the rest is wasted effort. This makes write_all_vectored() + // quadratic. let last_newline_buf_idx = bufs .iter() .enumerate() @@ -215,9 +219,14 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { // Don't try to reconstruct the exact amount written; just bail // in the event of a partial write - let lines_len = lines.iter().map(|buf| buf.len()).sum(); - if flushed < lines_len { - return Ok(flushed); + let mut lines_len: usize = 0; + for buf in lines { + // With overlapping/duplicate slices the total length may in theory + // exceed usize::MAX + lines_len = lines_len.saturating_add(buf.len()); + if flushed < lines_len { + return Ok(flushed); + } } // Now that the write has succeeded, buffer the rest (or as much of the diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 455de6d98bae6..42fc0053030af 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -128,8 +128,8 @@ impl Write for StdoutRaw { } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - handle_ebadf(self.0.write_vectored(bufs), total) + let total = || bufs.iter().map(|b| b.len()).sum(); + handle_ebadf_lazy(self.0.write_vectored(bufs), total) } #[inline] @@ -160,8 +160,8 @@ impl Write for StderrRaw { } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - handle_ebadf(self.0.write_vectored(bufs), total) + let total = || bufs.iter().map(|b| b.len()).sum(); + handle_ebadf_lazy(self.0.write_vectored(bufs), total) } #[inline] @@ -193,6 +193,13 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { } } +fn handle_ebadf_lazy(r: io::Result, default: impl FnOnce() -> T) -> io::Result { + match r { + Err(ref e) if stdio::is_ebadf(e) => Ok(default()), + r => r, + } +} + /// A handle to the standard input stream of a process. /// /// Each handle is a shared reference to a global buffer of input data to this From 66147c80ae9c9c68b0be1396f9ba4596a023d22d Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 2 Mar 2024 01:29:20 +0100 Subject: [PATCH 19/26] Move generic `NonZero` `rustc_layout_scalar_valid_range_start` attribute to inner type. --- library/core/src/num/nonzero.rs | 127 +++++++++++------- .../consts/const-eval/raw-bytes.32bit.stderr | 4 +- .../consts/const-eval/raw-bytes.64bit.stderr | 4 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 4 +- tests/ui/lint/clashing-extern-fn.stderr | 67 ++++++++- tests/ui/lint/invalid_value.stderr | 27 +--- tests/ui/lint/lint-ctypes-enum.stderr | 120 ++++++++++++++++- .../ui/print_type_sizes/niche-filling.stdout | 2 + 8 files changed, 269 insertions(+), 86 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 9e34c0d240dc2..cd22b5a6bad99 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -6,21 +6,12 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics; use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; +use crate::ptr; use crate::str::FromStr; use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; -mod private { - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - #[const_trait] - pub trait Sealed {} -} - /// A marker trait for primitive types which can be zero. /// /// This is an implementation detail for [NonZero]\ which may disappear or be replaced at any time. @@ -34,38 +25,70 @@ mod private { issue = "none" )] #[const_trait] -pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {} +pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { + #[doc(hidden)] + type NonZeroInner: Sized + Copy; +} macro_rules! impl_zeroable_primitive { - ($primitive:ty) => { - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - impl const private::Sealed for $primitive {} - - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - unsafe impl const ZeroablePrimitive for $primitive {} + ($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => { + mod private { + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + #[const_trait] + pub trait Sealed {} + + $( + #[derive(Debug, Clone, Copy, PartialEq)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + pub struct $NonZeroInner($primitive); + )+ + } + + $( + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + impl const private::Sealed for $primitive {} + + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + unsafe impl const ZeroablePrimitive for $primitive { + type NonZeroInner = private::$NonZeroInner; + } + )+ }; } -impl_zeroable_primitive!(u8); -impl_zeroable_primitive!(u16); -impl_zeroable_primitive!(u32); -impl_zeroable_primitive!(u64); -impl_zeroable_primitive!(u128); -impl_zeroable_primitive!(usize); -impl_zeroable_primitive!(i8); -impl_zeroable_primitive!(i16); -impl_zeroable_primitive!(i32); -impl_zeroable_primitive!(i64); -impl_zeroable_primitive!(i128); -impl_zeroable_primitive!(isize); +impl_zeroable_primitive!( + NonZeroU8Inner(u8), + NonZeroU16Inner(u16), + NonZeroU32Inner(u32), + NonZeroU64Inner(u64), + NonZeroU128Inner(u128), + NonZeroUsizeInner(usize), + NonZeroI8Inner(i8), + NonZeroI16Inner(i16), + NonZeroI32Inner(i32), + NonZeroI64Inner(i64), + NonZeroI128Inner(i128), + NonZeroIsizeInner(isize), +); /// A value that is known not to equal zero. /// @@ -80,10 +103,8 @@ impl_zeroable_primitive!(isize); /// ``` #[unstable(feature = "generic_nonzero", issue = "120257")] #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(1)] -#[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonZero"] -pub struct NonZero(T); +pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { ($Trait:ident) => { @@ -114,8 +135,7 @@ where { #[inline] fn clone(&self) -> Self { - // SAFETY: The contained value is non-zero. - unsafe { Self(self.0) } + Self(self.0) } } @@ -188,19 +208,19 @@ where #[inline] fn max(self, other: Self) -> Self { // SAFETY: The maximum of two non-zero values is still non-zero. - unsafe { Self(self.get().max(other.get())) } + unsafe { Self::new_unchecked(self.get().max(other.get())) } } #[inline] fn min(self, other: Self) -> Self { // SAFETY: The minimum of two non-zero values is still non-zero. - unsafe { Self(self.get().min(other.get())) } + unsafe { Self::new_unchecked(self.get().min(other.get())) } } #[inline] fn clamp(self, min: Self, max: Self) -> Self { // SAFETY: A non-zero value clamped between two non-zero values is still non-zero. - unsafe { Self(self.get().clamp(min.get(), max.get())) } + unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) } } } @@ -240,7 +260,7 @@ where #[inline] fn bitor(self, rhs: Self) -> Self::Output { // SAFETY: Bitwise OR of two non-zero values is still non-zero. - unsafe { Self(self.get() | rhs.get()) } + unsafe { Self::new_unchecked(self.get() | rhs.get()) } } } @@ -254,7 +274,7 @@ where #[inline] fn bitor(self, rhs: T) -> Self::Output { // SAFETY: Bitwise OR of a non-zero value with anything is still non-zero. - unsafe { Self(self.get() | rhs) } + unsafe { Self::new_unchecked(self.get() | rhs) } } } @@ -268,7 +288,7 @@ where #[inline] fn bitor(self, rhs: NonZero) -> Self::Output { // SAFETY: Bitwise OR of anything with a non-zero value is still non-zero. - unsafe { NonZero(self | rhs.get()) } + unsafe { NonZero::new_unchecked(self | rhs.get()) } } } @@ -345,7 +365,7 @@ where pub fn from_mut(n: &mut T) -> Option<&mut Self> { // SAFETY: Memory layout optimization guarantees that `Option>` has // the same layout and size as `T`, with `0` representing `None`. - let opt_n = unsafe { &mut *(n as *mut T as *mut Option) }; + let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::>()) }; opt_n.as_mut() } @@ -388,12 +408,17 @@ where // memory somewhere. If the value of `self` was from by-value argument // of some not-inlined function, LLVM don't have range metadata // to understand that the value cannot be zero. - match Self::new(self.0) { - Some(Self(n)) => n, + // + // SAFETY: `Self` is guaranteed to have the same layout as `Option`. + match unsafe { intrinsics::transmute_unchecked(self) } { None => { // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable. unsafe { intrinsics::unreachable() } } + Some(Self(inner)) => { + // SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`. + unsafe { intrinsics::transmute_unchecked(inner) } + } } } } diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index c06c30741164a..c1748c2e23769 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:59:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 0589280524cab..eb97eab9db756 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:59:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 70b961fe1cd4f..ab0fb2abdb309 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:26:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 86ee789aeb22d..22d9b4d76f13c 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,3 +1,31 @@ +warning: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:369:43 + | +LL | fn option_non_zero_usize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + = note: `#[warn(improper_ctypes)]` on by default + +warning: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:370:43 + | +LL | fn option_non_zero_isize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +warning: `extern` block uses type `Option`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:428:46 + | +LL | fn hidden_niche_transparent() -> Option; + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + warning: `extern` block uses type `Option`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:430:55 | @@ -6,7 +34,6 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:434:46 @@ -178,6 +205,30 @@ LL | fn non_null_ptr() -> *const usize; = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` +warning: `option_non_zero_usize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:369:13 + | +LL | fn option_non_zero_usize() -> usize; + | ----------------------------------- `option_non_zero_usize` previously declared here +... +LL | fn option_non_zero_usize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> usize` + found `unsafe extern "C" fn() -> Option>` + +warning: `option_non_zero_isize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:370:13 + | +LL | fn option_non_zero_isize() -> isize; + | ----------------------------------- `option_non_zero_isize` previously declared here +... +LL | fn option_non_zero_isize() -> Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> isize` + found `unsafe extern "C" fn() -> Option>` + warning: `option_non_zero_usize_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:374:13 | @@ -202,6 +253,18 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; = note: expected `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const isize` +warning: `hidden_niche_transparent` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:428:13 + | +LL | fn hidden_niche_transparent() -> usize; + | -------------------------------------- `hidden_niche_transparent` previously declared here +... +LL | fn hidden_niche_transparent() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> usize` + found `unsafe extern "C" fn() -> Option` + warning: `hidden_niche_transparent_no_niche` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:430:13 | @@ -226,5 +289,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 19 warnings emitted +warning: 25 warnings emitted diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index 955d01bd5d904..e45d061a1f051 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -320,10 +320,7 @@ error: the type `(NonZero, i32)` does not permit zero-initialization --> $DIR/invalid_value.rs:94:41 | LL | let _val: (NonZero, i32) = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null @@ -331,13 +328,9 @@ error: the type `(NonZero, i32)` does not permit being left uninitialized --> $DIR/invalid_value.rs:95:41 | LL | let _val: (NonZero, i32) = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null - = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization --> $DIR/invalid_value.rs:97:37 @@ -411,10 +404,7 @@ error: the type `OneFruitNonZero` does not permit zero-initialization --> $DIR/invalid_value.rs:106:37 | LL | let _val: OneFruitNonZero = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) @@ -427,10 +417,7 @@ error: the type `OneFruitNonZero` does not permit being left uninitialized --> $DIR/invalid_value.rs:107:37 | LL | let _val: OneFruitNonZero = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) @@ -438,7 +425,6 @@ note: because `std::num::NonZero` must be non-null (in this field of the on | LL | Banana(NonZero), | ^^^^^^^^^^^^ - = note: integers must be initialized error: the type `bool` does not permit being left uninitialized --> $DIR/invalid_value.rs:111:26 @@ -607,10 +593,7 @@ error: the type `NonZero` does not permit zero-initialization --> $DIR/invalid_value.rs:153:34 | LL | let _val: NonZero = mem::transmute(0); - | ^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 48be3eb5a5630..b1bacbeceda25 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -45,21 +45,131 @@ note: the type is defined here LL | enum T { | ^^^^^^ -error: `extern` block uses type `u128`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:71:21 + | +LL | fn nonzero_u8(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:72:22 + | +LL | fn nonzero_u16(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:73:22 + | +LL | fn nonzero_u32(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:74:22 + | +LL | fn nonzero_u64(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:75:23 | LL | fn nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: 128-bit integers don't currently have a known stable ABI + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:77:24 + | +LL | fn nonzero_usize(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:78:21 + | +LL | fn nonzero_i8(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:79:22 + | +LL | fn nonzero_i16(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:80:22 + | +LL | fn nonzero_i32(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:81:22 + | +LL | fn nonzero_i64(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint -error: `extern` block uses type `i128`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:82:23 | LL | fn nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: 128-bit integers don't currently have a known stable ABI + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:84:24 + | +LL | fn nonzero_isize(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:85:29 + | +LL | fn transparent_struct(x: Option>>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +error: `extern` block uses type `Option>>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:86:27 + | +LL | fn transparent_enum(x: Option>>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint error: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:87:28 @@ -88,5 +198,5 @@ LL | fn no_result(x: Result<(), num::NonZero>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 8 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index 53a58ccc4eef8..eeb5de5324121 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -68,6 +68,8 @@ print-type-size type: `Union2, u32>`: 4 bytes, alignment: print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes +print-type-size type: `core::num::nonzero::private::NonZeroU32Inner`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `std::num::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `std::option::Option>`: 4 bytes, alignment: 4 bytes From ba35507f6b952a95205025c9fb2b6431bb425435 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 2 Mar 2024 15:25:00 +0100 Subject: [PATCH 20/26] Fix lint. --- compiler/rustc_lint/src/types.rs | 44 +++++---- library/core/src/num/nonzero.rs | 1 + tests/ui/lint/clashing-extern-fn.stderr | 67 +------------ tests/ui/lint/lint-ctypes-enum.stderr | 120 +----------------------- 4 files changed, 35 insertions(+), 197 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5d36a8b3d0e9c..500efefbb1198 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -984,7 +984,14 @@ pub fn transparent_newtype_field<'a, 'tcx>( } /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { +fn ty_is_known_nonnull<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + mode: CItemKind, +) -> bool { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, @@ -1004,7 +1011,7 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - def.variants() .iter() .filter_map(|variant| transparent_newtype_field(tcx, variant)) - .any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode)) + .any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode)) } _ => false, } @@ -1012,7 +1019,13 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type. /// If the type passed in was not scalar, returns None. -fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { +fn get_nullable_type<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option> { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + Some(match *ty.kind() { ty::Adt(field_def, field_args) => { let inner_field_ty = { @@ -1028,22 +1041,19 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> .expect("No non-zst fields in transparent type.") .ty(tcx, field_args) }; - return get_nullable_type(tcx, inner_field_ty); + return get_nullable_type(tcx, param_env, inner_field_ty); } ty::Int(ty) => Ty::new_int(tcx, ty), ty::Uint(ty) => Ty::new_uint(tcx, ty), ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut), // As these types are always non-null, the nullable equivalent of - // Option of these types are their raw pointer counterparts. + // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }), - ty::FnPtr(..) => { - // There is no nullable equivalent for Rust's function pointers -- you - // must use an Option _> to represent it. - ty - } - - // We should only ever reach this case if ty_is_known_nonnull is extended - // to other types. + // There is no nullable equivalent for Rust's function pointers, + // you must use an `Option _>` to represent it. + ty::FnPtr(..) => ty, + // We should only ever reach this case if `ty_is_known_nonnull` is + // extended to other types. ref unhandled => { debug!( "get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}", @@ -1056,7 +1066,7 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> /// Check if this enum can be safely exported based on the "nullable pointer optimization". If it /// can, return the type that `ty` can be safely converted to, otherwise return `None`. -/// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`, +/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`, /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. /// FIXME: This duplicates code in codegen. pub(crate) fn repr_nullable_ptr<'tcx>( @@ -1075,7 +1085,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>( _ => return None, }; - if !ty_is_known_nonnull(tcx, field_ty, ckind) { + if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) { return None; } @@ -1099,10 +1109,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>( WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start, end } => { unreachable!("Unhandled start and end range: ({}, {})", start, end) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index cd22b5a6bad99..33b487873e7e5 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -103,6 +103,7 @@ impl_zeroable_primitive!( /// ``` #[unstable(feature = "generic_nonzero", issue = "120257")] #[repr(transparent)] +#[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonZero"] pub struct NonZero(T::NonZeroInner); diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 22d9b4d76f13c..86ee789aeb22d 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,31 +1,3 @@ -warning: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:369:43 - | -LL | fn option_non_zero_usize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - = note: `#[warn(improper_ctypes)]` on by default - -warning: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:370:43 - | -LL | fn option_non_zero_isize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:428:46 - | -LL | fn hidden_niche_transparent() -> Option; - | ^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `extern` block uses type `Option`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:430:55 | @@ -34,6 +6,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>>`, which is not FFI-safe --> $DIR/clashing-extern-fn.rs:434:46 @@ -205,30 +178,6 @@ LL | fn non_null_ptr() -> *const usize; = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` -warning: `option_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:369:13 - | -LL | fn option_non_zero_usize() -> usize; - | ----------------------------------- `option_non_zero_usize` previously declared here -... -LL | fn option_non_zero_usize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> usize` - found `unsafe extern "C" fn() -> Option>` - -warning: `option_non_zero_isize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:370:13 - | -LL | fn option_non_zero_isize() -> isize; - | ----------------------------------- `option_non_zero_isize` previously declared here -... -LL | fn option_non_zero_isize() -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> isize` - found `unsafe extern "C" fn() -> Option>` - warning: `option_non_zero_usize_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:374:13 | @@ -253,18 +202,6 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; = note: expected `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const isize` -warning: `hidden_niche_transparent` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:428:13 - | -LL | fn hidden_niche_transparent() -> usize; - | -------------------------------------- `hidden_niche_transparent` previously declared here -... -LL | fn hidden_niche_transparent() -> Option; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> usize` - found `unsafe extern "C" fn() -> Option` - warning: `hidden_niche_transparent_no_niche` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:430:13 | @@ -289,5 +226,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 25 warnings emitted +warning: 19 warnings emitted diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index b1bacbeceda25..48be3eb5a5630 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -45,131 +45,21 @@ note: the type is defined here LL | enum T { | ^^^^^^ -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:71:21 - | -LL | fn nonzero_u8(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:72:22 - | -LL | fn nonzero_u16(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:73:22 - | -LL | fn nonzero_u32(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:74:22 - | -LL | fn nonzero_u64(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:75:23 | LL | fn nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:77:24 - | -LL | fn nonzero_usize(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:78:21 - | -LL | fn nonzero_i8(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:79:22 - | -LL | fn nonzero_i16(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:80:22 - | -LL | fn nonzero_i32(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:81:22 - | -LL | fn nonzero_i64(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `Option>`, which is not FFI-safe +error: `extern` block uses type `i128`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:82:23 | LL | fn nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:84:24 - | -LL | fn nonzero_isize(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:85:29 - | -LL | fn transparent_struct(x: Option>>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - -error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:86:27 - | -LL | fn transparent_enum(x: Option>>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint + = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:87:28 @@ -198,5 +88,5 @@ LL | fn no_result(x: Result<(), num::NonZero>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 20 previous errors +error: aborting due to 8 previous errors From 2fc73d3cd3ad0b4a122eec41a38e007f9845cea2 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 2 Mar 2024 18:37:17 +0100 Subject: [PATCH 21/26] Fix `miri` tests. --- .../tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr | 4 ++-- .../tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr index 7d481940acec9..35de453522257 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC | LL | f(); - | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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 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 b1a2bd2c79a40..81d775f6d7f5f 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,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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 From 06992c729f0ce173ad1eeff3c86f0cc997b454f2 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 2 Mar 2024 19:44:35 +0100 Subject: [PATCH 22/26] Hide implementation details for `NonZero` auto traits. --- library/core/src/num/nonzero.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 33b487873e7e5..5605c871281b8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -6,6 +6,7 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics; use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::ptr; use crate::str::FromStr; @@ -129,6 +130,25 @@ impl_nonzero_fmt!(Octal); impl_nonzero_fmt!(LowerHex); impl_nonzero_fmt!(UpperHex); +macro_rules! impl_nonzero_auto_trait { + (unsafe $Trait:ident) => { + #[stable(feature = "nonzero", since = "1.28.0")] + unsafe impl $Trait for NonZero where T: ZeroablePrimitive + $Trait {} + }; + ($Trait:ident) => { + #[stable(feature = "nonzero", since = "1.28.0")] + impl $Trait for NonZero where T: ZeroablePrimitive + $Trait {} + }; +} + +// Implement auto-traits manually based on `T` to avoid docs exposing +// the `ZeroablePrimitive::NonZeroInner` implementation detail. +impl_nonzero_auto_trait!(RefUnwindSafe); +impl_nonzero_auto_trait!(unsafe Send); +impl_nonzero_auto_trait!(unsafe Sync); +impl_nonzero_auto_trait!(Unpin); +impl_nonzero_auto_trait!(UnwindSafe); + #[stable(feature = "nonzero", since = "1.28.0")] impl Clone for NonZero where From f4be633758ad08e429bf69f7ffbe46ed54d9c01e Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 6 Mar 2024 17:28:45 +0100 Subject: [PATCH 23/26] Fix lint. --- compiler/rustc_lint/src/builtin.rs | 2 ++ tests/ui/lint/invalid_value.stderr | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5f0af6aee6ace..f1f3c26c4568d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2468,6 +2468,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ty: Ty<'tcx>, init: InitKind, ) -> Option { + let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); + use rustc_type_ir::TyKind::*; match ty.kind() { // Primitive types that don't like 0 as a value. diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index e45d061a1f051..b4e7421829f82 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -323,6 +323,7 @@ LL | let _val: (NonZero, i32) = mem::zeroed(); | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null + = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null error: the type `(NonZero, i32)` does not permit being left uninitialized --> $DIR/invalid_value.rs:95:41 @@ -331,6 +332,8 @@ LL | let _val: (NonZero, i32) = mem::uninitialized(); | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null + = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null + = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization --> $DIR/invalid_value.rs:97:37 @@ -412,6 +415,7 @@ note: because `std::num::NonZero` must be non-null (in this field of the on | LL | Banana(NonZero), | ^^^^^^^^^^^^ + = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null error: the type `OneFruitNonZero` does not permit being left uninitialized --> $DIR/invalid_value.rs:107:37 @@ -425,6 +429,8 @@ note: because `std::num::NonZero` must be non-null (in this field of the on | LL | Banana(NonZero), | ^^^^^^^^^^^^ + = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null + = note: integers must be initialized error: the type `bool` does not permit being left uninitialized --> $DIR/invalid_value.rs:111:26 @@ -596,6 +602,7 @@ LL | let _val: NonZero = mem::transmute(0); | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null + = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null error: the type `NonNull` does not permit zero-initialization --> $DIR/invalid_value.rs:156:34 From cc38c1e9cb75d12f41cfda3317867759ab895b20 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 6 Mar 2024 19:14:03 +0100 Subject: [PATCH 24/26] Add #[inline] to BTreeMap::new constructor --- library/alloc/src/collections/btree/map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 58ffa9710d3e6..e99c6220e2064 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -624,6 +624,7 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_btree_new", since = "1.66.0")] + #[inline] #[must_use] pub const fn new() -> BTreeMap { BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData } From 0ee0f290a61c973a014d44ca3f5e3dc165f5e562 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 25 Feb 2024 20:43:06 +0000 Subject: [PATCH 25/26] Bless aarch64 asm test --- tests/ui/asm/aarch64/parse-error.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr index 46984a1fe1ca0..539c134472fda 100644 --- a/tests/ui/asm/aarch64/parse-error.stderr +++ b/tests/ui/asm/aarch64/parse-error.stderr @@ -130,17 +130,17 @@ LL | asm!("{1}", in("x0") foo, const bar); | | | explicit register argument -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` --> $DIR/parse-error.rs:66:29 | LL | asm!("", options(), ""); - | ^^ expected one of 9 possible tokens + | ^^ expected one of 10 possible tokens -error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"` --> $DIR/parse-error.rs:68:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); - | ^^^^ expected one of 9 possible tokens + | ^^^^ expected one of 10 possible tokens error: asm template must be a string literal --> $DIR/parse-error.rs:70:14 From ef626d772f7ee9ddba526b0693993f6479ee5c14 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 7 Mar 2024 09:49:15 -0500 Subject: [PATCH 26/26] PassWrapper: update for llvm/llvm-project@a3319371970b @rustbot label: +llvm-main --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 1cdfc22431e3e..f6253068eaa63 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -451,14 +451,30 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.ObjectFilenameForDebug = OutputObjFile; } if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) { +#if LLVM_VERSION_GE(19, 0) + Options.MCOptions.CompressDebugSections = DebugCompressionType::Zlib; +#else Options.CompressDebugSections = DebugCompressionType::Zlib; +#endif } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) { +#if LLVM_VERSION_GE(19, 0) + Options.MCOptions.CompressDebugSections = DebugCompressionType::Zstd; +#else Options.CompressDebugSections = DebugCompressionType::Zstd; +#endif } else if (!strcmp("none", DebugInfoCompression)) { +#if LLVM_VERSION_GE(19, 0) + Options.MCOptions.CompressDebugSections = DebugCompressionType::None; +#else Options.CompressDebugSections = DebugCompressionType::None; +#endif } +#if LLVM_VERSION_GE(19, 0) + Options.MCOptions.X86RelaxRelocations = RelaxELFRelocations; +#else Options.RelaxELFRelocations = RelaxELFRelocations; +#endif Options.UseInitArray = UseInitArray; #if LLVM_VERSION_LT(17, 0)