1
Fork 0

Auto merge of #92816 - tmiasko:rm-llvm-asm, r=Amanieu

Remove deprecated LLVM-style inline assembly

The `llvm_asm!` was deprecated back in #87590 1.56.0, with intention to remove
it once `asm!` was stabilized, which already happened in #91728 1.59.0. Now it
is time to remove `llvm_asm!` to avoid continued maintenance cost.

Closes #70173.
Closes #92794.
Closes #87612.
Closes #82065.

cc `@rust-lang/wg-inline-asm`

r? `@Amanieu`
This commit is contained in:
bors 2022-01-17 09:40:29 +00:00
commit a34c079752
171 changed files with 235 additions and 3297 deletions

View file

@ -1266,7 +1266,7 @@ impl Expr {
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@ -1423,8 +1423,6 @@ pub enum ExprKind {
/// Output of the `asm!()` macro.
InlineAsm(P<InlineAsm>),
/// Output of the `llvm_asm!()` macro.
LlvmInlineAsm(P<LlvmInlineAsm>),
/// A macro invocation; pre-expansion.
MacCall(MacCall),
@ -2076,41 +2074,6 @@ pub struct InlineAsm {
pub line_spans: Vec<Span>,
}
/// Inline assembly dialect.
///
/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)]
pub enum LlvmAsmDialect {
Att,
Intel,
}
/// LLVM-style inline assembly.
///
/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct LlvmInlineAsmOutput {
pub constraint: Symbol,
pub expr: P<Expr>,
pub is_rw: bool,
pub is_indirect: bool,
}
/// LLVM-style inline assembly.
///
/// E.g., `llvm_asm!("NOP");`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct LlvmInlineAsm {
pub asm: Symbol,
pub asm_str_style: StrStyle,
pub outputs: Vec<LlvmInlineAsmOutput>,
pub inputs: Vec<(Symbol, P<Expr>)>,
pub clobbers: Vec<Symbol>,
pub volatile: bool,
pub alignstack: bool,
pub dialect: LlvmAsmDialect,
}
/// A parameter in a function header.
///
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.

View file

@ -1350,23 +1350,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
ExprKind::LlvmInlineAsm(asm) => {
let LlvmInlineAsm {
asm: _,
asm_str_style: _,
outputs,
inputs,
clobbers: _,
volatile: _,
alignstack: _,
dialect: _,
} = asm.deref_mut();
for out in outputs {
let LlvmInlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
vis.visit_expr(expr);
}
visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
}
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
let StructExpr { qself, path, fields, rest } = se.deref_mut();

View file

@ -864,14 +864,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
ExprKind::LlvmInlineAsm(ref ia) => {
for &(_, ref input) in &ia.inputs {
visitor.visit_expr(input)
}
for output in &ia.outputs {
visitor.visit_expr(&output.expr)
}
}
ExprKind::Yield(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}

View file

@ -226,7 +226,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::InlineAsm(ref asm) => {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
ExprKind::Struct(ref se) => {
let rest = match &se.rest {
StructRest::Base(e) => Some(self.lower_expr(e)),
@ -1286,38 +1285,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
result
}
fn lower_expr_llvm_asm(&mut self, asm: &LlvmInlineAsm) -> hir::ExprKind<'hir> {
let inner = hir::LlvmInlineAsmInner {
inputs: asm.inputs.iter().map(|&(c, _)| c).collect(),
outputs: asm
.outputs
.iter()
.map(|out| hir::LlvmInlineAsmOutput {
constraint: out.constraint,
is_rw: out.is_rw,
is_indirect: out.is_indirect,
span: self.lower_span(out.expr.span),
})
.collect(),
asm: asm.asm,
asm_str_style: asm.asm_str_style,
clobbers: asm.clobbers.clone(),
volatile: asm.volatile,
alignstack: asm.alignstack,
dialect: asm.dialect,
};
let hir_asm = hir::LlvmInlineAsm {
inner,
inputs_exprs: self.arena.alloc_from_iter(
asm.inputs.iter().map(|&(_, ref input)| self.lower_expr_mut(input)),
),
outputs_exprs: self
.arena
.alloc_from_iter(asm.outputs.iter().map(|out| self.lower_expr_mut(&out.expr))),
};
hir::ExprKind::LlvmInlineAsm(self.arena.alloc(hir_asm))
}
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
hir::ExprField {
hir_id: self.next_id(),

View file

@ -960,15 +960,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
return;
}
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
struct_span_err!(
this.session,
expr.span,
E0472,
"llvm_asm! is unsupported on this target"
)
.emit();
}
ExprKind::Match(expr, arms) => {
this.visit_expr(expr);
for arm in arms {

View file

@ -2168,62 +2168,6 @@ impl<'a> State<'a> {
self.word("asm!");
self.print_inline_asm(a);
}
ast::ExprKind::LlvmInlineAsm(ref a) => {
self.word("llvm_asm!");
self.popen();
self.print_symbol(a.asm, a.asm_str_style);
self.word_space(":");
self.commasep(Inconsistent, &a.outputs, |s, out| {
let constraint = out.constraint.as_str();
let mut ch = constraint.chars();
match ch.next() {
Some('=') if out.is_rw => {
s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
}
_ => s.print_string(&constraint, ast::StrStyle::Cooked),
}
s.popen();
s.print_expr(&out.expr);
s.pclose();
});
self.space();
self.word_space(":");
self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
s.print_symbol(co, ast::StrStyle::Cooked);
s.popen();
s.print_expr(o);
s.pclose();
});
self.space();
self.word_space(":");
self.commasep(Inconsistent, &a.clobbers, |s, &co| {
s.print_symbol(co, ast::StrStyle::Cooked);
});
let mut options = vec![];
if a.volatile {
options.push("volatile");
}
if a.alignstack {
options.push("alignstack");
}
if a.dialect == ast::LlvmAsmDialect::Intel {
options.push("intel");
}
if !options.is_empty() {
self.space();
self.word_space(":");
self.commasep(Inconsistent, &options, |s, &co| {
s.print_string(co, ast::StrStyle::Cooked);
});
}
self.pclose();
}
ast::ExprKind::MacCall(ref m) => self.print_mac(m),
ast::ExprKind::Paren(ref e) => {
self.popen();

View file

@ -8,7 +8,6 @@ use rustc_mir_dataflow::ResultsVisitable;
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use std::fmt;
use std::iter;
use crate::{
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
@ -385,14 +384,6 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
self.kill_borrows_on_place(trans, Place::from(local));
}
mir::StatementKind::LlvmInlineAsm(ref asm) => {
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect && !kind.is_rw {
self.kill_borrows_on_place(trans, *output);
}
}
}
mir::StatementKind::FakeRead(..)
| mir::StatementKind::SetDiscriminant { .. }
| mir::StatementKind::StorageLive(..)

View file

@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
PlaceContext::MutatingUse(MutatingUseContext::Store) |
// This is potentially both a def and a use...
PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
// We let Call define the result in both the success and
// unwind cases. This is not really correct, however it
// does not seem to be observable due to the way that we

View file

