about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgnzlbg <gonzalobg88@gmail.com>2019-02-09 15:55:30 +0100
committergnzlbg <gonzalobg88@gmail.com>2019-02-23 15:48:40 +0100
commitc4b46ace556f3e4776d06ea7672daba6b243a80f (patch)
tree34033c65f3206aeb933e7784cbb19cb0d22405fa
parentbcfb5e8ac30c46ba512526d66f803756c124c7bb (diff)
downloadrust-c4b46ace556f3e4776d06ea7672daba6b243a80f.tar.gz
rust-c4b46ace556f3e4776d06ea7672daba6b243a80f.zip
Implement ffi_returns_twice attribute
-rw-r--r--src/librustc/hir/mod.rs3
-rw-r--r--src/librustc_codegen_llvm/attributes.rs3
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_typeck/collect.rs12
-rw-r--r--src/librustc_typeck/diagnostics.rs1
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/rustllvm/rustllvm.h1
-rw-r--r--src/test/codegen/ffi-returns-twice.rs15
-rw-r--r--src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr11
-rw-r--r--src/test/ui/ffi_returns_twice.rs6
-rw-r--r--src/test/ui/ffi_returns_twice.stderr9
13 files changed, 79 insertions, 0 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d0b92587b59..df02b91996f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2518,6 +2518,9 @@ bitflags! {
         /// `#[used]`: indicates that LLVM can't eliminate this function (but the
         /// linker can!).
         const USED                      = 1 << 9;
+        /// #[ffi_returns_twice], indicates that an extern function can return
+        /// multiple times
+        const FFI_RETURNS_TWICE = 1 << 10;
     }
 }
 
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 827ebff10f5..dab5cab65cd 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -223,6 +223,9 @@ pub fn from_fn_attrs(
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         Attribute::Cold.apply_llfn(Function, llfn);
     }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
+        Attribute::ReturnsTwice.apply_llfn(Function, llfn);
+    }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
         naked(llfn, true);
     }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index e761d2247a7..fe2664118f7 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -114,6 +114,7 @@ pub enum Attribute {
     SanitizeMemory  = 22,
     NonLazyBind     = 23,
     OptimizeNone    = 24,
+    ReturnsTwice    = 25,
 }
 
 /// LLVMIntPredicate
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ec1d9d24730..af029607638 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2388,6 +2388,18 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
         } else if attr.check_name("unwind") {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
+        } else if attr.check_name("ffi_returns_twice") {
+            if tcx.is_foreign_item(id) {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
+            } else {
+                // `#[ffi_returns_twice]` is only allowed `extern fn`s
+                struct_span_err!(
+                    tcx.sess,
+                    attr.span,
+                    E0723,
+                    "`#[ffi_returns_twice]` may only be used on `extern fn`s"
+                ).emit();
+            }
         } else if attr.check_name("rustc_allocator_nounwind") {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
         } else if attr.check_name("naked") {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 3c4a0760f3e..eec2d394849 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4738,4 +4738,5 @@ register_diagnostics! {
     E0698, // type inside generator must be known in this context
     E0719, // duplicate values for associated type binding
     E0722, // Malformed #[optimize] attribute
+    E0723, // `#[ffi_returns_twice]` is only allowed in `extern fn`
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d574b410ccc..378e774686a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -290,6 +290,9 @@ declare_features! (
     // The `repr(i128)` annotation for enums.
     (active, repr128, "1.16.0", Some(35118), None),
 
+    // Allows the use of `#[ffi_returns_twice]` on extern functions.
+    (active, ffi_returns_twice, "1.34.0", Some(58314), None),
+
     // The `unadjusted` ABI; perma-unstable.
     //
     // rustc internal
@@ -1128,6 +1131,11 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
                                  "the `#[naked]` attribute \
                                   is an experimental feature",
                                  cfg_fn!(naked_functions))),
+    ("ffi_returns_twice", Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                 "ffi_returns_twice",
+                                 "the `#[ffi_returns_twice]` attribute \
+                                  is an experimental feature",
+                                 cfg_fn!(ffi_returns_twice))),
     ("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated),
     ("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
     ("inline", Whitelisted, template!(Word, List: "always|never"), Ungated),
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index b33165b8463..a00417a3629 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -190,6 +190,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::NonLazyBind;
   case OptimizeNone:
     return Attribute::OptimizeNone;
+  case ReturnsTwice:
+    return Attribute::ReturnsTwice;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index 933266b4025..a9d267cdb31 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
   SanitizeMemory = 22,
   NonLazyBind = 23,
   OptimizeNone = 24,
+  ReturnsTwice = 25,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/src/test/codegen/ffi-returns-twice.rs b/src/test/codegen/ffi-returns-twice.rs
new file mode 100644
index 00000000000..f6648249eb6
--- /dev/null
+++ b/src/test/codegen/ffi-returns-twice.rs
@@ -0,0 +1,15 @@
+// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_returns_twice)]
+
+extern {
+    // CHECK-LABEL: @foo()
+    // CHECK: attributes #1 = { {{.*}}returns_twice{{.*}} }
+    #[no_mangle]
+    #[ffi_returns_twice]
+    pub fn foo();
+}
+
+pub fn bar() {
+    unsafe { foo() }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs
new file mode 100644
index 00000000000..d3df6e5a852
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs
@@ -0,0 +1,7 @@
+// ignore-tidy-linelength
+#![crate_type = "lib"]
+
+extern {
+    #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
+    pub fn foo();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
new file mode 100644
index 00000000000..5c111fe78f4
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
@@ -0,0 +1,11 @@
+error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
+  --> $DIR/feature-gate-ffi_returns_twice.rs:5:5
+   |
+LL |     #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(ffi_returns_twice)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/ffi_returns_twice.rs b/src/test/ui/ffi_returns_twice.rs
new file mode 100644
index 00000000000..5abf468febc
--- /dev/null
+++ b/src/test/ui/ffi_returns_twice.rs
@@ -0,0 +1,6 @@
+// ignore-tidy-linelength
+#![feature(ffi_returns_twice)]
+#![crate_type = "lib"]
+
+#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on `extern fn`s
+pub fn foo() {}
diff --git a/src/test/ui/ffi_returns_twice.stderr b/src/test/ui/ffi_returns_twice.stderr
new file mode 100644
index 00000000000..4d3ca73af02
--- /dev/null
+++ b/src/test/ui/ffi_returns_twice.stderr
@@ -0,0 +1,9 @@
+error[E0723]: `#[ffi_returns_twice]` may only be used on `extern fn`s
+  --> $DIR/ffi_returns_twice.rs:5:1
+   |
+LL | #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on `extern fn`s
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.