about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2020-04-14 00:19:46 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2020-05-20 01:16:11 +0200
commitabc236414b4bd609513899e651c41f314f71bac4 (patch)
tree4e3b3908a2ab5ec936da026ef507b2366af9229b
parent3a7dfda40a3e798bf086bd58cc7e5e09deb808b5 (diff)
downloadrust-abc236414b4bd609513899e651c41f314f71bac4.tar.gz
rust-abc236414b4bd609513899e651c41f314f71bac4.zip
Implement `#[ffi_const]` and `#[ffi_pure]` function attributes
Introduce function attribute corresponding to the `const`/`pure`
attributes supported by GCC, clang and other compilers.

Based on the work of gnzlbg <gonzalobg88@gmail.com>.
-rw-r--r--src/librustc_codegen_llvm/attributes.rs6
-rw-r--r--src/librustc_error_codes/error_codes.rs3
-rw-r--r--src/librustc_feature/active.rs6
-rw-r--r--src/librustc_feature/builtin_attrs.rs2
-rw-r--r--src/librustc_middle/middle/codegen_fn_attrs.rs6
-rw-r--r--src/librustc_span/symbol.rs2
-rw-r--r--src/librustc_typeck/collect.rs37
7 files changed, 62 insertions, 0 deletions
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 64412843f6d..421c6aca1a9 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -284,6 +284,12 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
         Attribute::ReturnsTwice.apply_llfn(Function, llfn);
     }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
+        Attribute::ReadOnly.apply_llfn(Function, llfn);
+    }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
+        Attribute::ReadNone.apply_llfn(Function, llfn);
+    }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
         naked(llfn, true);
     }
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index d6863c615f6..5865042859d 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -616,4 +616,7 @@ E0754: include_str!("./error_codes/E0754.md"),
     E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
+    E0755, // `#[ffi_pure]` is only allowed on foreign functions
+    E0756, // `#[ffi_const]` is only allowed on foreign functions
+    E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
 }
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 30b8b52bf24..90b2380d864 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -565,6 +565,12 @@ declare_features! (
     /// Allow conditional compilation depending on rust version
     (active, cfg_version, "1.45.0", Some(64796), None),
 
+    /// Allows the use of `#[ffi_pure]` on foreign functions.
+    (active, ffi_pure, "1.45.0", Some(58329), None),
+
+    /// Allows the use of `#[ffi_const]` on foreign functions.
+    (active, ffi_const, "1.45.0", Some(58328), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index 466b318bca7..44971a98cc3 100644
--- a/src/librustc_feature/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -331,6 +331,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
+    gated!(ffi_pure, Whitelisted, template!(Word), experimental!(ffi_pure)),
+    gated!(ffi_const, Whitelisted, template!(Word), experimental!(ffi_const)),
     gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
     gated!(
         register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
diff --git a/src/librustc_middle/middle/codegen_fn_attrs.rs b/src/librustc_middle/middle/codegen_fn_attrs.rs
index e3fe0b3111e..c480944069e 100644
--- a/src/librustc_middle/middle/codegen_fn_attrs.rs
+++ b/src/librustc_middle/middle/codegen_fn_attrs.rs
@@ -77,6 +77,12 @@ bitflags! {
         const NO_SANITIZE_THREAD  = 1 << 14;
         /// All `#[no_sanitize(...)]` attributes.
         const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits;
+        /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
+        /// declaration.
+        const FFI_PURE = 1 << 15;
+        /// #[ffi_const]: applies clang's `const` attribute to a foreign function
+        /// declaration.
+        const FFI_CONST = 1 << 16;
     }
 }
 
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index a38f5949204..6a6098710e8 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -322,6 +322,8 @@ symbols! {
         f32,
         f64,
         feature,
+        ffi_const,
+        ffi_pure,
         ffi_returns_twice,
         field,
         field_init_shorthand,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index fe3028102c6..66ef6a04be9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2374,6 +2374,43 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 )
                 .emit();
             }
+        } else if attr.check_name(sym::ffi_pure) {
+            if tcx.is_foreign_item(id) {
+                if attrs.iter().any(|a| a.check_name(sym::ffi_const)) {
+                    // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+                    struct_span_err!(
+                        tcx.sess,
+                        attr.span,
+                        E0757,
+                        "`#[ffi_const]` function cannot be `#[ffi_pure]`"
+                    )
+                    .emit();
+                } else {
+                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
+                }
+            } else {
+                // `#[ffi_pure]` is only allowed on foreign functions
+                struct_span_err!(
+                    tcx.sess,
+                    attr.span,
+                    E0755,
+                    "`#[ffi_pure]` may only be used on foreign functions"
+                )
+                .emit();
+            }
+        } else if attr.check_name(sym::ffi_const) {
+            if tcx.is_foreign_item(id) {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
+            } else {
+                // `#[ffi_const]` is only allowed on foreign functions
+                struct_span_err!(
+                    tcx.sess,
+                    attr.span,
+                    E0756,
+                    "`#[ffi_const]` may only be used on foreign functions"
+                )
+                .emit();
+            }
         } else if attr.check_name(sym::rustc_allocator_nounwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
         } else if attr.check_name(sym::naked) {