@ -5,12 +5,11 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
use rustc_middle::ty::TyCtxt;
use std::iter;
use crate::{
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind,
ReadOrWrite, Reservation, Shallow, Write, WriteKind,
};
pub(super) fn generate_invalidates<'tcx>(
@ -59,37 +58,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
StatementKind::Assign(box (lhs, rhs)) => {
self.consume_rvalue(location, rhs);
self.mutate_place(location, *lhs, Shallow(None), JustWrite);
self.mutate_place(location, *lhs, Shallow(None));
}
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
StatementKind::SetDiscriminant { place, variant_index: _ } => {
self.mutate_place(location, **place, Shallow(None), JustWrite);
}
StatementKind::LlvmInlineAsm(asm) => {
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.
self.access_place(
location,
*output,
(Deep, Read(ReadKind::Copy)),
LocalMutationIsAllowed::No,
);
} else {
self.mutate_place(
location,
*output,
if o.is_rw { Deep } else { Shallow(None) },
if o.is_rw { WriteAndRead } else { JustWrite },
);
}
}
for (_, input) in asm.inputs.iter() {
self.consume_operand(location, input);
}
self.mutate_place(location, **place, Shallow(None));
}
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
ref src,
@ -142,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
target: _,
unwind: _,
} => {
self.mutate_place(location, *drop_place, Deep, JustWrite);
self.mutate_place(location, *drop_place, Deep);
self.consume_operand(location, new_value);
}
TerminatorKind::Call {
@ -158,7 +133,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
self.consume_operand(location, arg);
}
if let Some((dest, _ /*bb*/)) = destination {
self.mutate_place(location, *dest, Deep, JustWrite);
self.mutate_place(location, *dest, Deep);
}
}
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@ -181,7 +156,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
}
self.mutate_place(location, *resume_arg, Deep, JustWrite);
self.mutate_place(location, *resume_arg, Deep);
}
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
// Invalidate all borrows of local places
@ -208,13 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
if let Some(place) = place {
self.mutate_place(location, place, Shallow(None), JustWrite);
self.mutate_place(location, place, Shallow(None));
}
}
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
self.consume_operand(location, in_value);
if let Some(out_place) = out_place {
self.mutate_place(location, out_place, Shallow(None), JustWrite);
self.mutate_place(location, out_place, Shallow(None));
}
}
InlineAsmOperand::Const { value: _ }
@ -238,13 +213,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
/// Simulates mutation of a place.
fn mutate_place(
&mut self,
location: Location,
place: Place<'tcx>,
kind: AccessDepth,
_mode: MutateMode,
) {
fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
self.access_place(
location,
place,

View file

@ -40,7 +40,6 @@ use either::Either;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::iter;
use std::mem;
use std::rc::Rc;
@ -55,7 +54,6 @@ use rustc_mir_dataflow::MoveDataParamEnv;
use self::diagnostics::{AccessKind, RegionName};
use self::location::LocationTable;
use self::prefixes::PrefixSet;
use self::MutateMode::{JustWrite, WriteAndRead};
use facts::AllFacts;
use self::path_utils::*;
@ -630,7 +628,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
StatementKind::Assign(box (lhs, ref rhs)) => {
self.consume_rvalue(location, (rhs, span), flow_state);
self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
}
StatementKind::FakeRead(box (_, ref place)) => {
// Read for match doesn't access any memory and is used to
@ -651,41 +649,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
);
}
StatementKind::SetDiscriminant { place, variant_index: _ } => {
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
self.mutate_place(location, (**place, span), Shallow(None), flow_state);
}
StatementKind::LlvmInlineAsm(ref asm) => {
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
if o.is_indirect {
// FIXME(eddyb) indirect inline asm outputs should
// be encoded through MIR place derefs instead.
self.access_place(
location,
(*output, o.span),
(Deep, Read(ReadKind::Copy)),
LocalMutationIsAllowed::No,
flow_state,
);
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(output.as_ref(), o.span),
flow_state,
);
} else {
self.mutate_place(
location,
(*output, o.span),
if o.is_rw { Deep } else { Shallow(None) },
if o.is_rw { WriteAndRead } else { JustWrite },
flow_state,
);
}
}
for (_, input) in asm.inputs.iter() {
self.consume_operand(location, (input, span), flow_state);
}
}
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
..
}) => {
@ -750,7 +715,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
target: _,
unwind: _,
} => {
self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state);
self.mutate_place(loc, (drop_place, span), Deep, flow_state);
self.consume_operand(loc, (new_value, span), flow_state);
}
TerminatorKind::Call {
@ -766,7 +731,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
self.consume_operand(loc, (arg, span), flow_state);
}
if let Some((dest, _ /*bb*/)) = *destination {
self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
self.mutate_place(loc, (dest, span), Deep, flow_state);
}
}
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@ -780,7 +745,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
self.consume_operand(loc, (value, span), flow_state);
self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
}
TerminatorKind::InlineAsm {
@ -798,13 +763,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
if let Some(place) = place {
self.mutate_place(
loc,
(place, span),
Shallow(None),
JustWrite,
flow_state,
);
self.mutate_place(loc, (place, span), Shallow(None), flow_state);
}
}
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
@ -814,7 +773,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
loc,
(out_place, span),
Shallow(None),
JustWrite,
flow_state,
);
}
@ -886,12 +844,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum MutateMode {
JustWrite,
WriteAndRead,
}
use self::AccessDepth::{Deep, Shallow};
use self::ReadOrWrite::{Activation, Read, Reservation, Write};
@ -977,7 +929,6 @@ enum LocalMutationIsAllowed {
#[derive(Copy, Clone, Debug)]
enum InitializationRequiringAction {
Update,
Borrow,
MatchOn,
Use,
@ -994,7 +945,6 @@ struct RootPlace<'tcx> {
impl InitializationRequiringAction {
fn as_noun(self) -> &'static str {
match self {
InitializationRequiringAction::Update => "update",
InitializationRequiringAction::Borrow => "borrow",
InitializationRequiringAction::MatchOn => "use", // no good noun
InitializationRequiringAction::Use => "use",
@ -1005,7 +955,6 @@ impl InitializationRequiringAction {
fn as_verb_in_past_tense(self) -> &'static str {
match self {
InitializationRequiringAction::Update => "updated",
InitializationRequiringAction::Borrow => "borrowed",
InitializationRequiringAction::MatchOn => "matched on",
InitializationRequiringAction::Use => "used",
@ -1242,23 +1191,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
location: Location,
place_span: (Place<'tcx>, Span),
kind: AccessDepth,
mode: MutateMode,
flow_state: &Flows<'cx, 'tcx>,
) {
// Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
match mode {
MutateMode::WriteAndRead => {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Update,
(place_span.0.as_ref(), place_span.1),
flow_state,
);
}
MutateMode::JustWrite => {
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
}
}
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
// Special case: you can assign an immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized

View file

@ -1478,7 +1478,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::LlvmInlineAsm { .. }
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
| StatementKind::Nop => {}

View file

@ -50,15 +50,6 @@ pub fn parse_asm_args<'a>(
return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
}
// Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
let mut err =
diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
err.note("consider migrating to the new asm! syntax specified in RFC 2873");
err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
return Err(err);
}
let first_template = p.parse_expr()?;
let mut args = AsmArgs {
templates: vec![first_template],

View file

@ -33,7 +33,6 @@ mod env;
mod format;
mod format_foreign;
mod global_allocator;
mod llvm_asm;
mod log_syntax;
mod panic;
mod source_util;
@ -78,7 +77,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
include_str: source_util::expand_include_str,
include: source_util::expand_include,
line: source_util::expand_line,
llvm_asm: llvm_asm::expand_llvm_asm,
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,

View file

@ -1,303 +0,0 @@
// Llvm-style inline assembly support.
//
use State::*;
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{self, TokenStream};
use rustc_ast::LlvmAsmDialect;
use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
use rustc_expand::base::*;
use rustc_parse::parser::Parser;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
enum State {
Asm,
Outputs,
Inputs,
Clobbers,
Options,
StateNone,
}
impl State {
fn next(&self) -> State {
match *self {
Asm => Outputs,
Outputs => Inputs,
Inputs => Clobbers,
Clobbers => Options,
Options => StateNone,
StateNone => StateNone,
}
}
}
const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
pub fn expand_llvm_asm<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
Ok(Some(inline_asm)) => inline_asm,
Ok(None) => return DummyResult::any(sp),
Err(mut err) => {
err.emit();
return DummyResult::any(sp);
}
};
// If there are no outputs, the inline assembly is executed just for its side effects,
// so ensure that it is volatile
if inline_asm.outputs.is_empty() {
inline_asm.volatile = true;
}
MacEager::expr(P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)),
span: cx.with_def_site_ctxt(sp),
attrs: ast::AttrVec::new(),
tokens: None,
}))
}
fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> {
match p.parse_str_lit() {
Ok(str_lit) => Ok(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");
Err(err)
}
}
}
fn parse_inline_asm<'a>(
cx: &mut ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
) -> Result<Option<ast::LlvmInlineAsm>, DiagnosticBuilder<'a>> {
// Split the tts before the first colon, to avoid `llvm_asm!("x": y)` being
// parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
let first_colon = tts
.trees()
.position(|tt| {
matches!(
tt,
tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
)
})
.unwrap_or(tts.len());
let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
let mut asm = kw::Empty;
let mut asm_str_style = None;
let mut outputs = Vec::new();
let mut inputs = Vec::new();
let mut clobs = Vec::new();
let mut volatile = false;
let mut alignstack = false;
let mut dialect = LlvmAsmDialect::Att;
let mut state = Asm;
'statement: loop {
match state {
Asm => {
if asm_str_style.is_some() {
// If we already have a string with instructions,
// ending up in Asm state again is an error.
return Err(struct_span_err!(
cx.sess.parse_sess.span_diagnostic,
sp,
E0660,
"malformed inline assembly"
));
}
// Nested parser, stop before the first colon (see above).
let mut p2 = cx.new_parser_from_tts(tts.trees().take(first_colon).collect());
if p2.token == token::Eof {
let mut err =
cx.struct_span_err(sp, "macro requires a string literal as an argument");
err.span_label(sp, "string literal required");
return Err(err);
}
let expr = p2.parse_expr()?;
let (s, style) =
match expr_to_string(cx, expr, "inline assembly must be a string literal") {
Some((s, st)) => (s, st),
None => return Ok(None),
};
// This is most likely malformed.
if p2.token != token::Eof {
let mut extra_tts = p2.parse_all_token_trees()?;
extra_tts.extend(tts.trees().skip(first_colon));
p = cx.new_parser_from_tts(extra_tts.into_iter().collect());
}
asm = s;
asm_str_style = Some(style);
}
Outputs => {
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
if !outputs.is_empty() {
p.eat(&token::Comma);
}
let constraint = parse_asm_str(&mut p)?;
let span = p.prev_token.span;
p.expect(&token::OpenDelim(token::Paren))?;
let expr = p.parse_expr()?;
p.expect(&token::CloseDelim(token::Paren))?;
// Expands a read+write operand into two operands.
//
// Use '+' modifier when you want the same expression
// to be both an input and an output at the same time.
// It's the opposite of '=&' which means that the memory
// cannot be shared with any other operand (usually when
// a register is clobbered early.)
let constraint_str = constraint.as_str();
let mut ch = constraint_str.chars();
let output = match ch.next() {
Some('=') => None,
Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
_ => {
struct_span_err!(
cx.sess.parse_sess.span_diagnostic,
span,
E0661,
"output operand constraint lacks '=' or '+'"
)
.emit();
None
}
};
let is_rw = output.is_some();
let is_indirect = constraint_str.contains('*');
outputs.push(ast::LlvmInlineAsmOutput {
constraint: output.unwrap_or(constraint),
expr,
is_rw,
is_indirect,
});
}
}
Inputs => {
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
if !inputs.is_empty() {
p.eat(&token::Comma);
}
let constraint = parse_asm_str(&mut p)?;
if constraint.as_str().starts_with('=') {
struct_span_err!(
cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0662,
"input operand constraint contains '='"
)
.emit();
} else if constraint.as_str().starts_with('+') {
struct_span_err!(
cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0663,
"input operand constraint contains '+'"
)
.emit();
}
p.expect(&token::OpenDelim(token::Paren))?;
let input = p.parse_expr()?;
p.expect(&token::CloseDelim(token::Paren))?;
inputs.push((constraint, input));
}
}
Clobbers => {
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
if !clobs.is_empty() {
p.eat(&token::Comma);
}
let s = parse_asm_str(&mut p)?;
if OPTIONS.iter().any(|&opt| s == opt) {
cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
} else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
struct_span_err!(
cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0664,
"clobber should not be surrounded by braces"
)
.emit();
}
clobs.push(s);
}
}
Options => {
let option = parse_asm_str(&mut p)?;
if option == sym::volatile {
// Indicates that the inline assembly has side effects
// and must not be optimized out along with its outputs.
volatile = true;
} else if option == sym::alignstack {
alignstack = true;
} else if option == sym::intel {
dialect = LlvmAsmDialect::Intel;
} else {
cx.span_warn(p.prev_token.span, "unrecognized option");
}
if p.token == token::Comma {
p.eat(&token::Comma);
}
}
StateNone => (),
}
loop {
// MOD_SEP is a double colon '::' without space in between.
// When encountered, the state must be advanced twice.
match (&p.token.kind, state.next(), state.next().next()) {
(&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => {
p.bump();
break 'statement;
}
(&token::Colon, st, _) | (&token::ModSep, _, st) => {
p.bump();
state = st;
}
(&token::Eof, ..) => break 'statement,
_ => break,
}
}
}
Ok(Some(ast::LlvmInlineAsm {
asm,
asm_str_style: asm_str_style.unwrap(),
outputs,
inputs,
clobbers: clobs,
volatile,
alignstack,
dialect,
}))
}

