diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2016-06-30 21:12:36 +0300 |
|---|---|---|
| committer | Eduard Burtescu <edy.burt@gmail.com> | 2016-06-30 21:12:36 +0300 |
| commit | f698cd3a3663a459e459f530f76adef3eeb815fd (patch) | |
| tree | 377be430e62d07b623677305b69822a44ca558f4 | |
| parent | c2b56fb7a0c24e04227318ca7e5950e9289ee3e4 (diff) | |
| download | rust-f698cd3a3663a459e459f530f76adef3eeb815fd.tar.gz rust-f698cd3a3663a459e459f530f76adef3eeb815fd.zip | |
Revert "Remove the return_address intrinsic."
This reverts commit b30134dbc3c29cf62a4518090e1389ff26918c19.
| -rw-r--r-- | src/libcore/intrinsics.rs | 6 | ||||
| -rw-r--r-- | src/librustc_trans/diagnostics.rs | 38 | ||||
| -rw-r--r-- | src/librustc_trans/intrinsic.rs | 12 | ||||
| -rw-r--r-- | src/librustc_typeck/check/intrinsic.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/intrinsic-return-address.rs | 24 | ||||
| -rw-r--r-- | src/test/run-pass/intrinsic-return-address.rs | 43 |
6 files changed, 125 insertions, 0 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index edb965c1962..94baf188bca 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -293,6 +293,12 @@ extern "rust-intrinsic" { #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute<T, U>(e: T) -> U; + /// Gives the address for the return value of the enclosing function. + /// + /// Using this intrinsic in a function that does not use an out pointer + /// will trigger a compiler error. + pub fn return_address() -> *const u8; + /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` /// implements `Copy`. diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs index f7f065a3562..d36878b0332 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_trans/diagnostics.rs @@ -12,6 +12,44 @@ register_long_diagnostics! { +E0510: r##" +`return_address` was used in an invalid context. Erroneous code example: + +```ignore +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn by_value() -> i32 { + let _ = return_address(); + // error: invalid use of `return_address` intrinsic: function does + // not use out pointer + 0 +} +``` + +Return values may be stored in a return register(s) or written into a so-called +out pointer. In case the returned value is too big (this is +target-ABI-dependent and generally not portable or future proof) to fit into +the return register(s), the compiler will return the value by writing it into +space allocated in the caller's stack frame. Example: + +``` +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn by_pointer() -> String { + let _ = return_address(); + String::new() // ok! +} +``` +"##, + E0511: r##" Invalid monomorphization of an intrinsic function was used. Erroneous code example: diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0..bd24647edf0 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -617,6 +617,18 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, + + (_, "return_address") => { + if !fcx.fn_ty.ret.is_indirect() { + span_err!(tcx.sess, span, E0510, + "invalid use of `return_address` intrinsic: function \ + does not use out pointer"); + C_null(Type::i8p(ccx)) + } else { + PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx)) + } + } + (_, "discriminant_value") => { let val_ty = substs.types.get(FnSpace, 0); match val_ty.sty { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e44..0fb08ec9855 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -275,6 +275,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), + "return_address" => (0, vec![], tcx.mk_imm_ptr(tcx.types.u8)), + "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), "discriminant_value" => (1, vec![ diff --git a/src/test/compile-fail/intrinsic-return-address.rs b/src/test/compile-fail/intrinsic-return-address.rs new file mode 100644 index 00000000000..906056896be --- /dev/null +++ b/src/test/compile-fail/intrinsic-return-address.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +unsafe fn f() { let _ = return_address(); } +//~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer + +unsafe fn g() -> isize { let _ = return_address(); 0 } +//~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer + +fn main() {} diff --git a/src/test/run-pass/intrinsic-return-address.rs b/src/test/run-pass/intrinsic-return-address.rs new file mode 100644 index 00000000000..63aed3f009f --- /dev/null +++ b/src/test/run-pass/intrinsic-return-address.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2014 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![feature(intrinsics)] + +use std::ptr; + +struct Point { + x: f32, + y: f32, + z: f32, +} + +extern "rust-intrinsic" { + fn return_address() -> *const u8; +} + +fn f(result: &mut usize) -> Point { + unsafe { + *result = return_address() as usize; + Point { + x: 1.0, + y: 2.0, + z: 3.0, + } + } + +} + +fn main() { + let mut intrinsic_reported_address = 0; + let pt = f(&mut intrinsic_reported_address); + let actual_address = &pt as *const Point as usize; + assert_eq!(intrinsic_reported_address, actual_address); +} |
