mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Add asm label support to AST and HIR
This commit is contained in:
parent
8f359beca4
commit
93fa8579c6
@ -2294,6 +2294,9 @@ pub enum InlineAsmOperand {
|
||||
Sym {
|
||||
sym: InlineAsmSym,
|
||||
},
|
||||
Label {
|
||||
block: P<Block>,
|
||||
},
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1330,6 +1330,7 @@ pub fn noop_visit_inline_asm<T: MutVisitor>(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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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) => {
|
||||
|
@ -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
|
||||
|
@ -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!")
|
||||
}
|
||||
})
|
||||
|
@ -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<AssocConst=3>`.
|
||||
|
@ -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> {
|
||||
|
@ -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()
|
||||
|
@ -470,6 +470,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
}
|
||||
// No special checking is needed for labels.
|
||||
hir::InlineAsmOperand::Label { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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!")
|
||||
}
|
||||
}
|
||||
|
@ -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<Block>> {
|
||||
pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
||||
if let [.., last] = &*attrs {
|
||||
self.error_on_forbidden_inner_attr(
|
||||
|
@ -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) => {
|
||||
// Handle non-returning asm
|
||||
let mut succ = if asm.options.contains(InlineAsmOptions::NORETURN) {
|
||||
self.exit_ln
|
||||
} else {
|
||||
succ
|
||||
};
|
||||
//
|
||||
// (inputs)
|
||||
// |
|
||||
// v
|
||||
// (outputs)
|
||||
// / \
|
||||
// | |
|
||||
// v v
|
||||
// (labels)(fallthrough)
|
||||
// | |
|
||||
// v v
|
||||
// ( succ / exit_ln )
|
||||
|
||||
// Do a first pass for writing outputs only
|
||||
// Handle non-returning asm
|
||||
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 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
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -399,6 +399,7 @@ symbols! {
|
||||
asm,
|
||||
asm_const,
|
||||
asm_experimental_arch,
|
||||
asm_goto,
|
||||
asm_sym,
|
||||
asm_unwind,
|
||||
assert,
|
||||
|
@ -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(_, _)
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user