View file

@ -749,18 +749,6 @@ fn codegen_stmt<'tcx>(
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..) => {}
StatementKind::LlvmInlineAsm(asm) => {
match asm.asm.asm.as_str().trim() {
"" => {
// Black box
}
_ => fx.tcx.sess.span_fatal(
stmt.source_info.span,
"Legacy `llvm_asm!` inline assembly is not supported. \
Try using the new `asm!` instead.",
),
}
}
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
StatementKind::CopyNonOverlapping(inner) => {
let dst = codegen_operand(fx, &inner.dst);

View file

@ -508,7 +508,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
{
return None;
}
StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
StatementKind::CopyNonOverlapping(_) => {
return None;
} // conservative handling
StatementKind::Assign(_)

View file

@ -4,7 +4,6 @@ use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
use rustc_hir::LlvmInlineAsmInner;
use rustc_middle::{bug, ty::Instance};
use rustc_span::{Span, Symbol};
use rustc_target::asm::*;
@ -106,17 +105,6 @@ enum ConstraintOrRegister {
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
.help("consider using the `asm!` macro instead")
.emit();
// We return `true` even if we've failed to generate the asm
// because we want to suppress the "malformed inline assembly" error
// generated by the frontend.
true
}
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>)>) {
if options.contains(InlineAsmOptions::MAY_UNWIND) {
self.sess()

View file

@ -7,13 +7,10 @@ use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_ast::LlvmAsmDialect;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug, ty::Instance};
use rustc_span::{Pos, Span, Symbol};
@ -24,100 +21,6 @@ use libc::{c_char, c_uint};
use tracing::debug;
impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn codegen_llvm_inline_asm(
&mut self,
ia: &hir::LlvmInlineAsmInner,
outputs: Vec<PlaceRef<'tcx, &'ll Value>>,
mut inputs: Vec<&'ll Value>,
span: Span,
) -> bool {
let mut ext_constraints = vec![];
let mut output_types = vec![];
// Prepare the output operands
let mut indirect_outputs = vec![];
for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() {
if out.is_rw {
let operand = self.load_operand(place);
if let OperandValue::Immediate(_) = operand.val {
inputs.push(operand.immediate());
}
ext_constraints.push(i.to_string());
}
if out.is_indirect {
let operand = self.load_operand(place);
if let OperandValue::Immediate(_) = operand.val {
indirect_outputs.push(operand.immediate());
}
} else {
output_types.push(place.layout.llvm_type(self.cx));
}
}
if !indirect_outputs.is_empty() {
indirect_outputs.extend_from_slice(&inputs);
inputs = indirect_outputs;
}
let clobbers = ia.clobbers.iter().map(|s| format!("~{{{}}}", &s));
// Default per-arch clobbers
// Basically what clang does
let arch_clobbers = match &self.sess().target.arch[..] {
"x86" | "x86_64" => &["~{dirflag}", "~{fpsr}", "~{flags}"][..],
"mips" | "mips64" => &["~{$1}"],
_ => &[],
};
let all_constraints = ia
.outputs
.iter()
.map(|out| out.constraint.to_string())
.chain(ia.inputs.iter().map(|s| s.to_string()))
.chain(ext_constraints)
.chain(clobbers)
.chain(arch_clobbers.iter().map(|s| (*s).to_string()))
.collect::<Vec<String>>()
.join(",");
debug!("Asm Constraints: {}", &all_constraints);
// Depending on how many outputs we have, the return type is different
let num_outputs = output_types.len();
let output_type = match num_outputs {
0 => self.type_void(),
1 => output_types[0],
_ => self.type_struct(&output_types, false),
};
let asm = ia.asm.as_str();
let r = inline_asm_call(
self,
&asm,
&all_constraints,
&inputs,
output_type,
ia.volatile,
ia.alignstack,
ia.dialect,
&[span],
false,
None,
);
if r.is_none() {
return false;
}
let r = r.unwrap();
// Again, based on how many outputs we have
let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect);
for (i, (_, &place)) in outputs.enumerate() {
let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) };
OperandValue::Immediate(v).store(self, place);
}
true
}
fn codegen_inline_asm(
&mut self,
template: &[InlineAsmTemplatePiece],
@ -349,9 +252,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
InlineAsmArch::X86 | InlineAsmArch::X86_64
if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
{
LlvmAsmDialect::Intel
llvm::AsmDialect::Intel
}
_ => LlvmAsmDialect::Att,
_ => llvm::AsmDialect::Att,
};
let result = inline_asm_call(
self,
@ -455,7 +358,7 @@ pub(crate) fn inline_asm_call<'ll>(
output: &'ll llvm::Type,
volatile: bool,
alignstack: bool,
dia: LlvmAsmDialect,
dia: llvm::AsmDialect,
line_spans: &[Span],
unwind: bool,
dest_catch_funclet: Option<(
@ -498,7 +401,7 @@ pub(crate) fn inline_asm_call<'ll>(
cons.len(),
volatile,
alignstack,
llvm::AsmDialect::from_generic(dia),
dia,
can_throw,
);
@ -522,7 +425,7 @@ pub(crate) fn inline_asm_call<'ll>(
// we just encode the start position of each line.
// FIXME: Figure out a way to pass the entire line spans.
let mut srcloc = vec![];
if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 {
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
// LLVM inserts an extra line to add the ".intel_syntax", so add
// a dummy srcloc entry for it.
//

View file

@ -7,7 +7,6 @@ use crate::type_of::LayoutLlvmExt;
use crate::va_arg::emit_va_arg;
use crate::value::Value;
use rustc_ast as ast;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@ -351,7 +350,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
self.type_void(),
true,
false,
ast::LlvmAsmDialect::Att,
llvm::AsmDialect::Att,
&[span],
false,
None,

View file

@ -423,22 +423,13 @@ pub enum MetadataType {
}
/// LLVMRustAsmDialect
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum AsmDialect {
Att,
Intel,
}
impl AsmDialect {
pub fn from_generic(asm: rustc_ast::LlvmAsmDialect) -> Self {
match asm {
rustc_ast::LlvmAsmDialect::Att => AsmDialect::Att,
rustc_ast::LlvmAsmDialect::Intel => AsmDialect::Intel,
}
}
}
/// LLVMRustCodeGenOptLevel
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]

View file

@ -211,7 +211,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::AddressOf

View file

@ -1,9 +1,7 @@
use rustc_errors::struct_span_err;
use rustc_middle::mir;
use super::FunctionCx;
use super::LocalRef;
use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;
@ -66,51 +64,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
bx
}
mir::StatementKind::LlvmInlineAsm(ref asm) => {
let outputs = asm
.outputs
.iter()
.map(|output| self.codegen_place(&mut bx, output.as_ref()))
.collect();
let input_vals = asm.inputs.iter().fold(
Vec::with_capacity(asm.inputs.len()),
|mut acc, (span, input)| {
let op = self.codegen_operand(&mut bx, input);
if let OperandValue::Immediate(_) = op.val {
acc.push(op.immediate());
} else {
struct_span_err!(
bx.sess(),
span.to_owned(),
E0669,
"invalid value for constraint in inline assembly"
)
.emit();
}
acc
},
);
if input_vals.len() == asm.inputs.len() {
let res = bx.codegen_llvm_inline_asm(
&asm.asm,
outputs,
input_vals,
statement.source_info.span,
);
if !res {
struct_span_err!(
bx.sess(),
statement.source_info.span,
E0668,
"malformed inline assembly"
)
.emit();
}
}
bx
}
mir::StatementKind::Coverage(box ref coverage) => {
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
bx

View file

@ -3,7 +3,6 @@ use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::def_id::DefId;
use rustc_hir::LlvmInlineAsmInner;
use rustc_middle::ty::Instance;
use rustc_span::Span;
use rustc_target::asm::InlineAsmRegOrRegClass;
@ -42,15 +41,6 @@ pub enum GlobalAsmOperandRef {
}
pub trait AsmBuilderMethods<'tcx>: BackendTypes {
/// Take an inline assembly expression and splat it out via LLVM
fn codegen_llvm_inline_asm(
&mut self,
ia: &LlvmInlineAsmInner,
outputs: Vec<PlaceRef<'tcx, Self::Value>>,
inputs: Vec<Self::Value>,
span: Span,
) -> bool;
/// Take an inline assembly expression and splat it out via LLVM
fn codegen_inline_asm(
&mut self,

View file

@ -140,8 +140,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.
Nop => {}
LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
}
self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;

View file

@ -751,10 +751,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.super_statement(statement, location);
match statement.kind {
StatementKind::LlvmInlineAsm { .. } => {
self.check_op(ops::InlineAsm);
}
StatementKind::Assign(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::FakeRead(..)

View file

@ -352,7 +352,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::LlvmInlineAsm(..)
| StatementKind::Retag(_, _)
| StatementKind::Coverage(_)
| StatementKind::Nop => {}

View file

@ -1,12 +1,9 @@
#### Note: this error code is no longer emitted by the compiler.
The argument to the `llvm_asm` macro is not well-formed.
Erroneous code example:
```compile_fail,E0660
```ignore (no longer emitted)
llvm_asm!("nop" "nop");
```
Considering that this would be a long explanation, we instead recommend you
take a look at the [`llvm_asm`] chapter of the Unstable book:
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html

View file

@ -1,13 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.
An invalid syntax was passed to the second argument of an `llvm_asm` macro line.
Erroneous code example:
```compile_fail,E0661
```ignore (no longer emitted)
let a;
llvm_asm!("nop" : "r"(a));
```
Considering that this would be a long explanation, we instead recommend you
take a look at the [`llvm_asm`] chapter of the Unstable book:
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html

View file

@ -1,16 +1,13 @@
#### Note: this error code is no longer emitted by the compiler.
An invalid input operand constraint was passed to the `llvm_asm` macro
(third line).
Erroneous code example:
```compile_fail,E0662
```ignore (no longer emitted)
llvm_asm!("xor %eax, %eax"
:
: "=test"("a")
);
```
Considering that this would be a long explanation, we instead recommend you
take a look at the [`llvm_asm`] chapter of the Unstable book:
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html

View file

@ -1,16 +1,13 @@
#### Note: this error code is no longer emitted by the compiler.
An invalid input operand constraint was passed to the `llvm_asm` macro
(third line).
Erroneous code example:
```compile_fail,E0663
```ignore (no longer emitted)
llvm_asm!("xor %eax, %eax"
:
: "+test"("a")
);
```
Considering that this would be a long explanation, we instead recommend you
take a look at the [`llvm_asm`] chapter of the Unstable book:
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html

View file

@ -1,16 +1,13 @@
#### Note: this error code is no longer emitted by the compiler.
A clobber was surrounded by braces in the `llvm_asm` macro.
Erroneous code example:
```compile_fail,E0664
```ignore (no longer emitted)
llvm_asm!("mov $$0x200, %eax"
:
:
: "{eax}"
);
```
Considering that this would be a long explanation, we instead recommend you
take a look at the [`llvm_asm`] chapter of the Unstable book:
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html

View file

@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.
Malformed inline assembly rejected by LLVM.
Erroneous code example:
```compile_fail,E0668
```ignore (no longer emitted)
#![feature(llvm_asm)]
fn main() {

View file

@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.
Cannot convert inline assembly operand to a single LLVM value.
Erroneous code example:
```compile_fail,E0669
```ignore (no longer emitted)
#![feature(llvm_asm)]
fn main() {

View file

@ -30,7 +30,6 @@ macro_rules! arena_types {
[] impl_item_ref: rustc_hir::ImplItemRef,
[] item: rustc_hir::Item<'tcx>,
[] inline_asm: rustc_hir::InlineAsm<'tcx>,
[] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
[] local: rustc_hir::Local<'tcx>,
[] mod_: rustc_hir::Mod<'tcx>,
[] owner_info: rustc_hir::OwnerInfo<'tcx>,

View file

@ -5,8 +5,8 @@ use crate::intravisit::FnKind;
use crate::LangItem;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObjectSyntax, UintTy};
use rustc_ast::{self as ast, CrateSugar};
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@ -1474,7 +1474,6 @@ impl Expr<'_> {
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Yield(..) => ExprPrecedence::Yield,
@ -1534,7 +1533,6 @@ impl Expr<'_> {
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
| ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::Lit(_)
| ExprKind::ConstBlock(..)
@ -1617,7 +1615,6 @@ impl Expr<'_> {
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
| ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::ConstBlock(..)
| ExprKind::Box(..)
@ -1758,8 +1755,6 @@ pub enum ExprKind<'hir> {
/// Inline assembly (from `asm!`), with its outputs and inputs.
InlineAsm(&'hir InlineAsm<'hir>),
/// Inline assembly (from `llvm_asm!`), with its outputs and inputs.
LlvmInlineAsm(&'hir LlvmInlineAsm<'hir>),
/// A struct or struct-like variant literal expression.
///
@ -2371,36 +2366,6 @@ pub struct InlineAsm<'hir> {
pub line_spans: &'hir [Span],
}
#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
pub struct LlvmInlineAsmOutput {
pub constraint: Symbol,
pub is_rw: bool,
pub is_indirect: bool,
pub span: Span,
}
// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
// it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
// arena-allocated slice.
#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
pub struct LlvmInlineAsmInner {
pub asm: Symbol,
pub asm_str_style: StrStyle,
pub outputs: Vec<LlvmInlineAsmOutput>,
pub inputs: Vec<Symbol>,
pub clobbers: Vec<Symbol>,
pub volatile: bool,
pub alignstack: bool,
pub dialect: LlvmAsmDialect,
}
#[derive(Debug, HashStable_Generic)]
pub struct LlvmInlineAsm<'hir> {
pub inner: LlvmInlineAsmInner,
pub outputs_exprs: &'hir [Expr<'hir>],
pub inputs_exprs: &'hir [Expr<'hir>],
}
/// Represents a parameter in a function header.
#[derive(Debug, HashStable_Generic)]
pub struct Param<'hir> {

View file

@ -1252,10 +1252,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::InlineAsm(ref asm) => {
walk_inline_asm(visitor, asm);
}
ExprKind::LlvmInlineAsm(ref asm) => {
walk_list!(visitor, visit_expr, asm.outputs_exprs);
walk_list!(visitor, visit_expr, asm.inputs_exprs);
}
ExprKind::Yield(ref subexpression, _) => {
visitor.visit_expr(subexpression);
}

View file

@ -1581,67 +1581,6 @@ impl<'a> State<'a> {
self.word("asm!");
self.print_inline_asm(asm);
}
hir::ExprKind::LlvmInlineAsm(ref a) => {
let i = &a.inner;
self.word("llvm_asm!");
self.popen();
self.print_symbol(i.asm, i.asm_str_style);
self.word_space(":");
let mut out_idx = 0;
self.commasep(Inconsistent, &i.outputs, |s, out| {
let constraint = out.constraint.as_str();
let mut ch = constraint.chars();
match ch.next() {
Some('=') if out.is_rw => {
s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
}
_ => s.print_string(&constraint, ast::StrStyle::Cooked),
}
s.popen();
s.print_expr(&a.outputs_exprs[out_idx]);
s.pclose();
out_idx += 1;
});
self.space();
self.word_space(":");
let mut in_idx = 0;
self.commasep(Inconsistent, &i.inputs, |s, &co| {
s.print_symbol(co, ast::StrStyle::Cooked);
s.popen();
s.print_expr(&a.inputs_exprs[in_idx]);
s.pclose();
in_idx += 1;
});
self.space();
self.word_space(":");
self.commasep(Inconsistent, &i.clobbers, |s, &co| {
s.print_symbol(co, ast::StrStyle::Cooked);
});
let mut options = vec![];
if i.volatile {
options.push("volatile");
}
if i.alignstack {
options.push("alignstack");
}
if i.dialect == ast::LlvmAsmDialect::Intel {
options.push("intel");
}
if !options.is_empty() {
self.space();
self.word_space(":");
self.commasep(Inconsistent, &options, |s, &co| {
s.print_string(co, ast::StrStyle::Cooked);
});
}
self.pclose();
}
hir::ExprKind::Yield(ref expr, _) => {
self.word_space("yield");
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);

View file

@ -1566,10 +1566,6 @@ pub enum StatementKind<'tcx> {
/// End the current live range for the storage of the local.
StorageDead(Local),
/// Executes a piece of inline Assembly. Stored in a Box to keep the size
/// of `StatementKind` low.
LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>),
/// Retag references in the given place, ensuring they got fresh tags. This is
/// part of the Stacked Borrows model. These statements are currently only interpreted
/// by miri and only generated when "-Z mir-emit-retag" is passed.
@ -1689,13 +1685,6 @@ pub enum FakeReadCause {
ForIndex,
}
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
pub struct LlvmInlineAsm<'tcx> {
pub asm: hir::LlvmInlineAsmInner,
pub outputs: Box<[Place<'tcx>]>,
pub inputs: Box<[(Span, Operand<'tcx>)]>,
}
impl Debug for Statement<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::StatementKind::*;
@ -1720,9 +1709,6 @@ impl Debug for Statement<'_> {
SetDiscriminant { ref place, variant_index } => {
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
}
LlvmInlineAsm(ref asm) => {
write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
}
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}

View file

@ -245,7 +245,6 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
SetDiscriminant { .. } => "SetDiscriminant",
StorageLive(..) => "StorageLive",
StorageDead(..) => "StorageDead",
LlvmInlineAsm(..) => "LlvmInlineAsm",
Retag(..) => "Retag",
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",

View file

@ -408,19 +408,6 @@ macro_rules! make_mir_visitor {
location
);
}
StatementKind::LlvmInlineAsm(asm) => {
for output in & $($mutability)? asm.outputs[..] {
self.visit_place(
output,
PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
location
);
}
for (span, input) in & $($mutability)? asm.inputs[..] {
self.visit_span(span);
self.visit_operand(input, location);
}
}
StatementKind::Retag(kind, place) => {
self.visit_retag(kind, place, location);
}
@ -1178,10 +1165,6 @@ pub enum NonMutatingUseContext {
pub enum MutatingUseContext {
/// Appears as LHS of an assignment.
Store,
/// Can often be treated as a `Store`, but needs to be separate because
/// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
/// cannot be simplified the way a `Store`-`Store` can be.
LlvmAsmOutput,
/// Output operand of an inline assembly block.
AsmOutput,
/// Destination of a call.
@ -1271,7 +1254,6 @@ impl PlaceContext {
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
| MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput,
)
)

View file

@ -431,12 +431,6 @@ pub enum ExprKind<'tcx> {
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
/// Inline LLVM assembly, i.e. `llvm_asm!()`.
LlvmInlineAsm {
asm: &'tcx hir::LlvmInlineAsmInner,
outputs: Box<[ExprId]>,
inputs: Box<[ExprId]>,
},
/// A `yield` expression.
Yield {
value: ExprId,

View file

@ -145,14 +145,6 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
}
}
ThreadLocalRef(_) => {}
LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
for &out_expr in &**outputs {
visitor.visit_expr(&visitor.thir()[out_expr]);
}
for &in_expr in &**inputs {
visitor.visit_expr(&visitor.thir()[in_expr]);
}
}
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
}
}

View file

@ -219,7 +219,6 @@ TrivialTypeFoldableAndLiftImpls! {
::rustc_hir::def_id::DefId,
::rustc_hir::def_id::LocalDefId,
::rustc_hir::HirId,
::rustc_hir::LlvmInlineAsmInner,
::rustc_hir::MatchSource,
::rustc_hir::Mutability,
::rustc_hir::Unsafety,

View file

@ -569,7 +569,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {

View file

@ -350,7 +350,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
// these do not have corresponding `Rvalue` variants,

View file

@ -67,8 +67,7 @@ impl Category {
| ExprKind::Repeat { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
| ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
Some(Category::Constant)

View file

@ -477,9 +477,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// These cases don't actually need a destination
ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::LlvmInlineAsm { .. } => {
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
unpack!(block = this.stmt_expr(block, expr, None));
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
block.unit()

View file

@ -101,38 +101,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
BreakableTarget::Return,
source_info,
),
ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
this.block_context.push(BlockFrame::SubExpr);
let outputs = outputs
.into_iter()
.copied()
.map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
.collect::<Vec<_>>()
.into_boxed_slice();
let inputs = inputs
.into_iter()
.copied()
.map(|input| {
let input = &this.thir[input];
(input.span, unpack!(block = this.as_local_operand(block, &input)))
})
.collect::<Vec<_>>()
.into_boxed_slice();
this.cfg.push(
block,
Statement {
source_info,
kind: StatementKind::LlvmInlineAsm(Box::new(LlvmInlineAsm {
asm: asm.clone(),
outputs,
inputs,
})),
},
);
this.block_context.pop();
block.unit()
}
_ => {
assert!(
statement_scope.is_some(),

View file

@ -329,7 +329,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::LogicalOp { .. }
| ExprKind::Use { .. } => {
// We don't need to save the old value and restore it
@ -377,7 +376,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
self.requires_unsafe(expr.span, DerefOfRawPointer);
}
}
ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
ExprKind::InlineAsm { .. } => {
self.requires_unsafe(expr.span, UseOfInlineAssembly);
}
ExprKind::Adt(box Adt {

View file

@ -570,12 +570,6 @@ impl<'tcx> Cx<'tcx> {
line_spans: asm.line_spans,
},
hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
asm: &asm.inner,
outputs: self.mirror_exprs(asm.outputs_exprs),
inputs: self.mirror_exprs(asm.inputs_exprs),
},
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);

View file

@ -176,7 +176,6 @@ impl DefUse {
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
| MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,

View file

@ -134,11 +134,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
| StatementKind::SetDiscriminant { box place, .. } => {
trans.gen(place.local);
}
StatementKind::LlvmInlineAsm(asm) => {
for place in &*asm.outputs {
trans.gen(place.local);
}
}
// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.

View file

@ -4,7 +4,6 @@ use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
use std::iter;
use std::mem;
use super::abs_domain::Lift;
@ -293,16 +292,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::FakeRead(box (_, place)) => {
self.create_move_path(*place);
}
StatementKind::LlvmInlineAsm(ref asm) => {
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
if !kind.is_indirect {
self.gather_init(output.as_ref(), InitKind::Deep);
}
}
for (_, input) in asm.inputs.iter() {
self.gather_operand(input);
}
}
StatementKind::StorageLive(_) => {}
StatementKind::StorageDead(local) => {
self.gather_move(Place::from(*local));

View file

@ -104,10 +104,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
// safe (at least as emitted during MIR construction)
}
StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
UnsafetyViolationKind::General,
UnsafetyViolationDetails::UseOfInlineAssembly,
),
StatementKind::CopyNonOverlapping(..) => unreachable!(),
}
self.super_statement(statement, location);
@ -208,7 +204,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
MutatingUseContext::Store
| MutatingUseContext::Drop
| MutatingUseContext::AsmOutput
| MutatingUseContext::LlvmAsmOutput
)
);
// If this is just an assignment, determine if the assigned type needs dropping.

View file

@ -1032,8 +1032,7 @@ impl Visitor<'_> for CanConstProp {
// These could be propagated with a smarter analysis or just some careful thinking about
// whether they'd be fine right now.
MutatingUse(MutatingUseContext::LlvmAsmOutput)
| MutatingUse(MutatingUseContext::Yield)
MutatingUse(MutatingUseContext::Yield)
| MutatingUse(MutatingUseContext::Drop)
| MutatingUse(MutatingUseContext::Retag)
// These can't ever be propagated under any scheme, as we can't reason about indirect

View file

@ -835,7 +835,6 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Assign(_)
| StatementKind::SetDiscriminant { .. }
| StatementKind::LlvmInlineAsm(_)
| StatementKind::Retag(_, _)
| StatementKind::AscribeUserType(_, _) => {
Some(statement.source_info.span)

View file

@ -534,25 +534,6 @@ impl<'a> Conflicts<'a> {
// eliminate the resulting self-assignments automatically.
StatementKind::Assign(_) => {}
StatementKind::LlvmInlineAsm(asm) => {
// Inputs and outputs must not overlap.
for (_, input) in &*asm.inputs {
if let Some(in_place) = input.place() {
if !in_place.is_indirect() {
for out_place in &*asm.outputs {
if !out_place.is_indirect() && !in_place.is_indirect() {
self.record_local_conflict(
in_place.local,
out_place.local,
"aliasing llvm_asm! operands",
);
}
}
}
}
}
}
StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)

View file

@ -1449,9 +1449,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
}
// FIXME: Does `llvm_asm!` have any aliasing requirements?
StatementKind::LlvmInlineAsm(_) => {}
StatementKind::FakeRead(..)
| StatementKind::SetDiscriminant { .. }
| StatementKind::StorageLive(_)

View file

@ -50,7 +50,6 @@ impl RemoveNoopLandingPads {
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
| StatementKind::LlvmInlineAsm { .. }
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag { .. } => {
return false;

View file

@ -239,10 +239,6 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
}
}
// If inline assembly is found, we probably should
// not try to analyze the code
StatementKind::LlvmInlineAsm(_) => return false,
// These statements have no influence on the place
// we are interested in
StatementKind::FakeRead(_)
@ -320,10 +316,6 @@ fn find_determining_place<'tcx>(
| StatementKind::CopyNonOverlapping(_)
| StatementKind::Nop => {}
// If inline assembly is found, we probably should
// not try to analyze the code
StatementKind::LlvmInlineAsm(_) => return None,
// If the discriminant is set, it is always set
// as a constant, so the job is already done.
// As we are **ignoring projections**, if the place

View file

@ -483,8 +483,7 @@ impl UsedLocals {
impl<'tcx> Visitor<'tcx> for UsedLocals {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
StatementKind::LlvmInlineAsm(..)
| StatementKind::CopyNonOverlapping(..)
StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag(..)
| StatementKind::Coverage(..)
| StatementKind::FakeRead(..)

View file

@ -631,10 +631,6 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
.filter(|(_, bb)| {
// Reaching `unreachable` is UB so assume it doesn't happen.
bb.terminator().kind != TerminatorKind::Unreachable
// But `asm!(...)` could abort the program,
// so we cannot assume that the `unreachable` terminator itself is reachable.
// FIXME(Centril): use a normalization pass instead of a check.
|| bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..)))
})
.peekable();

View file

@ -23,23 +23,14 @@ impl MirPass<'_> for UnreachablePropagation {
for (bb, bb_data) in traversal::postorder(body) {
let terminator = bb_data.terminator();
// HACK: If the block contains any asm statement it is not regarded as unreachable.
// This is a temporary solution that handles possibly diverging asm statements.
// Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
let asm_stmt_in_block = || {
bb_data.statements.iter().any(|stmt: &Statement<'_>| {
matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
})
};
if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
if terminator.kind == TerminatorKind::Unreachable {
unreachable_blocks.insert(bb);
} else {
let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
if let Some(terminator_kind) = terminator_kind_opt {
if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
if terminator_kind == TerminatorKind::Unreachable {
unreachable_blocks.insert(bb);
}
replacements.insert(bb, terminator_kind);

View file

@ -103,7 +103,6 @@ use rustc_span::Span;
use std::collections::VecDeque;
use std::io;
use std::io::prelude::*;
use std::iter;
use std::rc::Rc;
mod rwu_table;
@ -470,7 +469,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
| hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::Type(..)
| hir::ExprKind::Err
@ -1091,26 +1089,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
succ
}
hir::ExprKind::LlvmInlineAsm(ref asm) => {
let ia = &asm.inner;
let outputs = asm.outputs_exprs;
let inputs = asm.inputs_exprs;
let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| {
// see comment on places
// in propagate_through_place_components()
if o.is_indirect {
self.propagate_through_expr(output, succ)
} else {
let acc = if o.is_rw { ACC_WRITE | ACC_READ } else { ACC_WRITE };
let succ = self.write_place(output, succ, acc);
self.propagate_through_place_components(output, succ)
}
});
// Inputs are executed first. Propagate last because of rev order
self.propagate_through_exprs(inputs, succ)
}
hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err
@ -1387,20 +1365,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
}
}
hir::ExprKind::LlvmInlineAsm(ref asm) => {
for input in asm.inputs_exprs {
this.visit_expr(input);
}
// Output operands must be places
for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) {
if !o.is_indirect {
this.check_place(output);
}
this.visit_expr(output);
}
}
hir::ExprKind::Let(let_expr) => {
this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
}

View file

@ -236,22 +236,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
self.check_inline_asm(expr.hir_id, asm, span);
}
ExprKind::LlvmInlineAsm(..) => {
self.items.push((ItemKind::Asm, span));
self.tcx.struct_span_lint_hir(
UNSUPPORTED_NAKED_FUNCTIONS,
expr.hir_id,
span,
|lint| {
lint.build(
"the LLVM-style inline assembly is unsupported in naked functions",
)
.help("use the new asm! syntax specified in RFC 2873")
.emit();
},
);
}
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
hir::intravisit::walk_expr(self, expr);
}

View file

@ -808,7 +808,6 @@ symbols! {
linkage,
lint_reasons,
literal,
llvm_asm,
load,
loaded_from_disk,
local,

View file

@ -479,7 +479,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
// let expressions imply control flow
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
self.error(node.span, "control flow is not supported in generic constants")?,
ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
ExprKind::InlineAsm { .. } => {
self.error(node.span, "assembly is not supported in generic constants")?
}

View file

@ -282,12 +282,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
ExprKind::LlvmInlineAsm(asm) => {
for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
self.check_expr(expr);
}
tcx.mk_unit()
}
ExprKind::Break(destination, ref expr_opt) => {
self.check_expr_break(destination, expr_opt.as_deref(), expr)
}

View file

@ -17,7 +17,6 @@ use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
use std::iter;
use crate::mem_categorization as mc;
@ -360,17 +359,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
hir::ExprKind::LlvmInlineAsm(ia) => {
for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) {
if o.is_indirect {
self.consume_expr(output);
} else {
self.mutate_expr(output);
}
}
self.consume_exprs(ia.inputs_exprs);
}
hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)

View file

@ -378,7 +378,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
| hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
}

View file

@ -180,7 +180,6 @@
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(llvm_asm)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
#![feature(must_not_suspend)]

View file

@ -1397,32 +1397,6 @@ pub(crate) mod builtin {
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
}
/// LLVM-style inline assembly.
///
/// Read the [unstable book] for the usage.
///
/// [unstable book]: ../unstable-book/library-features/llvm-asm.html
#[unstable(
feature = "llvm_asm",
issue = "70173",
reason = "prefer using the new asm! syntax instead"
)]
#[rustc_deprecated(
since = "1.56",
reason = "will be removed from the compiler, use asm! instead"
)]
#[rustc_builtin_macro]
#[macro_export]
macro_rules! llvm_asm {
("assembly template"
: $("output"(operand),)*
: $("input"(operand),)*
: $("clobbers",)*
: $("options",)*) => {
/* compiler built-in */
};
}
/// Prints passed tokens into the standard output.
#[unstable(
feature = "log_syntax",

View file

@ -56,8 +56,8 @@ pub use crate::hash::macros::Hash;
#[doc(no_inline)]
pub use crate::{
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
option_env, stringify, trace_macros,
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
stringify, trace_macros,
};
#[unstable(

View file

@ -294,7 +294,6 @@
#![feature(intra_doc_pointers)]
#![feature(lang_items)]
#![feature(linkage)]
#![feature(llvm_asm)]
#![feature(log_syntax)]
#![feature(map_try_insert)]
#![feature(maybe_uninit_slice)]
@ -571,8 +570,8 @@ pub use core::{
#[allow(deprecated)]
pub use core::{
assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm,
log_syntax, module_path, option_env, stringify, trace_macros,
env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
module_path, option_env, stringify, trace_macros,
};
#[unstable(

View file

@ -40,9 +40,8 @@ pub use crate::result::Result::{self, Err, Ok};
#[doc(no_inline)]
pub use core::prelude::v1::{
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
PartialOrd,
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
};
#[unstable(

View file

@ -1,190 +0,0 @@
# `llvm_asm`
The tracking issue for this feature is: [#70173]
[#70173]: https://github.com/rust-lang/rust/issues/70173
------------------------
For extremely low-level manipulations and performance reasons, one
might wish to control the CPU directly. Rust supports using inline
assembly to do this via the `llvm_asm!` macro.
```rust,ignore (pseudo-code)
llvm_asm!(assembly template
: output operands
: input operands
: clobbers
: options
);
```
Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the
crate to allow) and of course requires an `unsafe` block.
> **Note**: the examples here are given in x86/x86-64 assembly, but
> all platforms are supported.
## Assembly template
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
```rust
#![feature(llvm_asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn foo() {
unsafe {
llvm_asm!("NOP");
}
}
// Other platforms:
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn foo() { /* ... */ }
fn main() {
// ...
foo();
// ...
}
```
(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
llvm_asm!("xor %eax, %eax"
:
:
: "eax"
);
# } }
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn main() {}
```
Whitespace also doesn't matter:
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
llvm_asm!("xor %eax, %eax" ::: "eax");
# } }
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn main() {}
```
## Operands
Input and output operands follow the same format: `:
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable place, or not yet assigned:
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
let c: i32;
unsafe {
llvm_asm!("add $2, $0"
: "=r"(c)
: "0"(a), "r"(b)
);
}
c
}
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
assert_eq!(add(3, 14159), 14162)
}
```
If you would like to use real operands in this position, however,
you are required to put curly braces `{}` around the register that
you want, and you are required to put the specific size of the
operand. This is useful for very low level programming, where
which register you use is important:
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# unsafe fn read_byte_in(port: u16) -> u8 {
let result: u8;
llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
result
# }
```
## Clobbers
Some instructions modify registers which might otherwise have held
different values so we use the clobbers list to indicate to the
compiler not to assume any values loaded into those registers will
stay valid.
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
// Put the value 0x200 in eax:
llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
# } }
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn main() {}
```
Input and output registers need not be listed since that information
is already communicated by the given constraints. Otherwise, any other
registers used either implicitly or explicitly should be listed.
If the assembly changes the condition code register `cc` should be
specified as one of the clobbers. Similarly, if the assembly modifies
memory, `memory` should also be specified.
## Options
The last section, `options` is specific to Rust. The format is comma
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
specify some extra info about the inline assembly:
Current valid options are:
1. `volatile` - specifying this is analogous to
`__asm__ __volatile__ (...)` in gcc/clang.
2. `alignstack` - certain instructions expect the stack to be
aligned a certain way (i.e. SSE) and specifying this indicates to
the compiler to insert its usual stack alignment code
3. `intel` - use intel syntax instead of the default AT&T.
```rust
# #![feature(llvm_asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() {
let result: i32;
unsafe {
llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
}
println!("eax is currently {}", result);
# }
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn main() {}
```
## More Information
The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's
inline assembler expressions][llvm-docs], so be sure to check out [their
documentation as well][llvm-docs] for more information about clobbers,
constraints, etc.
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions

View file

@ -1,14 +0,0 @@
// compile-flags: -O
#![feature(llvm_asm)]
#![crate_type = "lib"]
// Check that inline assembly expressions without any outputs
// are marked as having side effects / being volatile
// CHECK-LABEL: @assembly
#[no_mangle]
pub fn assembly() {
unsafe { llvm_asm!("") }
// CHECK: tail call void asm sideeffect "", {{.*}}
}

View file

@ -18,23 +18,19 @@
#![allow(warnings)]
#![feature(rustc_attrs)]
#![feature(llvm_asm)]
#![crate_type="rlib"]
use std::arch::asm;
// Change template
#[cfg(any(cfail1,cfail4))]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn change_template(a: i32) -> i32 {
pub fn change_template(_a: i32) -> i32 {
let c: i32;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(c)
: "0"(a)
:
:
);
asm!("mov {0}, 1",
out(reg) c
);
}
c
}
@ -45,15 +41,12 @@ pub fn change_template(a: i32) -> i32 {
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
#[rustc_clean(cfg="cfail6")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn change_template(a: i32) -> i32 {
pub fn change_template(_a: i32) -> i32 {
let c: i32;
unsafe {
llvm_asm!("add 2, $0"
: "=r"(c)
: "0"(a)
:
:
);
asm!("mov {0}, 2",
out(reg) c
);
}
c
}
@ -67,12 +60,10 @@ pub fn change_output(a: i32) -> i32 {
let mut _out1: i32 = 0;
let mut _out2: i32 = 0;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out1)
: "0"(a)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out1,
in(reg) a
);
}
_out1
}
@ -87,12 +78,10 @@ pub fn change_output(a: i32) -> i32 {
let mut _out1: i32 = 0;
let mut _out2: i32 = 0;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out2)
: "0"(a)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out2,
in(reg) a
);
}
_out1
}
@ -105,12 +94,10 @@ pub fn change_output(a: i32) -> i32 {
pub fn change_input(_a: i32, _b: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a
);
}
_out
}
@ -124,12 +111,10 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
pub fn change_input(_a: i32, _b: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_b)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _b
);
}
_out
}
@ -142,12 +127,10 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a), "r"(_b)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
in("eax") _b);
}
_out
}
@ -161,30 +144,26 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "r"(_a), "0"(_b)
:
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
in("ecx") _b);
}
_out
}
// Change clobber
#[cfg(any(cfail1,cfail4))]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn change_clobber(_a: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a)
:/*--*/
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
lateout("ecx") _
);
}
_out
}
@ -198,12 +177,11 @@ pub fn change_clobber(_a: i32) -> i32 {
pub fn change_clobber(_a: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a)
: "eax"
:
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
lateout("edx") _
);
}
_out
}
@ -216,12 +194,11 @@ pub fn change_clobber(_a: i32) -> i32 {
pub fn change_options(_a: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a)
:
:/*-------*/
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
options(readonly),
);
}
_out
}
@ -235,12 +212,11 @@ pub fn change_options(_a: i32) -> i32 {
pub fn change_options(_a: i32) -> i32 {
let _out;
unsafe {
llvm_asm!("add 1, $0"
: "=r"(_out)
: "0"(_a)
:
: "volatile"
);
asm!("mov {0}, {1}",
out(reg) _out,
in(reg) _a,
options(nomem ),
);
}
_out
}

View file

@ -1,75 +0,0 @@
- // MIR for `main` before UnreachablePropagation
+ // MIR for `main` after UnreachablePropagation
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/unreachable_asm.rs:10:11: 10:11
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
let _3: Empty; // in scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
let _5: (); // in scope 0 at $DIR/unreachable_asm.rs:14:9: 18:10
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm.rs:14:12: 14:16
let _7: (); // in scope 0 at $DIR/unreachable_asm.rs:21:9: 21:37
let mut _8: !; // in scope 0 at $DIR/unreachable_asm.rs:22:9: 22:21
scope 1 {
debug _x => _3; // in scope 1 at $DIR/unreachable_asm.rs:11:17: 11:19
}
scope 2 {
debug _y => _4; // in scope 2 at $DIR/unreachable_asm.rs:12:13: 12:19
scope 3 {
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
_1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
// mir::Constant
// + span: $DIR/unreachable_asm.rs:11:23: 11:28
// + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
}
bb1: {
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
}
bb2: {
StorageLive(_3); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
StorageLive(_4); // scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
StorageLive(_5); // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
StorageLive(_6); // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
_6 = const true; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
}
bb3: {
_4 = const 21_i32; // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
_5 = const (); // scope 2 at $DIR/unreachable_asm.rs:14:17: 16:10
goto -> bb5; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
}
bb4: {
_4 = const 42_i32; // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
_5 = const (); // scope 2 at $DIR/unreachable_asm.rs:16:16: 18:10
goto -> bb5; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
}
bb5: {
StorageDead(_6); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
StorageDead(_5); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
StorageLive(_7); // scope 2 at $DIR/unreachable_asm.rs:21:9: 21:37
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:34
_7 = const (); // scope 3 at $DIR/unreachable_asm.rs:21:9: 21:37
StorageDead(_7); // scope 2 at $DIR/unreachable_asm.rs:21:36: 21:37
StorageLive(_8); // scope 2 at $DIR/unreachable_asm.rs:22:9: 22:21
unreachable; // scope 2 at $DIR/unreachable_asm.rs:22:15: 22:17
}
bb6: {
_0 = const (); // scope 0 at $DIR/unreachable_asm.rs:23:6: 23:6
StorageDead(_1); // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2
return; // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2
}
}

View file

@ -1,24 +0,0 @@
#![feature(llvm_asm)]
enum Empty {}
fn empty() -> Option<Empty> {
None
}
// EMIT_MIR unreachable_asm.main.UnreachablePropagation.diff
fn main() {
if let Some(_x) = empty() {
let mut _y;
if true {
_y = 21;
} else {
_y = 42;
}
// asm instruction stops unreachable propagation to if else blocks bb4 and bb5.
unsafe { llvm_asm!("NOP"); }
match _x { }
}
}

View file

@ -1,85 +0,0 @@
- // MIR for `main` before UnreachablePropagation
+ // MIR for `main` after UnreachablePropagation
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/unreachable_asm_2.rs:10:11: 10:11
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
let _3: Empty; // in scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
let _5: (); // in scope 0 at $DIR/unreachable_asm_2.rs:14:9: 22:10
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm_2.rs:14:12: 14:16
let _7: (); // in scope 0 at $DIR/unreachable_asm_2.rs:16:13: 16:41
let _8: (); // in scope 0 at $DIR/unreachable_asm_2.rs:20:13: 20:41
let mut _9: !; // in scope 0 at $DIR/unreachable_asm_2.rs:24:9: 24:21
scope 1 {
debug _x => _3; // in scope 1 at $DIR/unreachable_asm_2.rs:11:17: 11:19
}
scope 2 {
debug _y => _4; // in scope 2 at $DIR/unreachable_asm_2.rs:12:13: 12:19
scope 3 {
}
scope 4 {
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
_1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
// mir::Constant
// + span: $DIR/unreachable_asm_2.rs:11:23: 11:28
// + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
}
bb1: {
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
- switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
+ switchInt(move _2) -> [1_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
}
bb2: {
StorageLive(_3); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
StorageLive(_4); // scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
StorageLive(_5); // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
StorageLive(_6); // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
_6 = const true; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
}
bb3: {
StorageLive(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:13: 16:41
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:38
_7 = const (); // scope 3 at $DIR/unreachable_asm_2.rs:16:13: 16:41
StorageDead(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41
_4 = const 21_i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
_5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:14:17: 18:10
- goto -> bb5; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
+ unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
}
bb4: {
StorageLive(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:13: 20:41
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:38
_8 = const (); // scope 4 at $DIR/unreachable_asm_2.rs:20:13: 20:41
StorageDead(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41
_4 = const 42_i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
_5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:18:16: 22:10
- goto -> bb5; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
+ unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
}
bb5: {
- StorageDead(_6); // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
- StorageDead(_5); // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
- StorageLive(_9); // scope 2 at $DIR/unreachable_asm_2.rs:24:9: 24:21
- unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:24:15: 24:17
- }
-
- bb6: {
_0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:25:6: 25:6
StorageDead(_1); // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2
return; // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2
}
}

View file

@ -1,26 +0,0 @@
#![feature(llvm_asm)]
enum Empty {}
fn empty() -> Option<Empty> {
None
}
// EMIT_MIR unreachable_asm_2.main.UnreachablePropagation.diff
fn main() {
if let Some(_x) = empty() {
let mut _y;
if true {
// asm instruction stops unreachable propagation to block bb3.
unsafe { llvm_asm!("NOP"); }
_y = 21;
} else {
// asm instruction stops unreachable propagation to block bb3.
unsafe { llvm_asm!("NOP"); }
_y = 42;
}
match _x { }
}
}

View file

@ -1,3 +0,0 @@
#![feature(llvm_asm)]
pub fn main() { unsafe { llvm_asm!("" : : : "hello", "world") }; }

View file

@ -1,11 +0,0 @@
#![feature(llvm_asm)]
// pp-exact
pub fn main() {
unsafe {
llvm_asm!("" : : : : "volatile");
llvm_asm!("" : : : : "alignstack");
llvm_asm!("" : : : : "intel");
}
}

View file

@ -1,8 +1,8 @@
// pp-exact
#![feature(llvm_asm)]
#[cfg(foo = r#"just parse this"#)]
extern crate blah as blah;
fn main() { unsafe { llvm_asm!(r###"blah"###); } }
use std::arch::asm;
fn main() { unsafe { asm!(r###"blah"###); } }

View file

@ -1,12 +1,11 @@
#![feature(llvm_asm)]
#![crate_type="lib"]
use std::arch::asm;
#[deny(unreachable_code)]
pub fn exit(n: usize) -> i32 {
unsafe {
// Pretend this asm is an exit() syscall.
llvm_asm!("" :: "r"(n) :: "volatile");
// Can't actually reach this point, but rustc doesn't know that.
asm!("/*{0}*/", in(reg) n);
}
// This return value is just here to generate some extra code for a return
// value, making it easier for the test script to detect whether the

View file

@ -1,5 +1,6 @@
#![feature(llvm_asm, core_intrinsics)]
#![feature(core_intrinsics)]
#![crate_type="lib"]
use std::arch::asm;
use std::intrinsics;
@ -7,7 +8,7 @@ use std::intrinsics;
pub fn exit(n: usize) -> i32 {
unsafe {
// Pretend this asm is an exit() syscall.
llvm_asm!("" :: "r"(n) :: "volatile");
asm!("/*{0}*/", in(reg) n);
intrinsics::unreachable()
}
// This return value is just here to generate some extra code for a return

View file

@ -5,9 +5,7 @@
// ignore-android
// ignore-arm
// ignore-aarch64
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
#![feature(asm_sym)]
#[cfg(target_arch = "x86_64")]
pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
@ -54,37 +52,37 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct
#[cfg(target_arch = "x86_64")]
pub fn main() {
use std::arch::asm;
let result: i64;
unsafe {
llvm_asm!("mov rdi, 1;
mov rsi, 2;
mov rdx, 3;
mov rcx, 4;
mov r8, 5;
mov r9, 6;
mov eax, 0x3F800000;
movd xmm0, eax;
mov eax, 0x40000000;
movd xmm1, eax;
mov eax, 0x40800000;
movd xmm2, eax;
mov eax, 0x41000000;
movd xmm3, eax;
mov eax, 0x41800000;
movd xmm4, eax;
mov eax, 0x42000000;
movd xmm5, eax;
mov eax, 0x42800000;
movd xmm6, eax;
mov eax, 0x43000000;
movd xmm7, eax;
call r10
"
: "={rax}"(result)
: "{r10}"(all_the_registers as usize)
: "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory"
: "intel", "alignstack"
)
asm!("mov rdi, 1",
"mov rsi, 2",
"mov rdx, 3",
"mov rcx, 4",
"mov r8, 5",
"mov r9, 6",
"mov eax, 0x3F800000",
"movd xmm0, eax",
"mov eax, 0x40000000",
"movd xmm1, eax",
"mov eax, 0x40800000",
"movd xmm2, eax",
"mov eax, 0x41000000",
"movd xmm3, eax",
"mov eax, 0x41800000",
"movd xmm4, eax",
"mov eax, 0x42000000",
"movd xmm5, eax",
"mov eax, 0x42800000",
"movd xmm6, eax",
"mov eax, 0x43000000",
"movd xmm7, eax",
"call {0}",
sym all_the_registers,
out("rax") result,
clobber_abi("sysv64"),
);
}
assert_eq!(result, 42);

View file

@ -3,12 +3,10 @@
// ignore-spirv
// ignore-wasm32
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
#![feature(asm_const, asm_sym)]
#![crate_type = "lib"]
#![allow(deprecated)] // llvm_asm!
use std::arch::asm;
@ -114,16 +112,6 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
inner
}
#[naked]
unsafe extern "C" fn llvm() -> ! {
//~^ WARN naked functions must contain a single asm block
//~| WARN this was previously accepted
llvm_asm!("");
//~^ WARN LLVM-style inline assembly is unsupported in naked functions
//~| WARN this was previously accepted
core::hint::unreachable_unchecked();
}
#[naked]
unsafe extern "C" fn invalid_options() {
asm!("", options(nomem, preserves_flags, noreturn));

View file

@ -1,35 +1,35 @@
error: asm with the `pure` option must have at least one output
--> $DIR/naked-functions.rs:136:14
--> $DIR/naked-functions.rs:124:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:23:5
--> $DIR/naked-functions.rs:21:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:25:5
--> $DIR/naked-functions.rs:23:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:27:6
--> $DIR/naked-functions.rs:25:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:29:5
--> $DIR/naked-functions.rs:27:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:39:5
--> $DIR/naked-functions.rs:37:5
|
LL | a + 1
| ^
@ -37,7 +37,7 @@ LL | a + 1
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:36:1
--> $DIR/naked-functions.rs:34:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
@ -53,7 +53,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:45:31
--> $DIR/naked-functions.rs:43:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
@ -61,7 +61,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:45:23
--> $DIR/naked-functions.rs:43:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
@ -70,7 +70,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:52:1
--> $DIR/naked-functions.rs:50:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
@ -84,7 +84,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:72:10
--> $DIR/naked-functions.rs:70:10
|
LL | in(reg) a,
| ^^^^^^^^^
@ -102,7 +102,7 @@ LL | out(reg) e,
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:69:5
--> $DIR/naked-functions.rs:67:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
@ -117,7 +117,7 @@ LL | | );
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:59:1
--> $DIR/naked-functions.rs:57:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
@ -141,7 +141,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:85:1
--> $DIR/naked-functions.rs:83:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
@ -153,7 +153,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:94:5
--> $DIR/naked-functions.rs:92:5
|
LL | asm!("");
| ^^^^^^^^
@ -162,7 +162,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:97:5
--> $DIR/naked-functions.rs:95:5
|
LL | asm!("");
| ^^^^^^^^
@ -171,7 +171,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:100:5
--> $DIR/naked-functions.rs:98:5
|
LL | asm!("");
| ^^^^^^^^
@ -180,7 +180,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:91:1
--> $DIR/naked-functions.rs:89:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
@ -202,7 +202,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:111:11
--> $DIR/naked-functions.rs:109:11
|
LL | *&y
| ^
@ -210,7 +210,7 @@ LL | *&y
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:108:5
--> $DIR/naked-functions.rs:106:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
@ -224,35 +224,8 @@ LL | | }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
--> $DIR/naked-functions.rs:121:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
= help: use the new asm! syntax specified in RFC 2873
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:118:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
LL | |
LL | | llvm_asm!("");
... |
LL | | core::hint::unreachable_unchecked();
| | ------------------------------------ non-asm is unsupported in naked functions
LL | | }
| |_^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:129:5
--> $DIR/naked-functions.rs:117:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -261,7 +234,7 @@ LL | asm!("", options(nomem, preserves_flags, noreturn));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
--> $DIR/naked-functions.rs:136:5
--> $DIR/naked-functions.rs:124:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -270,7 +243,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:136:5
--> $DIR/naked-functions.rs:124:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -279,7 +252,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:145:15
--> $DIR/naked-functions.rs:133:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
@ -287,13 +260,13 @@ LL | pub unsafe fn default_abi() {
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:151:15
--> $DIR/naked-functions.rs:139:15
|
LL | pub unsafe fn rust_abi() {
| ^^^^^^^^
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:191:1
--> $DIR/naked-functions.rs:179:1
|
LL | #[inline]
| ^^^^^^^^^
@ -302,7 +275,7 @@ LL | #[inline]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:199:1
--> $DIR/naked-functions.rs:187:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
@ -311,7 +284,7 @@ LL | #[inline(always)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:207:1
--> $DIR/naked-functions.rs:195:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
@ -320,7 +293,7 @@ LL | #[inline(never)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:215:1
--> $DIR/naked-functions.rs:203:1
|
LL | #[inline]
| ^^^^^^^^^
@ -329,7 +302,7 @@ LL | #[inline]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:218:1
--> $DIR/naked-functions.rs:206:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
@ -338,7 +311,7 @@ LL | #[inline(always)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
--> $DIR/naked-functions.rs:221:1
--> $DIR/naked-functions.rs:209:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
@ -346,5 +319,5 @@ LL | #[inline(never)]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: aborting due to 8 previous errors; 25 warnings emitted
error: aborting due to 8 previous errors; 23 warnings emitted

View file

@ -8,9 +8,6 @@
// check-pass
// dont-check-compiler-stdout - don't check for any AST change.
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
enum V {
A(i32),
B { f: [i64; 3 + 4] }
@ -27,12 +24,6 @@ macro_rules! call_println {
}
fn main() {
#[cfg(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64"))]
unsafe { llvm_asm!(""::::); }
let x: (i32) = 35;
let y = x as i64<> + 5;

View file

@ -1,83 +0,0 @@
// ignore-s390x
// ignore-emscripten
// ignore-powerpc
// ignore-powerpc64
// ignore-powerpc64le
// ignore-riscv64
// ignore-sparc
// ignore-sparc64
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
#[cfg(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64",
target_arch = "mips",
target_arch = "mips64"))]
mod test_cases {
fn is_move() {
let y: &mut isize;
let x = &mut 0isize;
unsafe {
llvm_asm!("nop" : : "r"(x));
}
let z = x; //~ ERROR use of moved value: `x`
}
fn in_is_read() {
let mut x = 3;
let y = &mut x;
unsafe {
llvm_asm!("nop" : : "r"(x)); //~ ERROR cannot use
}
let z = y;
}
fn out_is_assign() {
let x = 3;
unsafe {
llvm_asm!("nop" : "=r"(x)); //~ ERROR cannot assign twice
}
let mut a = &mut 3;
let b = &*a;
unsafe {
llvm_asm!("nop" : "=r"(a)); // OK, Shallow write to `a`
}
let c = b;
let d = *a;
}
fn rw_is_assign() {
let x = 3;
unsafe {
llvm_asm!("nop" : "+r"(x)); //~ ERROR cannot assign twice
}
}
fn indirect_is_not_init() {
let x: i32;
unsafe {
llvm_asm!("nop" : "=*r"(x)); //~ ERROR use of possibly-uninitialized variable
}
}
fn rw_is_read() {
let mut x = &mut 3;
let y = &*x;
unsafe {
llvm_asm!("nop" : "+r"(x)); //~ ERROR cannot assign to `x` because it is borrowed
}
let z = y;
}
fn two_moves() {
let x = &mut 2;
unsafe {
llvm_asm!("nop" : : "r"(x), "r"(x) ); //~ ERROR use of moved value
}
}
}
fn main() {}

View file

@ -1,81 +0,0 @@
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:26:17
|
LL | let x = &mut 0isize;
| - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
LL | unsafe {
LL | llvm_asm!("nop" : : "r"(x));
| - value moved here
LL | }
LL | let z = x;
| ^ value used here after move
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/borrowck-asm.rs:33:37
|
LL | let y = &mut x;
| ------ borrow of `x` occurs here
LL | unsafe {
LL | llvm_asm!("nop" : : "r"(x));
| ^ use of borrowed `x`
LL | }
LL | let z = y;
| - borrow later used here
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/borrowck-asm.rs:41:36
|
LL | let x = 3;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
LL | unsafe {
LL | llvm_asm!("nop" : "=r"(x));
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `x`
--> $DIR/borrowck-asm.rs:55:36
|
LL | let x = 3;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
LL | unsafe {
LL | llvm_asm!("nop" : "+r"(x));
| ^ cannot assign twice to immutable variable
error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/borrowck-asm.rs:62:37
|
LL | llvm_asm!("nop" : "=*r"(x));
| ^ use of possibly-uninitialized `x`
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/borrowck-asm.rs:70:36
|
LL | let y = &*x;
| --- borrow of `x` occurs here
LL | unsafe {
LL | llvm_asm!("nop" : "+r"(x));
| ^ assignment to borrowed `x` occurs here
LL | }
LL | let z = y;
| - borrow later used here
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:78:45
|
LL | let x = &mut 2;
| - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
LL | unsafe {
LL | llvm_asm!("nop" : : "r"(x), "r"(x) );
| - ^ value used here after move
| |
| value moved here
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0381, E0382, E0384, E0503, E0506.
For more information about an error, try `rustc --explain E0381`.

View file

@ -1,24 +1,13 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
// only-x86_64
#![feature(llvm_asm)]
#![allow(const_err)]
#![allow(deprecated)] // llvm_asm!
use std::arch::asm;
fn main() {}
// Make sure we catch executing inline assembly.
static TEST_BAD1: () = {
unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
//~^ ERROR could not evaluate static initializer
//~| NOTE inline assembly is not supported
//~| NOTE in this expansion of llvm_asm!
//~| NOTE in this expansion of llvm_asm!
};
// Make sure we catch executing inline assembly.
static TEST_BAD2: () = {
static TEST_BAD: () = {
unsafe { asm!("nop"); }
//~^ ERROR could not evaluate static initializer
//~| NOTE inline assembly is not supported

View file

@ -1,13 +1,5 @@
error[E0080]: could not evaluate static initializer
--> $DIR/inline_asm.rs:13:14
|
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported
|
= note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: could not evaluate static initializer
--> $DIR/inline_asm.rs:22:14
--> $DIR/inline_asm.rs:11:14
|
LL | unsafe { asm!("nop"); }
| ^^^^^^^^^^^ inline assembly is not supported
@ -15,17 +7,11 @@ LL | unsafe { asm!("nop"); }
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
--> $DIR/inline_asm.rs:13:14
|
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/inline_asm.rs:22:14
--> $DIR/inline_asm.rs:11:14
|
LL | unsafe { asm!("nop"); }
| ^^^^^^^^^^^
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0080`.

