diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 73c77cdddd9..47c29436856 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -839,6 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>, expr.span, []); } + ast::ExprInlineAsm(ref ia) => { + for &(_, out) in ia.outputs.iter() { + this.check_assignment(out); + } + } _ => { } } } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index aaaa893c3e5..224c8bf6a6b 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -309,6 +309,23 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt, visit::walk_expr(this, ex, ()); } + ast::ExprInlineAsm(ref ia) => { + for &(_, out) in ia.outputs.iter() { + let out_cmt = this.bccx.cat_expr(out); + match opt_loan_path(out_cmt) { + Some(out_lp) => { + gather_moves::gather_assignment(this.bccx, this.move_data, + ex.id, ex.span, + out_lp, out.id); + } + None => { + // See the comment for ExprAssign. + } + } + } + visit::walk_expr(this, ex, ()); + } + _ => { visit::walk_expr(this, ex, ()); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 27384a6ab4b..824dbb5b561 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -1227,12 +1227,15 @@ pub fn propagate_through_expr(&self, expr: @Expr, succ: LiveNode) self.propagate_through_expr(e, succ) } - ExprInlineAsm(ref ia) =>{ + ExprInlineAsm(ref ia) => { let succ = do ia.inputs.rev_iter().fold(succ) |succ, &(_, expr)| { self.propagate_through_expr(expr, succ) }; do ia.outputs.rev_iter().fold(succ) |succ, &(_, expr)| { - self.propagate_through_expr(expr, succ) + // see comment on lvalues in + // propagate_through_lvalue_components() + let succ = self.write_lvalue(expr, succ, ACC_WRITE); + self.propagate_through_lvalue_components(expr, succ) } } @@ -1478,12 +1481,7 @@ fn check_expr(this: &mut Liveness, expr: @Expr) { // Output operands must be lvalues for &(_, out) in ia.outputs.iter() { - match out.node { - ExprAddrOf(_, inner) => { - this.check_lvalue(inner); - } - _ => {} - } + this.check_lvalue(out); this.visit_expr(out, ()); } diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs index 4a960b1721d..cfeefc8642c 100644 --- a/src/librustc/middle/trans/asm.rs +++ b/src/librustc/middle/trans/asm.rs @@ -18,6 +18,8 @@ use middle::trans::build::*; use middle::trans::callee; use middle::trans::common::*; +use middle::trans::expr::*; +use middle::trans::type_of::*; use middle::ty; use middle::trans::type_::Type; @@ -30,34 +32,15 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block { let mut bcx = bcx; let mut constraints = ~[]; let mut cleanups = ~[]; - let mut aoutputs = ~[]; + let mut output_types = ~[]; // Prepare the output operands let outputs = do ia.outputs.map |&(c, out)| { constraints.push(c); - aoutputs.push(unpack_result!(bcx, { - callee::trans_arg_expr(bcx, - expr_ty(bcx, out), - ty::ByCopy, - out, - &mut cleanups, - callee::DontAutorefArg) - })); - - let e = match out.node { - ast::ExprAddrOf(_, e) => e, - _ => fail2!("Expression must be addr of") - }; - - unpack_result!(bcx, { - callee::trans_arg_expr(bcx, - expr_ty(bcx, e), - ty::ByCopy, - e, - &mut cleanups, - callee::DontAutorefArg) - }) + let out_datum = unpack_datum!(bcx, trans_to_datum(bcx, out)); + output_types.push(type_of(bcx.ccx(), out_datum.ty)); + out_datum.val }; @@ -92,7 +75,7 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block { clobbers = format!("{},{}", ia.clobbers, clobbers); } else { clobbers.push_str(ia.clobbers); - }; + } // Add the clobbers to our constraints list if clobbers.len() != 0 && constraints.len() != 0 { @@ -107,12 +90,12 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block { let numOutputs = outputs.len(); // Depending on how many outputs we have, the return type is different - let output = if numOutputs == 0 { + let output_type = if numOutputs == 0 { Type::void() } else if numOutputs == 1 { - val_ty(outputs[0]) + output_types[0] } else { - Type::struct_(outputs.map(|o| val_ty(*o)), false) + Type::struct_(output_types, false) }; let dialect = match ia.dialect { @@ -122,19 +105,17 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block { let r = do ia.asm.with_c_str |a| { do constraints.with_c_str |c| { - InlineAsmCall(bcx, a, c, inputs, output, ia.volatile, ia.alignstack, dialect) + InlineAsmCall(bcx, a, c, inputs, output_type, ia.volatile, ia.alignstack, dialect) } }; // Again, based on how many outputs we have if numOutputs == 1 { - let op = PointerCast(bcx, aoutputs[0], val_ty(outputs[0]).ptr_to()); - Store(bcx, r, op); + Store(bcx, r, outputs[0]); } else { - for (i, o) in aoutputs.iter().enumerate() { + for (i, o) in outputs.iter().enumerate() { let v = ExtractValue(bcx, r, i); - let op = PointerCast(bcx, *o, val_ty(outputs[i]).ptr_to()); - Store(bcx, v, op); + Store(bcx, v, *o); } } diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index e836367555a..f4b1c7f1f06 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -75,16 +75,18 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) } let (constraint, _str_style) = p.parse_str(); + + if constraint.starts_with("+") { + cx.span_unimpl(*p.last_span, + "'+' (read+write) output operand constraint modifier"); + } else if !constraint.starts_with("=") { + cx.span_err(*p.last_span, "output operand constraint lacks '='"); + } + p.expect(&token::LPAREN); let out = p.parse_expr(); p.expect(&token::RPAREN); - let out = @ast::Expr { - id: ast::DUMMY_NODE_ID, - span: out.span, - node: ast::ExprAddrOf(ast::MutMutable, out) - }; - outputs.push((constraint, out)); } } @@ -98,6 +100,13 @@ pub fn expand_asm(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) } let (constraint, _str_style) = p.parse_str(); + + if constraint.starts_with("=") { + cx.span_err(*p.last_span, "input operand constraint contains '='"); + } else if constraint.starts_with("+") { + cx.span_err(*p.last_span, "input operand constraint contains '+'"); + } + p.expect(&token::LPAREN); let input = p.parse_expr(); p.expect(&token::RPAREN); diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs new file mode 100644 index 00000000000..442536b1e29 --- /dev/null +++ b/src/test/compile-fail/asm-in-bad-modifier.rs @@ -0,0 +1,27 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: int) { info2!("{}", x); } + +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "x86_64")] +pub fn main() { + let x: int; + let y: int; + unsafe { + asm!("mov $1, $0" : "=r"(x) : "=r"(5u)); //~ ERROR input operand constraint contains '=' + asm!("mov $1, $0" : "=r"(y) : "+r"(5u)); //~ ERROR input operand constraint contains '+' + } + foo(x); + foo(y); +} + +#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] +pub fn main() {} diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs new file mode 100644 index 00000000000..6709e803d88 --- /dev/null +++ b/src/test/compile-fail/asm-out-assign-imm.rs @@ -0,0 +1,26 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: int) { info2!("{}", x); } + +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "x86_64")] +pub fn main() { + let x: int; + x = 1; //~ NOTE prior assignment occurs here + foo(x); + unsafe { + asm!("mov $1, $0" : "=r"(x) : "r"(5u)); //~ ERROR re-assignment of immutable variable `x` + } + foo(x); +} + +#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] +pub fn main() {} diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs new file mode 100644 index 00000000000..9ddb0d529d4 --- /dev/null +++ b/src/test/compile-fail/asm-out-no-modifier.rs @@ -0,0 +1,24 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: int) { info2!("{}", x); } + +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "x86_64")] +pub fn main() { + let x: int; + unsafe { + asm!("mov $1, $0" : "r"(x) : "r"(5u)); //~ ERROR output operand constraint lacks '=' + } + foo(x); +} + +#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] +pub fn main() {} diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs new file mode 100644 index 00000000000..9a3701511e3 --- /dev/null +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -0,0 +1,24 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: int) { info2!("{}", x); } + +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "x86_64")] +pub fn main() { + let x: int; + unsafe { + asm!("mov $1, $0" : "=r"(x) : "r"(x)); //~ ERROR use of possibly uninitialized value: `x` + } + foo(x); +} + +#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] +pub fn main() {} diff --git a/src/test/run-pass/asm-out-assign.rs b/src/test/run-pass/asm-out-assign.rs new file mode 100644 index 00000000000..2e1fc65d2ba --- /dev/null +++ b/src/test/run-pass/asm-out-assign.rs @@ -0,0 +1,32 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "x86_64")] +pub fn main() { + let x: int; + unsafe { + // Treat the output as initialization. + asm!("mov $1, $0" : "=r"(x) : "r"(5u)); + } + assert_eq!(x, 5); + + let mut x = x + 1; + assert_eq!(x, 6); + + unsafe { + // Assignment to mutable. + asm!("mov $1, $0" : "=r"(x) : "r"(x + 7)); + } + assert_eq!(x, 13); +} + +#[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] +pub fn main() {}