Add asm label support to AST and HIR

This commit is contained in:
Gary Guo 2023-12-25 20:53:01 +00:00
parent 8f359beca4
commit 93fa8579c6
25 changed files with 143 additions and 21 deletions

View File

@ -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,
}
}
}

View File

@ -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),
}
}
}

View File

@ -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()

View File

@ -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

View File

@ -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");
}
};

View File

@ -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 {

View File

@ -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) => {

View File

@ -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

View File

@ -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!")
}
})

View File

@ -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>`.

View File

@ -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> {

View File

@ -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()

View File

@ -470,6 +470,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
};
}
// No special checking is needed for labels.
hir::InlineAsmOperand::Label { .. } => {}
}
}
}

View File

@ -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");

View File

@ -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) {

View File

@ -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);
}
}
}
}

View File

@ -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,

View File

@ -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!")
}
}

View File

@ -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(

View File

@ -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

View File

@ -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() {

View File

@ -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),
}
}
}

View File

@ -399,6 +399,7 @@ symbols! {
asm,
asm_const,
asm_experimental_arch,
asm_goto,
asm_sym,
asm_unwind,
assert,

View File

@ -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(_, _)

View File

@ -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),
}
}
},