View file

@ -1,10 +0,0 @@
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
fn main() {
let a;
llvm_asm!("nop" "nop");
//~^ ERROR E0660
llvm_asm!("nop" "nop" : "=r"(a));
//~^ ERROR E0660
}

View file

@ -1,15 +0,0 @@
error[E0660]: malformed inline assembly
--> $DIR/E0660.rs:6:5
|
LL | llvm_asm!("nop" "nop");
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0660]: malformed inline assembly
--> $DIR/E0660.rs:8:5
|
LL | llvm_asm!("nop" "nop" : "=r"(a));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0660`.

View file

@ -1,10 +0,0 @@
// ignore-emscripten
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
fn main() {
let a; //~ ERROR type annotations needed
llvm_asm!("nop" : "r"(a));
//~^ ERROR E0661
}

View file

@ -1,16 +0,0 @@
error[E0661]: output operand constraint lacks '=' or '+'
--> $DIR/E0661.rs:8:23
|
LL | llvm_asm!("nop" : "r"(a));
| ^^^
error[E0282]: type annotations needed
--> $DIR/E0661.rs:7:9
|
LL | let a;
| ^ consider giving `a` a type
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0661.
For more information about an error, try `rustc --explain E0282`.

View file

@ -1,11 +0,0 @@
// ignore-emscripten
#![feature(llvm_asm)]
#![allow(deprecated)] // llvm_asm!
fn main() {
llvm_asm!("xor %eax, %eax"
:
: "=test"("a") //~ ERROR E0662
);
}

Some files were not shown because too many files have changed in this diff Show more