gccrs: unsafe: check use of `target_feature` attribute
authorPrajwal S N <prajwalnadig21@gmail.com>
Sat, 31 Dec 2022 07:19:02 +0000 (12:49 +0530)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 6 Apr 2023 08:47:16 +0000 (10:47 +0200)
The `target_feature` attribute is for conditional compilation and may or
may not compile on all platforms. Using it requires an unsafe function
or block.

gcc/rust/ChangeLog:

* checks/errors/rust-unsafe-checker.cc (check_target_attr): New function.
(UnsafeChecker::check_function_attr): Call into `check_target_attr`.
(UnsafeChecker::visit): Check for target_feature attributes.
* checks/errors/rust-unsafe-checker.h: Add declarations.
* util/rust-attributes.cc: Add attribute.

gcc/testsuite/ChangeLog:

* rust/compile/unsafe11.rs: New test.

Signed-off-by: Prajwal S N <prajwalnadig21@gmail.com>
gcc/rust/checks/errors/rust-unsafe-checker.cc
gcc/rust/checks/errors/rust-unsafe-checker.h
gcc/rust/util/rust-attributes.cc
gcc/testsuite/rust/compile/unsafe11.rs [new file with mode: 0644]

index 9480863..3c369a2 100644 (file)
@@ -179,6 +179,31 @@ UnsafeChecker::check_function_call (HirId node_id, Location locus)
                       locus);
 }
 
+static void
+check_target_attr (HIR::Function *fn, Location locus)
+{
+  if (std::any_of (fn->get_outer_attrs ().begin (),
+                  fn->get_outer_attrs ().end (),
+                  [] (const AST::Attribute &attr) {
+                    return attr.get_path ().as_string () == "target_feature";
+                  }))
+    rust_error_at (locus,
+                  "call to function with %<#[target_feature]%> requires "
+                  "unsafe function or block");
+}
+
+void
+UnsafeChecker::check_function_attr (HirId node_id, Location locus)
+{
+  if (unsafe_context.is_in_context ())
+    return;
+
+  auto maybe_fn = mappings.lookup_hir_item (node_id);
+
+  if (maybe_fn && maybe_fn->get_item_kind () == Item::ItemKind::Function)
+    check_target_attr (static_cast<Function *> (maybe_fn), locus);
+}
+
 void
 UnsafeChecker::visit (Lifetime &)
 {}
@@ -398,11 +423,13 @@ UnsafeChecker::visit (CallExpr &expr)
 
   rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
 
-  // At this point we have the function's HIR Id. There are two checks we
+  // At this point we have the function's HIR Id. There are three checks we
   // must perform:
   //     1. The function is an unsafe one
   //     2. The function is an extern one
+  //     3. The function is marked with a target_feature attribute
   check_function_call (definition_id, expr.get_locus ());
+  check_function_attr (definition_id, expr.get_locus ());
 
   if (expr.has_params ())
     for (auto &arg : expr.get_arguments ())
index 9df44db..2abd3a6 100644 (file)
@@ -46,6 +46,11 @@ private:
    */
   void check_function_call (HirId node_id, Location locus);
 
+  /**
+   * Check if any unsafe attributes are present on a function
+   */
+  void check_function_attr (HirId node_id, Location locus);
+
   StackedContexts<HirId> unsafe_context;
 
   Resolver::TypeCheckContext &context;
index 33f2c93..0458f69 100644 (file)
@@ -41,6 +41,9 @@ static const BuiltinAttrDefinition __definitions[]
      {"repr", CODE_GENERATION},
      {"path", EXPANSION},
      {"macro_use", NAME_RESOLUTION},
+     // FIXME: This is not implemented yet, see
+     // https://github.com/Rust-GCC/gccrs/issues/1475
+     {"target_feature", CODE_GENERATION},
      // From now on, these are reserved by the compiler and gated through
      // #![feature(rustc_attrs)]
      {"rustc_inherit_overflow_checks", CODE_GENERATION}};
diff --git a/gcc/testsuite/rust/compile/unsafe11.rs b/gcc/testsuite/rust/compile/unsafe11.rs
new file mode 100644 (file)
index 0000000..c87902f
--- /dev/null
@@ -0,0 +1,8 @@
+#[target_feature(sse)]
+fn foo() {
+    let a: usize = 0;
+}
+
+fn main() {
+    foo() // { dg-error "requires unsafe function or block" }
+}