Add support for clobber_abi to asm!
This commit is contained in:
parent
2f4612260d
commit
3fd463a5ca
12 changed files with 652 additions and 79 deletions
|
@ -2027,6 +2027,7 @@ pub enum InlineAsmOperand {
|
||||||
pub struct InlineAsm {
|
pub struct InlineAsm {
|
||||||
pub template: Vec<InlineAsmTemplatePiece>,
|
pub template: Vec<InlineAsmTemplatePiece>,
|
||||||
pub operands: Vec<(InlineAsmOperand, Span)>,
|
pub operands: Vec<(InlineAsmOperand, Span)>,
|
||||||
|
pub clobber_abi: Option<(Symbol, Span)>,
|
||||||
pub options: InlineAsmOptions,
|
pub options: InlineAsmOptions,
|
||||||
pub line_spans: Vec<Span>,
|
pub line_spans: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut clobber_abi = None;
|
||||||
|
if let Some(asm_arch) = asm_arch {
|
||||||
|
if let Some((abi_name, abi_span)) = asm.clobber_abi {
|
||||||
|
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
|
||||||
|
Ok(abi) => clobber_abi = Some((abi, abi_span)),
|
||||||
|
Err(&[]) => {
|
||||||
|
self.sess
|
||||||
|
.struct_span_err(
|
||||||
|
abi_span,
|
||||||
|
"`clobber_abi` is not supported on this target",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
Err(supported_abis) => {
|
||||||
|
let mut err =
|
||||||
|
self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
|
||||||
|
let mut abis = format!("`{}`", supported_abis[0]);
|
||||||
|
for m in &supported_abis[1..] {
|
||||||
|
let _ = write!(abis, ", `{}`", m);
|
||||||
|
}
|
||||||
|
err.note(&format!(
|
||||||
|
"the following ABIs are supported on this target: {}",
|
||||||
|
abis
|
||||||
|
));
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lower operands to HIR. We use dummy register classes if an error
|
// Lower operands to HIR. We use dummy register classes if an error
|
||||||
// occurs during lowering because we still need to be able to produce a
|
// occurs during lowering because we still need to be able to produce a
|
||||||
// valid HIR.
|
// valid HIR.
|
||||||
let sess = self.sess;
|
let sess = self.sess;
|
||||||
let operands: Vec<_> = asm
|
let mut operands: Vec<_> = asm
|
||||||
.operands
|
.operands
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(op, op_sp)| {
|
.map(|(op, op_sp)| {
|
||||||
|
@ -336,6 +366,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a clobber_abi is specified, add the necessary clobbers to the
|
||||||
|
// operands list.
|
||||||
|
if let Some((abi, abi_span)) = clobber_abi {
|
||||||
|
for &clobber in abi.clobbered_regs() {
|
||||||
|
let mut output_used = false;
|
||||||
|
clobber.overlapping_regs(|reg| {
|
||||||
|
if used_output_regs.contains_key(®) {
|
||||||
|
output_used = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if !output_used {
|
||||||
|
operands.push((
|
||||||
|
hir::InlineAsmOperand::Out {
|
||||||
|
reg: asm::InlineAsmRegOrRegClass::Reg(clobber),
|
||||||
|
late: true,
|
||||||
|
expr: None,
|
||||||
|
},
|
||||||
|
abi_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let operands = self.arena.alloc_from_iter(operands);
|
let operands = self.arena.alloc_from_iter(operands);
|
||||||
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
||||||
let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
|
let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
|
||||||
|
|
|
@ -2186,11 +2186,15 @@ impl<'a> State<'a> {
|
||||||
enum AsmArg<'a> {
|
enum AsmArg<'a> {
|
||||||
Template(String),
|
Template(String),
|
||||||
Operand(&'a InlineAsmOperand),
|
Operand(&'a InlineAsmOperand),
|
||||||
|
ClobberAbi(Symbol),
|
||||||
Options(InlineAsmOptions),
|
Options(InlineAsmOptions),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
|
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
|
||||||
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
|
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
|
||||||
|
if let Some((abi, _)) = asm.clobber_abi {
|
||||||
|
args.push(AsmArg::ClobberAbi(abi));
|
||||||
|
}
|
||||||
if !asm.options.is_empty() {
|
if !asm.options.is_empty() {
|
||||||
args.push(AsmArg::Options(asm.options));
|
args.push(AsmArg::Options(asm.options));
|
||||||
}
|
}
|
||||||
|
@ -2257,6 +2261,12 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AsmArg::ClobberAbi(abi) => {
|
||||||
|
s.word("clobber_abi");
|
||||||
|
s.popen();
|
||||||
|
s.print_symbol(*abi, ast::StrStyle::Cooked);
|
||||||
|
s.pclose();
|
||||||
|
}
|
||||||
AsmArg::Options(opts) => {
|
AsmArg::Options(opts) => {
|
||||||
s.word("options");
|
s.word("options");
|
||||||
s.popen();
|
s.popen();
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct AsmArgs {
|
||||||
operands: Vec<(ast::InlineAsmOperand, Span)>,
|
operands: Vec<(ast::InlineAsmOperand, Span)>,
|
||||||
named_args: FxHashMap<Symbol, usize>,
|
named_args: FxHashMap<Symbol, usize>,
|
||||||
reg_args: FxHashSet<usize>,
|
reg_args: FxHashSet<usize>,
|
||||||
|
clobber_abi: Option<(Symbol, Span)>,
|
||||||
options: ast::InlineAsmOptions,
|
options: ast::InlineAsmOptions,
|
||||||
options_spans: Vec<Span>,
|
options_spans: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
@ -63,6 +64,7 @@ fn parse_args<'a>(
|
||||||
operands: vec![],
|
operands: vec![],
|
||||||
named_args: FxHashMap::default(),
|
named_args: FxHashMap::default(),
|
||||||
reg_args: FxHashSet::default(),
|
reg_args: FxHashSet::default(),
|
||||||
|
clobber_abi: None,
|
||||||
options: ast::InlineAsmOptions::empty(),
|
options: ast::InlineAsmOptions::empty(),
|
||||||
options_spans: vec![],
|
options_spans: vec![],
|
||||||
};
|
};
|
||||||
|
@ -85,6 +87,13 @@ fn parse_args<'a>(
|
||||||
break;
|
break;
|
||||||
} // accept trailing commas
|
} // accept trailing commas
|
||||||
|
|
||||||
|
// Parse clobber_abi
|
||||||
|
if p.eat_keyword(sym::clobber_abi) {
|
||||||
|
parse_clobber_abi(&mut p, &mut args)?;
|
||||||
|
allow_templates = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
if p.eat_keyword(sym::options) {
|
if p.eat_keyword(sym::options) {
|
||||||
parse_options(&mut p, &mut args, is_global_asm)?;
|
parse_options(&mut p, &mut args, is_global_asm)?;
|
||||||
|
@ -160,7 +169,11 @@ fn parse_args<'a>(
|
||||||
ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
|
ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
|
||||||
ast::ExprKind::MacCall(..) => {}
|
ast::ExprKind::MacCall(..) => {}
|
||||||
_ => {
|
_ => {
|
||||||
let errstr = "expected operand, options, or additional template string";
|
let errstr = if is_global_asm {
|
||||||
|
"expected operand, options, or additional template string"
|
||||||
|
} else {
|
||||||
|
"expected operand, clobber_abi, options, or additional template string"
|
||||||
|
};
|
||||||
let mut err = ecx.struct_span_err(template.span, errstr);
|
let mut err = ecx.struct_span_err(template.span, errstr);
|
||||||
err.span_label(template.span, errstr);
|
err.span_label(template.span, errstr);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
@ -177,13 +190,19 @@ fn parse_args<'a>(
|
||||||
let slot = args.operands.len();
|
let slot = args.operands.len();
|
||||||
args.operands.push((op, span));
|
args.operands.push((op, span));
|
||||||
|
|
||||||
// Validate the order of named, positional & explicit register operands and options. We do
|
// Validate the order of named, positional & explicit register operands and
|
||||||
// this at the end once we have the full span of the argument available.
|
// clobber_abi/options. We do this at the end once we have the full span
|
||||||
|
// of the argument available.
|
||||||
if !args.options_spans.is_empty() {
|
if !args.options_spans.is_empty() {
|
||||||
ecx.struct_span_err(span, "arguments are not allowed after options")
|
ecx.struct_span_err(span, "arguments are not allowed after options")
|
||||||
.span_labels(args.options_spans.clone(), "previous options")
|
.span_labels(args.options_spans.clone(), "previous options")
|
||||||
.span_label(span, "argument")
|
.span_label(span, "argument")
|
||||||
.emit();
|
.emit();
|
||||||
|
} else if let Some((_, abi_span)) = args.clobber_abi {
|
||||||
|
ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
|
||||||
|
.span_label(abi_span, "clobber_abi")
|
||||||
|
.span_label(span, "argument")
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
if explicit_reg {
|
if explicit_reg {
|
||||||
if name.is_some() {
|
if name.is_some() {
|
||||||
|
@ -256,16 +275,23 @@ fn parse_args<'a>(
|
||||||
|
|
||||||
let mut have_real_output = false;
|
let mut have_real_output = false;
|
||||||
let mut outputs_sp = vec![];
|
let mut outputs_sp = vec![];
|
||||||
|
let mut regclass_outputs = vec![];
|
||||||
for (op, op_sp) in &args.operands {
|
for (op, op_sp) in &args.operands {
|
||||||
match op {
|
match op {
|
||||||
ast::InlineAsmOperand::Out { expr, .. }
|
ast::InlineAsmOperand::Out { reg, expr, .. }
|
||||||
| ast::InlineAsmOperand::SplitInOut { out_expr: expr, .. } => {
|
| ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => {
|
||||||
outputs_sp.push(*op_sp);
|
outputs_sp.push(*op_sp);
|
||||||
have_real_output |= expr.is_some();
|
have_real_output |= expr.is_some();
|
||||||
|
if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
|
||||||
|
regclass_outputs.push(*op_sp);
|
||||||
}
|
}
|
||||||
ast::InlineAsmOperand::InOut { .. } => {
|
}
|
||||||
|
ast::InlineAsmOperand::InOut { reg, .. } => {
|
||||||
outputs_sp.push(*op_sp);
|
outputs_sp.push(*op_sp);
|
||||||
have_real_output = true;
|
have_real_output = true;
|
||||||
|
if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
|
||||||
|
regclass_outputs.push(*op_sp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -284,6 +310,24 @@ fn parse_args<'a>(
|
||||||
// Bail out now since this is likely to confuse MIR
|
// Bail out now since this is likely to confuse MIR
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
if let Some((_, abi_span)) = args.clobber_abi {
|
||||||
|
if is_global_asm {
|
||||||
|
let err =
|
||||||
|
ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
|
||||||
|
|
||||||
|
// Bail out now since this is likely to confuse later stages
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
if !regclass_outputs.is_empty() {
|
||||||
|
ecx.struct_span_err(
|
||||||
|
regclass_outputs.clone(),
|
||||||
|
"asm with `clobber_abi` must specify explicit registers for outputs",
|
||||||
|
)
|
||||||
|
.span_label(abi_span, "clobber_abi")
|
||||||
|
.span_labels(regclass_outputs, "generic outputs")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(args)
|
Ok(args)
|
||||||
}
|
}
|
||||||
|
@ -375,6 +419,49 @@ fn parse_options<'a>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_clobber_abi<'a>(
|
||||||
|
p: &mut Parser<'a>,
|
||||||
|
args: &mut AsmArgs,
|
||||||
|
) -> Result<(), DiagnosticBuilder<'a>> {
|
||||||
|
let span_start = p.prev_token.span;
|
||||||
|
|
||||||
|
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
|
||||||
|
|
||||||
|
let clobber_abi = match p.parse_str_lit() {
|
||||||
|
Ok(str_lit) => str_lit.symbol_unescaped,
|
||||||
|
Err(opt_lit) => {
|
||||||
|
let span = opt_lit.map_or(p.token.span, |lit| lit.span);
|
||||||
|
let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
|
||||||
|
err.span_label(span, "not a string literal");
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
|
||||||
|
|
||||||
|
let new_span = span_start.to(p.prev_token.span);
|
||||||
|
|
||||||
|
if let Some((_, prev_span)) = args.clobber_abi {
|
||||||
|
let mut err = p
|
||||||
|
.sess
|
||||||
|
.span_diagnostic
|
||||||
|
.struct_span_err(new_span, "clobber_abi specified multiple times");
|
||||||
|
err.span_label(prev_span, "clobber_abi previously specified here");
|
||||||
|
return Err(err);
|
||||||
|
} else if !args.options_spans.is_empty() {
|
||||||
|
let mut err = p
|
||||||
|
.sess
|
||||||
|
.span_diagnostic
|
||||||
|
.struct_span_err(new_span, "clobber_abi is not allowed after options");
|
||||||
|
err.span_labels(args.options_spans.clone(), "options");
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.clobber_abi = Some((clobber_abi, new_span));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_reg<'a>(
|
fn parse_reg<'a>(
|
||||||
p: &mut Parser<'a>,
|
p: &mut Parser<'a>,
|
||||||
explicit_reg: &mut bool,
|
explicit_reg: &mut bool,
|
||||||
|
@ -660,7 +747,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans })
|
Some(ast::InlineAsm {
|
||||||
|
template,
|
||||||
|
operands: args.operands,
|
||||||
|
clobber_abi: args.clobber_abi,
|
||||||
|
options: args.options,
|
||||||
|
line_spans,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_asm<'cx>(
|
pub fn expand_asm<'cx>(
|
||||||
|
|
|
@ -377,6 +377,7 @@ symbols! {
|
||||||
char,
|
char,
|
||||||
client,
|
client,
|
||||||
clippy,
|
clippy,
|
||||||
|
clobber_abi,
|
||||||
clone,
|
clone,
|
||||||
clone_closures,
|
clone_closures,
|
||||||
clone_from,
|
clone_from,
|
||||||
|
|
|
@ -712,3 +712,185 @@ pub fn allocatable_registers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Copy,
|
||||||
|
Clone,
|
||||||
|
Encodable,
|
||||||
|
Decodable,
|
||||||
|
Debug,
|
||||||
|
Eq,
|
||||||
|
PartialEq,
|
||||||
|
PartialOrd,
|
||||||
|
Hash,
|
||||||
|
HashStable_Generic
|
||||||
|
)]
|
||||||
|
pub enum InlineAsmClobberAbi {
|
||||||
|
X86,
|
||||||
|
X86_64Win,
|
||||||
|
X86_64SysV,
|
||||||
|
Arm,
|
||||||
|
AArch64,
|
||||||
|
RiscV,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InlineAsmClobberAbi {
|
||||||
|
/// Parses a clobber ABI for the given target, or returns a list of supported
|
||||||
|
/// clobber ABIs for the target.
|
||||||
|
pub fn parse(
|
||||||
|
arch: InlineAsmArch,
|
||||||
|
target: &Target,
|
||||||
|
name: Symbol,
|
||||||
|
) -> Result<Self, &'static [&'static str]> {
|
||||||
|
let name = &*name.as_str();
|
||||||
|
match arch {
|
||||||
|
InlineAsmArch::X86 => match name {
|
||||||
|
"C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
|
||||||
|
Ok(InlineAsmClobberAbi::X86)
|
||||||
|
}
|
||||||
|
_ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
|
||||||
|
},
|
||||||
|
InlineAsmArch::X86_64 => match name {
|
||||||
|
"C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
|
||||||
|
"C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
|
||||||
|
"win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
|
||||||
|
"sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
|
||||||
|
_ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
|
||||||
|
},
|
||||||
|
InlineAsmArch::Arm => match name {
|
||||||
|
"C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
|
||||||
|
_ => Err(&["C", "system", "efiapi", "aapcs"]),
|
||||||
|
},
|
||||||
|
InlineAsmArch::AArch64 => match name {
|
||||||
|
"C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
|
||||||
|
_ => Err(&["C", "system", "efiapi"]),
|
||||||
|
},
|
||||||
|
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
|
||||||
|
"C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
|
||||||
|
_ => Err(&["C", "system", "efiapi"]),
|
||||||
|
},
|
||||||
|
_ => Err(&[]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the set of registers which are clobbered by this ABI.
|
||||||
|
pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
|
||||||
|
macro_rules! clobbered_regs {
|
||||||
|
($arch:ident $arch_reg:ident {
|
||||||
|
$(
|
||||||
|
$reg:ident,
|
||||||
|
)*
|
||||||
|
}) => {
|
||||||
|
&[
|
||||||
|
$(InlineAsmReg::$arch($arch_reg::$reg),)*
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
match self {
|
||||||
|
InlineAsmClobberAbi::X86 => clobbered_regs! {
|
||||||
|
X86 X86InlineAsmReg {
|
||||||
|
ax, cx, dx,
|
||||||
|
|
||||||
|
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||||
|
|
||||||
|
k1, k2, k3, k4, k5, k6, k7,
|
||||||
|
|
||||||
|
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
|
||||||
|
st0, st1, st2, st3, st4, st5, st6, st7,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
|
||||||
|
X86 X86InlineAsmReg {
|
||||||
|
ax, cx, dx, si, di, r8, r9, r10, r11,
|
||||||
|
|
||||||
|
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||||
|
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
|
||||||
|
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
|
||||||
|
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
|
||||||
|
|
||||||
|
k1, k2, k3, k4, k5, k6, k7,
|
||||||
|
|
||||||
|
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
|
||||||
|
st0, st1, st2, st3, st4, st5, st6, st7,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
|
||||||
|
X86 X86InlineAsmReg {
|
||||||
|
// rdi and rsi are callee-saved on windows
|
||||||
|
ax, cx, dx, r8, r9, r10, r11,
|
||||||
|
|
||||||
|
// xmm6-xmm15 are callee-saved on windows, but we need to
|
||||||
|
// mark them as clobbered anyways because the upper portions
|
||||||
|
// of ymm6-ymm15 are volatile.
|
||||||
|
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
|
||||||
|
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
|
||||||
|
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
|
||||||
|
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
|
||||||
|
|
||||||
|
k1, k2, k3, k4, k5, k6, k7,
|
||||||
|
|
||||||
|
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
|
||||||
|
st0, st1, st2, st3, st4, st5, st6, st7,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InlineAsmClobberAbi::AArch64 => clobbered_regs! {
|
||||||
|
AArch64 AArch64InlineAsmReg {
|
||||||
|
x0, x1, x2, x3, x4, x5, x6, x7,
|
||||||
|
x8, x9, x10, x11, x12, x13, x14, x15,
|
||||||
|
// x18 is platform-reserved or temporary, but we exclude it
|
||||||
|
// here since it is a reserved register.
|
||||||
|
x16, x17, x30,
|
||||||
|
|
||||||
|
// Technically the low 64 bits of v8-v15 are preserved, but
|
||||||
|
// we have no way of expressing this using clobbers.
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10, v11, v12, v13, v14, v15,
|
||||||
|
v16, v17, v18, v19, v20, v21, v22, v23,
|
||||||
|
v24, v25, v26, v27, v28, v29, v30, v31,
|
||||||
|
|
||||||
|
p0, p1, p2, p3, p4, p5, p6, p7,
|
||||||
|
p8, p9, p10, p11, p12, p13, p14, p15,
|
||||||
|
ffr,
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InlineAsmClobberAbi::Arm => clobbered_regs! {
|
||||||
|
Arm ArmInlineAsmReg {
|
||||||
|
// r9 is platform-reserved and is treated as callee-saved.
|
||||||
|
r0, r1, r2, r3, r12, r14,
|
||||||
|
|
||||||
|
// The finest-grained register variant is used here so that
|
||||||
|
// partial uses of larger registers are properly handled.
|
||||||
|
s0, s1, s2, s3, s4, s5, s6, s7,
|
||||||
|
s8, s9, s10, s11, s12, s13, s14, s15,
|
||||||
|
// s16-s31 are callee-saved
|
||||||
|
d16, d17, d18, d19, d20, d21, d22, d23,
|
||||||
|
d24, d25, d26, d27, d28, d29, d30, d31,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InlineAsmClobberAbi::RiscV => clobbered_regs! {
|
||||||
|
RiscV RiscVInlineAsmReg {
|
||||||
|
// ra
|
||||||
|
x1,
|
||||||
|
// t0-t2
|
||||||
|
x5, x6, x7,
|
||||||
|
// a0-a7
|
||||||
|
x10, x11, x12, x13, x14, x15, x16, x17,
|
||||||
|
// t3-t6
|
||||||
|
x28, x29, x30, x31,
|
||||||
|
// ft0-ft7
|
||||||
|
f0, f1, f2, f3, f4, f5, f6, f7,
|
||||||
|
// fa0-fa7
|
||||||
|
f10, f11, f12, f13, f14, f15, f16, f17,
|
||||||
|
// ft8-ft11
|
||||||
|
f28, f29, f30, f31,
|
||||||
|
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10, v11, v12, v13, v14, v15,
|
||||||
|
v16, v17, v18, v19, v20, v21, v22, v23,
|
||||||
|
v24, v25, v26, v27, v28, v29, v30, v31,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -290,38 +290,33 @@ unsafe {
|
||||||
assert_eq!(x, 4 * 6);
|
assert_eq!(x, 4 * 6);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Symbol operands
|
## Symbol operands and ABI clobbers
|
||||||
|
|
||||||
A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
|
A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
|
||||||
This allows you to call a function or access a global variable without needing to keep its address in a register.
|
This allows you to call a function or access a global variable without needing to keep its address in a register.
|
||||||
|
|
||||||
```rust,allow_fail
|
```rust,allow_fail
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
extern "C" fn foo(arg: i32) {
|
extern "C" fn foo(arg: i32) -> i32 {
|
||||||
println!("arg = {}", arg);
|
println!("arg = {}", arg);
|
||||||
|
arg * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_foo(arg: i32) {
|
fn call_foo(arg: i32) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let result;
|
||||||
asm!(
|
asm!(
|
||||||
"call {}",
|
"call {}",
|
||||||
sym foo,
|
sym foo,
|
||||||
// 1st argument in rdi, which is caller-saved
|
// 1st argument in rdi
|
||||||
inout("rdi") arg => _,
|
in("rdi") arg,
|
||||||
// All caller-saved registers must be marked as clobbered
|
// Return value in rax
|
||||||
out("rax") _, out("rcx") _, out("rdx") _, out("rsi") _,
|
out("rax") result,
|
||||||
out("r8") _, out("r9") _, out("r10") _, out("r11") _,
|
// Mark all registers which are not preserved by the "C" calling
|
||||||
out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
|
// convention as clobbered.
|
||||||
out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
|
clobber_abi("C"),
|
||||||
out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
|
);
|
||||||
out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
|
result
|
||||||
// Also mark AVX-512 registers as clobbered. This is accepted by the
|
|
||||||
// compiler even if AVX-512 is not enabled on the current target.
|
|
||||||
out("xmm16") _, out("xmm17") _, out("xmm18") _, out("xmm19") _,
|
|
||||||
out("xmm20") _, out("xmm21") _, out("xmm22") _, out("xmm23") _,
|
|
||||||
out("xmm24") _, out("xmm25") _, out("xmm26") _, out("xmm27") _,
|
|
||||||
out("xmm28") _, out("xmm29") _, out("xmm30") _, out("xmm31") _,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -329,6 +324,8 @@ fn call_foo(arg: i32) {
|
||||||
Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`:
|
Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`:
|
||||||
the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
|
the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
|
||||||
|
|
||||||
|
By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered.
|
||||||
|
|
||||||
## Register template modifiers
|
## Register template modifiers
|
||||||
|
|
||||||
In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
|
In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
|
||||||
|
@ -456,12 +453,25 @@ reg_spec := <register class> / "<explicit register>"
|
||||||
operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
|
operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
|
||||||
reg_operand := dir_spec "(" reg_spec ")" operand_expr
|
reg_operand := dir_spec "(" reg_spec ")" operand_expr
|
||||||
operand := reg_operand / "const" const_expr / "sym" path
|
operand := reg_operand / "const" const_expr / "sym" path
|
||||||
|
clobber_abi := "clobber_abi(" <abi> ")"
|
||||||
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
|
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
|
||||||
options := "options(" option *["," option] [","] ")"
|
options := "options(" option *["," option] [","] ")"
|
||||||
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
|
asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] ["," options] [","] ")"
|
||||||
```
|
```
|
||||||
|
|
||||||
The macro will initially be supported only on ARM, AArch64, Hexagon, PowerPC, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
|
Inline assembly is currently supported on the following architectures:
|
||||||
|
- x86 and x86-64
|
||||||
|
- ARM
|
||||||
|
- AArch64
|
||||||
|
- RISC-V
|
||||||
|
- NVPTX
|
||||||
|
- PowerPC
|
||||||
|
- Hexagon
|
||||||
|
- MIPS32r2 and MIPS64r2
|
||||||
|
- wasm32
|
||||||
|
- BPF
|
||||||
|
|
||||||
|
Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
|
||||||
|
|
||||||
[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
|
[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
|
||||||
|
|
||||||
|
@ -780,6 +790,24 @@ As stated in the previous section, passing an input value smaller than the regis
|
||||||
|
|
||||||
[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
|
[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
|
||||||
|
|
||||||
|
## ABI clobbers
|
||||||
|
|
||||||
|
The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list.
|
||||||
|
|
||||||
|
Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
|
||||||
|
The following ABIs can be used with `clobber_abi`:
|
||||||
|
|
||||||
|
| Architecture | ABI name | Clobbered registers |
|
||||||
|
| ------------ | -------- | ------------------- |
|
||||||
|
| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `st([0-7])` |
|
||||||
|
| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` |
|
||||||
|
| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `st([0-7])` |
|
||||||
|
| AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x30`, `v[0-31]`, `p[0-15]`, `ffr` |
|
||||||
|
| ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` |
|
||||||
|
| RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` |
|
||||||
|
|
||||||
|
The list of clobbered registers for each ABI is updated in rustc as architectures gain new registers: this ensures that `asm` clobbers will continue to be correct when LLVM starts using these new registers in its generated code.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
Flags are used to further influence the behavior of the inline assembly block.
|
Flags are used to further influence the behavior of the inline assembly block.
|
||||||
|
|
35
src/test/codegen/asm-clobber_abi.rs
Normal file
35
src/test/codegen/asm-clobber_abi.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// compile-flags: -O
|
||||||
|
// only-x86_64
|
||||||
|
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
// CHECK-LABEL: @clobber_sysv64
|
||||||
|
// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn clobber_sysv64() {
|
||||||
|
asm!("", clobber_abi("sysv64"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @clobber_win64
|
||||||
|
// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn clobber_win64() {
|
||||||
|
asm!("", clobber_abi("win64"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @clobber_sysv64
|
||||||
|
// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn clobber_sysv64_edx() {
|
||||||
|
let foo: i32;
|
||||||
|
asm!("", out("edx") foo, clobber_abi("sysv64"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @clobber_win64
|
||||||
|
// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn clobber_win64_edx() {
|
||||||
|
let foo: i32;
|
||||||
|
asm!("", out("edx") foo, clobber_abi("win64"));
|
||||||
|
}
|
|
@ -15,6 +15,14 @@ fn main() {
|
||||||
asm!("{}", out(reg) foo, options(noreturn));
|
asm!("{}", out(reg) foo, options(noreturn));
|
||||||
//~^ ERROR asm outputs are not allowed with the `noreturn` option
|
//~^ ERROR asm outputs are not allowed with the `noreturn` option
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("", clobber_abi("foo"));
|
||||||
|
//~^ ERROR invalid ABI for `clobber_abi`
|
||||||
|
asm!("{}", out(reg) foo, clobber_abi("C"));
|
||||||
|
//~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
|
||||||
|
asm!("", out("eax") foo, clobber_abi("C"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global_asm!("", options(nomem));
|
global_asm!("", options(nomem));
|
||||||
|
|
|
@ -28,41 +28,57 @@ error: asm outputs are not allowed with the `noreturn` option
|
||||||
LL | asm!("{}", out(reg) foo, options(noreturn));
|
LL | asm!("{}", out(reg) foo, options(noreturn));
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: asm with `clobber_abi` must specify explicit registers for outputs
|
||||||
|
--> $DIR/bad-options.rs:22:20
|
||||||
|
|
|
||||||
|
LL | asm!("{}", out(reg) foo, clobber_abi("C"));
|
||||||
|
| ^^^^^^^^^^^^ ---------------- clobber_abi
|
||||||
|
| |
|
||||||
|
| generic outputs
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
||||||
--> $DIR/bad-options.rs:20:25
|
--> $DIR/bad-options.rs:28:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(nomem));
|
LL | global_asm!("", options(nomem));
|
||||||
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
|
||||||
--> $DIR/bad-options.rs:22:25
|
--> $DIR/bad-options.rs:30:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(readonly));
|
LL | global_asm!("", options(readonly));
|
||||||
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
|
||||||
--> $DIR/bad-options.rs:24:25
|
--> $DIR/bad-options.rs:32:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(noreturn));
|
LL | global_asm!("", options(noreturn));
|
||||||
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
|
||||||
--> $DIR/bad-options.rs:26:25
|
--> $DIR/bad-options.rs:34:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(pure));
|
LL | global_asm!("", options(pure));
|
||||||
| ^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
|
||||||
--> $DIR/bad-options.rs:28:25
|
--> $DIR/bad-options.rs:36:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(nostack));
|
LL | global_asm!("", options(nostack));
|
||||||
| ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
|
||||||
--> $DIR/bad-options.rs:30:25
|
--> $DIR/bad-options.rs:38:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(preserves_flags));
|
LL | global_asm!("", options(preserves_flags));
|
||||||
| ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: invalid ABI for `clobber_abi`
|
||||||
|
--> $DIR/bad-options.rs:20:18
|
||||||
|
|
|
||||||
|
LL | asm!("", clobber_abi("foo"));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
|
||||||
|
|
||||||
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn main() {
|
||||||
asm!("{}" foo);
|
asm!("{}" foo);
|
||||||
//~^ ERROR expected token: `,`
|
//~^ ERROR expected token: `,`
|
||||||
asm!("{}", foo);
|
asm!("{}", foo);
|
||||||
//~^ ERROR expected operand, options, or additional template string
|
//~^ ERROR expected operand, clobber_abi, options, or additional template string
|
||||||
asm!("{}", in foo);
|
asm!("{}", in foo);
|
||||||
//~^ ERROR expected `(`, found `foo`
|
//~^ ERROR expected `(`, found `foo`
|
||||||
asm!("{}", in(reg foo));
|
asm!("{}", in(reg foo));
|
||||||
|
@ -37,6 +37,21 @@ fn main() {
|
||||||
asm!("{}", options(), const foo);
|
asm!("{}", options(), const foo);
|
||||||
//~^ ERROR arguments are not allowed after options
|
//~^ ERROR arguments are not allowed after options
|
||||||
//~^^ ERROR attempt to use a non-constant value in a constant
|
//~^^ ERROR attempt to use a non-constant value in a constant
|
||||||
|
asm!("", clobber_abi(foo));
|
||||||
|
//~^ ERROR expected string literal
|
||||||
|
asm!("", clobber_abi("C" foo));
|
||||||
|
//~^ ERROR expected `)`, found `foo`
|
||||||
|
asm!("", clobber_abi("C", foo));
|
||||||
|
//~^ ERROR expected `)`, found `,`
|
||||||
|
asm!("{}", clobber_abi("C"), const foo);
|
||||||
|
//~^ ERROR arguments are not allowed after clobber_abi
|
||||||
|
//~^^ ERROR attempt to use a non-constant value in a constant
|
||||||
|
asm!("", options(), clobber_abi("C"));
|
||||||
|
//~^ ERROR clobber_abi is not allowed after options
|
||||||
|
asm!("{}", options(), clobber_abi("C"), const foo);
|
||||||
|
//~^ ERROR clobber_abi is not allowed after options
|
||||||
|
asm!("", clobber_abi("C"), clobber_abi("C"));
|
||||||
|
//~^ ERROR clobber_abi specified multiple times
|
||||||
asm!("{a}", a = const foo, a = const bar);
|
asm!("{a}", a = const foo, a = const bar);
|
||||||
//~^ ERROR duplicate argument named `a`
|
//~^ ERROR duplicate argument named `a`
|
||||||
//~^^ ERROR argument never used
|
//~^^ ERROR argument never used
|
||||||
|
@ -86,6 +101,21 @@ global_asm!("", options(nomem, FOO));
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR expected one of
|
||||||
global_asm!("{}", options(), const FOO);
|
global_asm!("{}", options(), const FOO);
|
||||||
//~^ ERROR arguments are not allowed after options
|
//~^ ERROR arguments are not allowed after options
|
||||||
|
global_asm!("", clobber_abi(FOO));
|
||||||
|
//~^ ERROR expected string literal
|
||||||
|
global_asm!("", clobber_abi("C" FOO));
|
||||||
|
//~^ ERROR expected `)`, found `FOO`
|
||||||
|
global_asm!("", clobber_abi("C", FOO));
|
||||||
|
//~^ ERROR expected `)`, found `,`
|
||||||
|
global_asm!("{}", clobber_abi("C"), const FOO);
|
||||||
|
//~^ ERROR arguments are not allowed after clobber_abi
|
||||||
|
//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
|
||||||
|
global_asm!("", options(), clobber_abi("C"));
|
||||||
|
//~^ ERROR clobber_abi is not allowed after options
|
||||||
|
global_asm!("{}", options(), clobber_abi("C"), const FOO);
|
||||||
|
//~^ ERROR clobber_abi is not allowed after options
|
||||||
|
global_asm!("", clobber_abi("C"), clobber_abi("C"));
|
||||||
|
//~^ ERROR clobber_abi specified multiple times
|
||||||
global_asm!("{a}", a = const FOO, a = const BAR);
|
global_asm!("{a}", a = const FOO, a = const BAR);
|
||||||
//~^ ERROR duplicate argument named `a`
|
//~^ ERROR duplicate argument named `a`
|
||||||
//~^^ ERROR argument never used
|
//~^^ ERROR argument never used
|
||||||
|
|
|
@ -16,11 +16,11 @@ error: expected token: `,`
|
||||||
LL | asm!("{}" foo);
|
LL | asm!("{}" foo);
|
||||||
| ^^^ expected `,`
|
| ^^^ expected `,`
|
||||||
|
|
||||||
error: expected operand, options, or additional template string
|
error: expected operand, clobber_abi, options, or additional template string
|
||||||
--> $DIR/parse-error.rs:15:20
|
--> $DIR/parse-error.rs:15:20
|
||||||
|
|
|
|
||||||
LL | asm!("{}", foo);
|
LL | asm!("{}", foo);
|
||||||
| ^^^ expected operand, options, or additional template string
|
| ^^^ expected operand, clobber_abi, options, or additional template string
|
||||||
|
|
||||||
error: expected `(`, found `foo`
|
error: expected `(`, found `foo`
|
||||||
--> $DIR/parse-error.rs:17:23
|
--> $DIR/parse-error.rs:17:23
|
||||||
|
@ -90,8 +90,58 @@ LL | asm!("{}", options(), const foo);
|
||||||
| |
|
| |
|
||||||
| previous options
|
| previous options
|
||||||
|
|
||||||
|
error: expected string literal
|
||||||
|
--> $DIR/parse-error.rs:40:30
|
||||||
|
|
|
||||||
|
LL | asm!("", clobber_abi(foo));
|
||||||
|
| ^^^ not a string literal
|
||||||
|
|
||||||
|
error: expected `)`, found `foo`
|
||||||
|
--> $DIR/parse-error.rs:42:34
|
||||||
|
|
|
||||||
|
LL | asm!("", clobber_abi("C" foo));
|
||||||
|
| ^^^ expected `)`
|
||||||
|
|
||||||
|
error: expected `)`, found `,`
|
||||||
|
--> $DIR/parse-error.rs:44:33
|
||||||
|
|
|
||||||
|
LL | asm!("", clobber_abi("C", foo));
|
||||||
|
| ^ expected `)`
|
||||||
|
|
||||||
|
error: arguments are not allowed after clobber_abi
|
||||||
|
--> $DIR/parse-error.rs:46:38
|
||||||
|
|
|
||||||
|
LL | asm!("{}", clobber_abi("C"), const foo);
|
||||||
|
| ---------------- ^^^^^^^^^ argument
|
||||||
|
| |
|
||||||
|
| clobber_abi
|
||||||
|
|
||||||
|
error: clobber_abi is not allowed after options
|
||||||
|
--> $DIR/parse-error.rs:49:29
|
||||||
|
|
|
||||||
|
LL | asm!("", options(), clobber_abi("C"));
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| options
|
||||||
|
|
||||||
|
error: clobber_abi is not allowed after options
|
||||||
|
--> $DIR/parse-error.rs:51:31
|
||||||
|
|
|
||||||
|
LL | asm!("{}", options(), clobber_abi("C"), const foo);
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| options
|
||||||
|
|
||||||
|
error: clobber_abi specified multiple times
|
||||||
|
--> $DIR/parse-error.rs:53:36
|
||||||
|
|
|
||||||
|
LL | asm!("", clobber_abi("C"), clobber_abi("C"));
|
||||||
|
| ---------------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| clobber_abi previously specified here
|
||||||
|
|
||||||
error: duplicate argument named `a`
|
error: duplicate argument named `a`
|
||||||
--> $DIR/parse-error.rs:40:36
|
--> $DIR/parse-error.rs:55:36
|
||||||
|
|
|
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ------------- ^^^^^^^^^^^^^ duplicate argument
|
| ------------- ^^^^^^^^^^^^^ duplicate argument
|
||||||
|
@ -99,7 +149,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| previously here
|
| previously here
|
||||||
|
|
||||||
error: argument never used
|
error: argument never used
|
||||||
--> $DIR/parse-error.rs:40:36
|
--> $DIR/parse-error.rs:55:36
|
||||||
|
|
|
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^^^^^^^^^^^ argument never used
|
| ^^^^^^^^^^^^^ argument never used
|
||||||
|
@ -107,13 +157,13 @@ LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
||||||
|
|
||||||
error: explicit register arguments cannot have names
|
error: explicit register arguments cannot have names
|
||||||
--> $DIR/parse-error.rs:45:18
|
--> $DIR/parse-error.rs:60:18
|
||||||
|
|
|
|
||||||
LL | asm!("", a = in("eax") foo);
|
LL | asm!("", a = in("eax") foo);
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: named arguments cannot follow explicit register arguments
|
error: named arguments cannot follow explicit register arguments
|
||||||
--> $DIR/parse-error.rs:47:36
|
--> $DIR/parse-error.rs:62:36
|
||||||
|
|
|
|
||||||
LL | asm!("{a}", in("eax") foo, a = const bar);
|
LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ------------- ^^^^^^^^^^^^^ named argument
|
| ------------- ^^^^^^^^^^^^^ named argument
|
||||||
|
@ -121,7 +171,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| explicit register argument
|
| explicit register argument
|
||||||
|
|
||||||
error: named arguments cannot follow explicit register arguments
|
error: named arguments cannot follow explicit register arguments
|
||||||
--> $DIR/parse-error.rs:50:36
|
--> $DIR/parse-error.rs:65:36
|
||||||
|
|
|
|
||||||
LL | asm!("{a}", in("eax") foo, a = const bar);
|
LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ------------- ^^^^^^^^^^^^^ named argument
|
| ------------- ^^^^^^^^^^^^^ named argument
|
||||||
|
@ -129,27 +179,27 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| explicit register argument
|
| explicit register argument
|
||||||
|
|
||||||
error: positional arguments cannot follow named arguments or explicit register arguments
|
error: positional arguments cannot follow named arguments or explicit register arguments
|
||||||
--> $DIR/parse-error.rs:53:36
|
--> $DIR/parse-error.rs:68:36
|
||||||
|
|
|
|
||||||
LL | asm!("{1}", in("eax") foo, const bar);
|
LL | asm!("{1}", in("eax") foo, const bar);
|
||||||
| ------------- ^^^^^^^^^ positional argument
|
| ------------- ^^^^^^^^^ positional argument
|
||||||
| |
|
| |
|
||||||
| explicit register argument
|
| explicit register argument
|
||||||
|
|
||||||
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
|
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
|
||||||
--> $DIR/parse-error.rs:56:29
|
--> $DIR/parse-error.rs:71:29
|
||||||
|
|
|
|
||||||
LL | asm!("", options(), "");
|
LL | asm!("", options(), "");
|
||||||
| ^^ expected one of 8 possible tokens
|
| ^^ expected one of 9 possible tokens
|
||||||
|
|
||||||
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
|
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
|
||||||
--> $DIR/parse-error.rs:58:33
|
--> $DIR/parse-error.rs:73:33
|
||||||
|
|
|
|
||||||
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
|
||||||
| ^^^^ expected one of 8 possible tokens
|
| ^^^^ expected one of 9 possible tokens
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/parse-error.rs:60:14
|
--> $DIR/parse-error.rs:75:14
|
||||||
|
|
|
|
||||||
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -157,7 +207,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo);
|
||||||
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/parse-error.rs:62:21
|
--> $DIR/parse-error.rs:77:21
|
||||||
|
|
|
|
||||||
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -165,69 +215,125 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
|
||||||
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: requires at least a template string argument
|
error: requires at least a template string argument
|
||||||
--> $DIR/parse-error.rs:69:1
|
--> $DIR/parse-error.rs:84:1
|
||||||
|
|
|
|
||||||
LL | global_asm!();
|
LL | global_asm!();
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/parse-error.rs:71:13
|
--> $DIR/parse-error.rs:86:13
|
||||||
|
|
|
|
||||||
LL | global_asm!(FOO);
|
LL | global_asm!(FOO);
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: expected token: `,`
|
error: expected token: `,`
|
||||||
--> $DIR/parse-error.rs:73:18
|
--> $DIR/parse-error.rs:88:18
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}" FOO);
|
LL | global_asm!("{}" FOO);
|
||||||
| ^^^ expected `,`
|
| ^^^ expected `,`
|
||||||
|
|
||||||
error: expected operand, options, or additional template string
|
error: expected operand, options, or additional template string
|
||||||
--> $DIR/parse-error.rs:75:19
|
--> $DIR/parse-error.rs:90:19
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}", FOO);
|
LL | global_asm!("{}", FOO);
|
||||||
| ^^^ expected operand, options, or additional template string
|
| ^^^ expected operand, options, or additional template string
|
||||||
|
|
||||||
error: expected expression, found end of macro arguments
|
error: expected expression, found end of macro arguments
|
||||||
--> $DIR/parse-error.rs:77:24
|
--> $DIR/parse-error.rs:92:24
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}", const);
|
LL | global_asm!("{}", const);
|
||||||
| ^ expected expression
|
| ^ expected expression
|
||||||
|
|
||||||
error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
|
error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
|
||||||
--> $DIR/parse-error.rs:79:30
|
--> $DIR/parse-error.rs:94:30
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}", const(reg) FOO);
|
LL | global_asm!("{}", const(reg) FOO);
|
||||||
| ^^^ expected one of `,`, `.`, `?`, or an operator
|
| ^^^ expected one of `,`, `.`, `?`, or an operator
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
|
||||||
--> $DIR/parse-error.rs:81:25
|
--> $DIR/parse-error.rs:96:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(FOO));
|
LL | global_asm!("", options(FOO));
|
||||||
| ^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
||||||
--> $DIR/parse-error.rs:83:25
|
--> $DIR/parse-error.rs:98:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(nomem FOO));
|
LL | global_asm!("", options(nomem FOO));
|
||||||
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
|
||||||
--> $DIR/parse-error.rs:85:25
|
--> $DIR/parse-error.rs:100:25
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(nomem, FOO));
|
LL | global_asm!("", options(nomem, FOO));
|
||||||
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
||||||
|
|
||||||
error: arguments are not allowed after options
|
error: arguments are not allowed after options
|
||||||
--> $DIR/parse-error.rs:87:30
|
--> $DIR/parse-error.rs:102:30
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}", options(), const FOO);
|
LL | global_asm!("{}", options(), const FOO);
|
||||||
| --------- ^^^^^^^^^ argument
|
| --------- ^^^^^^^^^ argument
|
||||||
| |
|
| |
|
||||||
| previous options
|
| previous options
|
||||||
|
|
||||||
|
error: expected string literal
|
||||||
|
--> $DIR/parse-error.rs:104:29
|
||||||
|
|
|
||||||
|
LL | global_asm!("", clobber_abi(FOO));
|
||||||
|
| ^^^ not a string literal
|
||||||
|
|
||||||
|
error: expected `)`, found `FOO`
|
||||||
|
--> $DIR/parse-error.rs:106:33
|
||||||
|
|
|
||||||
|
LL | global_asm!("", clobber_abi("C" FOO));
|
||||||
|
| ^^^ expected `)`
|
||||||
|
|
||||||
|
error: expected `)`, found `,`
|
||||||
|
--> $DIR/parse-error.rs:108:32
|
||||||
|
|
|
||||||
|
LL | global_asm!("", clobber_abi("C", FOO));
|
||||||
|
| ^ expected `)`
|
||||||
|
|
||||||
|
error: arguments are not allowed after clobber_abi
|
||||||
|
--> $DIR/parse-error.rs:110:37
|
||||||
|
|
|
||||||
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
|
||||||
|
| ---------------- ^^^^^^^^^ argument
|
||||||
|
| |
|
||||||
|
| clobber_abi
|
||||||
|
|
||||||
|
error: `clobber_abi` cannot be used with `global_asm!`
|
||||||
|
--> $DIR/parse-error.rs:110:19
|
||||||
|
|
|
||||||
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: clobber_abi is not allowed after options
|
||||||
|
--> $DIR/parse-error.rs:113:28
|
||||||
|
|
|
||||||
|
LL | global_asm!("", options(), clobber_abi("C"));
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| options
|
||||||
|
|
||||||
|
error: clobber_abi is not allowed after options
|
||||||
|
--> $DIR/parse-error.rs:115:30
|
||||||
|
|
|
||||||
|
LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| options
|
||||||
|
|
||||||
|
error: clobber_abi specified multiple times
|
||||||
|
--> $DIR/parse-error.rs:117:35
|
||||||
|
|
|
||||||
|
LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
|
||||||
|
| ---------------- ^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| clobber_abi previously specified here
|
||||||
|
|
||||||
error: duplicate argument named `a`
|
error: duplicate argument named `a`
|
||||||
--> $DIR/parse-error.rs:89:35
|
--> $DIR/parse-error.rs:119:35
|
||||||
|
|
|
|
||||||
LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
||||||
| ------------- ^^^^^^^^^^^^^ duplicate argument
|
| ------------- ^^^^^^^^^^^^^ duplicate argument
|
||||||
|
@ -235,27 +341,27 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
||||||
| previously here
|
| previously here
|
||||||
|
|
||||||
error: argument never used
|
error: argument never used
|
||||||
--> $DIR/parse-error.rs:89:35
|
--> $DIR/parse-error.rs:119:35
|
||||||
|
|
|
|
||||||
LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
|
||||||
| ^^^^^^^^^^^^^ argument never used
|
| ^^^^^^^^^^^^^ argument never used
|
||||||
|
|
|
|
||||||
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
|
||||||
|
|
||||||
error: expected one of `const` or `options`, found `""`
|
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
|
||||||
--> $DIR/parse-error.rs:92:28
|
--> $DIR/parse-error.rs:122:28
|
||||||
|
|
|
|
||||||
LL | global_asm!("", options(), "");
|
LL | global_asm!("", options(), "");
|
||||||
| ^^ expected one of `const` or `options`
|
| ^^ expected one of `clobber_abi`, `const`, or `options`
|
||||||
|
|
||||||
error: expected one of `const` or `options`, found `"{}"`
|
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
|
||||||
--> $DIR/parse-error.rs:94:30
|
--> $DIR/parse-error.rs:124:30
|
||||||
|
|
|
|
||||||
LL | global_asm!("{}", const FOO, "{}", const FOO);
|
LL | global_asm!("{}", const FOO, "{}", const FOO);
|
||||||
| ^^^^ expected one of `const` or `options`
|
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/parse-error.rs:96:13
|
--> $DIR/parse-error.rs:126:13
|
||||||
|
|
|
|
||||||
LL | global_asm!(format!("{{{}}}", 0), const FOO);
|
LL | global_asm!(format!("{{{}}}", 0), const FOO);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -263,7 +369,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
|
||||||
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: asm template must be a string literal
|
error: asm template must be a string literal
|
||||||
--> $DIR/parse-error.rs:98:20
|
--> $DIR/parse-error.rs:128:20
|
||||||
|
|
|
|
||||||
LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
|
LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -280,7 +386,16 @@ LL | asm!("{}", options(), const foo);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error[E0435]: attempt to use a non-constant value in a constant
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:40:31
|
--> $DIR/parse-error.rs:46:44
|
||||||
|
|
|
||||||
|
LL | let mut foo = 0;
|
||||||
|
| ---------- help: consider using `const` instead of `let`: `const foo`
|
||||||
|
...
|
||||||
|
LL | asm!("{}", clobber_abi("C"), const foo);
|
||||||
|
| ^^^ non-constant value
|
||||||
|
|
||||||
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
|
--> $DIR/parse-error.rs:55:31
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ---------- help: consider using `const` instead of `let`: `const foo`
|
||||||
|
@ -289,7 +404,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error[E0435]: attempt to use a non-constant value in a constant
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:40:46
|
--> $DIR/parse-error.rs:55:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ---------- help: consider using `const` instead of `let`: `const bar`
|
||||||
|
@ -298,7 +413,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error[E0435]: attempt to use a non-constant value in a constant
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:47:46
|
--> $DIR/parse-error.rs:62:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ---------- help: consider using `const` instead of `let`: `const bar`
|
||||||
|
@ -307,7 +422,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error[E0435]: attempt to use a non-constant value in a constant
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:50:46
|
--> $DIR/parse-error.rs:65:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ---------- help: consider using `const` instead of `let`: `const bar`
|
||||||
|
@ -316,7 +431,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error[E0435]: attempt to use a non-constant value in a constant
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:53:42
|
--> $DIR/parse-error.rs:68:42
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ---------- help: consider using `const` instead of `let`: `const bar`
|
||||||
|
@ -324,6 +439,6 @@ LL | let mut bar = 0;
|
||||||
LL | asm!("{1}", in("eax") foo, const bar);
|
LL | asm!("{1}", in("eax") foo, const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
||||||
error: aborting due to 47 previous errors
|
error: aborting due to 63 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0435`.
|
For more information about this error, try `rustc --explain E0435`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue