about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeSeulArtichaut <leseulartichaut@gmail.com>2020-05-01 14:17:02 +0200
committerLeSeulArtichaut <leseulartichaut@gmail.com>2020-05-01 14:17:43 +0200
commit2474f0ed88bc1a06e02230619b18e7bc8bb673fc (patch)
treed41c98ef5c25c3e9ab18f8823a275ccb13094e09
parenteece58a8e35c444afba6fa34873bc0244e32cd29 (diff)
downloadrust-2474f0ed88bc1a06e02230619b18e7bc8bb673fc.tar.gz
rust-2474f0ed88bc1a06e02230619b18e7bc8bb673fc.zip
Allow `#[target_feature]` on safe functions
-rw-r--r--src/librustc_feature/active.rs3
-rw-r--r--src/librustc_span/symbol.rs1
-rw-r--r--src/librustc_typeck/collect.rs51
3 files changed, 47 insertions, 8 deletions
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 7b3c599e8c7..cec9e0ce3af 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -559,6 +559,9 @@ declare_features! (
     /// Allow negative trait implementations.
     (active, negative_impls, "1.44.0", Some(68318), None),
 
+    /// Allows the use of `#[target_feature]` on safe functions.
+    (active, target_feature_11, "1.45.0", Some(69098), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 1575e6fd533..74d73404acd 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -722,6 +722,7 @@ symbols! {
         suggestion,
         sync_trait,
         target_feature,
+        target_feature_11,
         target_has_atomic,
         target_has_atomic_load_store,
         target_thread_local,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 9f70a0fbc24..eba8f008537 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, Node, Unsafety};
+use rustc_hir::{GenericParamKind, Node};
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -2413,13 +2413,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 codegen_fn_attrs.export_name = Some(s);
             }
         } else if attr.check_name(sym::target_feature) {
-            if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == Unsafety::Normal {
-                let msg = "`#[target_feature(..)]` can only be applied to `unsafe` functions";
-                tcx.sess
-                    .struct_span_err(attr.span, msg)
-                    .span_label(attr.span, "can only be applied to `unsafe` functions")
-                    .span_label(tcx.def_span(id), "not an `unsafe` function")
-                    .emit();
+            if !tcx.features().target_feature_11 {
+                check_target_feature_safe_fn(tcx, id, attr.span);
+            } else if let Some(local_id) = id.as_local() {
+                if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
+                    check_target_feature_trait_unsafe(tcx, local_id, attr.span);
+                }
             }
             from_target_feature(tcx, id, attr, &whitelist, &mut codegen_fn_attrs.target_features);
         } else if attr.check_name(sym::linkage) {
@@ -2666,3 +2665,39 @@ fn check_link_name_xor_ordinal(
         tcx.sess.err(msg);
     }
 }
+
+/// Checks the function annotated with `#[target_feature]` is unsafe,
+/// reporting an error if it isn't.
+fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) {
+    if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
+        let mut err = feature_err(
+            &tcx.sess.parse_sess,
+            sym::target_feature_11,
+            attr_span,
+            "`#[target_feature(..)]` can only be applied to `unsafe` functions",
+        );
+        err.span_label(tcx.def_span(id), "not an `unsafe` function");
+        err.emit();
+    }
+}
+
+/// Checks the function annotated with `#[target_feature]` is not a safe
+/// trait method implementation, reporting an error if it is.
+fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
+    let hir_id = tcx.hir().as_local_hir_id(id);
+    let node = tcx.hir().get(hir_id);
+    if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
+        let parent_id = tcx.hir().get_parent_item(hir_id);
+        let parent_item = tcx.hir().expect_item(parent_id);
+        if let hir::ItemKind::Impl { of_trait: Some(_), .. } = parent_item.kind {
+            tcx.sess
+                .struct_span_err(
+                    attr_span,
+                    "`#[target_feature(..)]` cannot be applied to safe trait method",
+                )
+                .span_label(attr_span, "cannot be applied to safe trait method")
+                .span_label(tcx.def_span(id), "not an `unsafe` function")
+                .emit();
+        }
+    }
+}