about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/intrinsics.rs7
-rw-r--r--src/librustc/middle/trans/callee.rs4
-rw-r--r--src/librustc/middle/trans/intrinsic.rs13
-rw-r--r--src/test/compile-fail/intrinsic-return-address.rs31
-rw-r--r--src/test/run-pass/intrinsic-return-address.rs2
5 files changed, 51 insertions, 6 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 002babf7df9..1dd3d6ce9db 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -310,6 +310,13 @@ extern "rust-intrinsic" {
     /// ```
     pub fn transmute<T,U>(e: T) -> U;
 
+    /// Gives the address for the return value of the enclosing function.
+    ///
+    /// Using this instrinsic in a function that does not use an out pointer
+    /// will trigger a compiler error.
+    #[cfg(not(stage0))]
+    pub fn return_address() -> *const u8;
+
     /// Returns `true` if a type requires drop glue.
     pub fn needs_drop<T>() -> bool;
 
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 3bea9d64462..dd37f3adab9 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -765,9 +765,11 @@ pub fn trans_call_inner<'a>(
             assert!(abi == synabi::RustIntrinsic);
             assert!(dest.is_some());
 
+            let call_info = call_info.expect("no call info for intrinsic call?");
             return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
                                                    arg_cleanup_scope, args,
-                                                   dest.unwrap(), substs);
+                                                   dest.unwrap(), substs,
+                                                   call_info);
         }
         NamedTupleConstructor(substs, disr) => {
             assert!(dest.is_some());
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 154f2b122ab..359c8d24f72 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -126,7 +126,7 @@ pub fn check_intrinsics(ccx: &CrateContext) {
 pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
                                 callee_ty: ty::t, cleanup_scope: cleanup::CustomScopeIndex,
                                 args: callee::CallArgs, dest: expr::Dest,
-                                substs: subst::Substs) -> Result<'a> {
+                                substs: subst::Substs, call_info: NodeInfo) -> Result<'a> {
 
     let fcx = bcx.fcx;
     let ccx = fcx.ccx;
@@ -426,9 +426,14 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
                                     *llargs.get(0), *llargs.get(1)),
 
         (_, "return_address") => {
-            PointerCast(bcx,
-                        bcx.fcx.llretptr.get().unwrap(),
-                        Type::i8p(bcx.ccx()))
+            if !fcx.caller_expects_out_pointer {
+                tcx.sess.span_err(call_info.span,
+                                  "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))
+            }
         }
 
         // This requires that atomic intrinsics follow a specific naming pattern:
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..9c1db4057c6
--- /dev/null
+++ b/src/test/compile-fail/intrinsic-return-address.rs
@@ -0,0 +1,31 @@
+// 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() -> int {
+    let _ = return_address();
+    //~^ ERROR invalid use of `return_address` intrinsic: function does not use out pointer
+    0
+}
+
+fn main() {}
+
+
diff --git a/src/test/run-pass/intrinsic-return-address.rs b/src/test/run-pass/intrinsic-return-address.rs
index a28a79d306b..91af669340d 100644
--- a/src/test/run-pass/intrinsic-return-address.rs
+++ b/src/test/run-pass/intrinsic-return-address.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(intrinsics)];
+#![feature(intrinsics)]
 
 use std::ptr;