From: Wesley Lewis <[email protected]>

Return the error E0802 on structs that have no type parameter to act as a 
pointee, or several
which are marked as pointee. For structs having multiple non-generic typed 
fields, the one
marked with #[pointee] will be selected as the pointee.

Fixes Rust-GCC/gccrs#4915

Author:         Wesley Lewis <[email protected]>

gcc/rust/ChangeLog:

        * expand/rust-derive-coerce-pointee.cc
        (DeriveCoercePointee::validate_non_generic_pointee): New.
        (DeriveCoercePointee::go): Call validate_non_generic_pointee.
        * expand/rust-derive-coerce-pointee.h
        (DeriveCoercePointee::validate_non_generic_pointee): Declare.
        * util/rust-attribute-values.h: Added POINTEE.

gcc/testsuite/ChangeLog:

        * rust/compile/derive-coerce-pointee6.rs: New test.

Signed-off-by: Wesley Lewis <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/bf1780e025a28132ef1ca46fc3acc40a1dda9d4e

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4915: https://github.com/Rust-GCC/gccrs/issues/4915

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4950

 gcc/rust/expand/rust-derive-coerce-pointee.cc | 123 +++++++++++++-----
 gcc/rust/expand/rust-derive-coerce-pointee.h  |  17 ++-
 gcc/rust/util/rust-attribute-values.h         |   1 +
 .../rust/compile/derive-coerce-pointee6.rs    |  41 ++++++
 .../rust/compile/derive-coerce-pointee7.rs    |  27 ++++
 5 files changed, 172 insertions(+), 37 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee6.rs
 create mode 100644 gcc/testsuite/rust/compile/derive-coerce-pointee7.rs

diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.cc 
b/gcc/rust/expand/rust-derive-coerce-pointee.cc
index b2c71d2c8..e23362b75 100644
--- a/gcc/rust/expand/rust-derive-coerce-pointee.cc
+++ b/gcc/rust/expand/rust-derive-coerce-pointee.cc
@@ -18,7 +18,6 @@
 
 #include "rust-attribute-values.h"
 #include "rust-derive-coerce-pointee.h"
-#include "rust-diagnostics.h"
 #include "rust-feature-store.h"
 #include "rust-feature.h"
 #include "rust-session-manager.h"
@@ -34,8 +33,7 @@ DeriveCoercePointee::DeriveCoercePointee (location_t loc,
 std::unique_ptr<AST::Item>
 DeriveCoercePointee::go (Item &item)
 {
-  validate_repr_transparent (item);
-  validate_number_of_fields (item);
+  item.accept_vis (*this);
   Features::EarlyFeatureGateStore::get ().add (
     Feature::Name::DERIVE_COERCE_POINTEE,
     Error (loc, "use of unstable library feature %<derive_coerce_pointee%>"));
@@ -77,7 +75,7 @@ DeriveCoercePointee::go (Item &item)
 }
 
 // CoercePointee requires the Struct or Tuple to have transparent 
representation
-bool
+void
 DeriveCoercePointee::validate_repr_transparent (const Item &item)
 {
   const auto &attrs = item.get_outer_attrs ();
@@ -85,55 +83,118 @@ DeriveCoercePointee::validate_repr_transparent (const Item 
&item)
     {
       if (attr.get_path ().as_string () != Values::Attributes::REPR)
        continue;
-      if (attr.empty_input ())
-       continue;
+      rust_assert (!attr.empty_input ());
 
       const auto &attr_input = attr.get_attr_input ();
-      if (attr_input.get_attr_input_type ()
-         != AST::AttrInput::AttrInputType::TOKEN_TREE)
-       continue;
+      rust_assert (attr_input.get_attr_input_type ()
+                  == AST::AttrInput::AttrInputType::TOKEN_TREE);
 
       auto meta_item = static_cast<const AST::DelimTokenTree &> (attr_input)
                         .parse_to_meta_item ();
+      rust_assert (meta_item);
 
       for (const auto &item : meta_item->get_items ())
        if (item->as_string () == "transparent")
-         return true;
+         return;
     }
   rust_error_at (item.get_locus (), ErrorCode::E0802,
                 "%<CoercePointee%> is only applicable to struct/tuple with "
                 "repr(transparent) layout");
-  return false;
 }
 
 // Structs or Tuples with CoercePointee must have minimum of one field else
 // compile time error
-bool
+void
 DeriveCoercePointee::validate_number_of_fields (const Item &item)
 {
-  size_t field_count = 0;
-
-  if (item.get_item_kind () == Item::Kind::Struct)
-    {
-      auto *struct_item = static_cast<const StructStruct *> (&item);
-      field_count = struct_item->get_fields ().size ();
-    }
-  else
-    {
-      rust_error_at (item.get_locus (), ErrorCode::E0802,
-                    "%<CoercePointee%> can only be derived on structs with "
-                    "#[repr(transparent)]");
-      return false;
-    }
+  rust_assert (item.get_item_kind () == Item::Kind::Struct);
+  auto &struct_item = static_cast<const StructStruct &> (item);
+  size_t field_count = struct_item.get_fields ().size ();
 
   if (field_count == 0)
+    rust_error_at (item.get_locus (), ErrorCode::E0802,
+                  "%<CoercePointee%> can only be derived on a struct "
+                  "with at least one field");
+}
+
+// #[pointee] needs to be on a generic type parameter, and if there are 2 or
+// more generic parameters (not traits), one of them must have the attribute
+void
+DeriveCoercePointee::validate_non_generic_pointee (const Rust::AST::Item &item)
+{
+  rust_assert (item.get_item_kind () == Item::Kind::Struct);
+  const StructStruct &struct_item = static_cast<const StructStruct &> (item);
+  const std::vector<std::unique_ptr<GenericParam>> &generic_params
+    = struct_item.get_generic_params ();
+
+  // Implicitly it becomes the pointee
+  if (generic_params.size () == 1)
+    return;
+
+  size_t pointee_count = 0;
+
+  for (size_t i = 0; i < generic_params.size (); ++i)
     {
-      rust_error_at (item.get_locus (), ErrorCode::E0802,
-                    "%<CoercePointee%> can only be derived on a struct "
-                    "with at least one field");
-      return false;
+      if (generic_params[i].get ()->get_kind () != GenericParam::Kind::Const
+         && (generic_params)[i].get ()->get_kind ()
+              != GenericParam::Kind::Lifetime)
+       {
+         auto &type_param
+           = static_cast<TypeParam &> (*(generic_params)[i].get ());
+
+         for (const auto &attr : type_param.get_outer_attrs ())
+           {
+             if (attr.get_path ().as_string () == Values::Attributes::POINTEE)
+               pointee_count += 1;
+           }
+       }
     }
-  return true;
+
+  if (pointee_count == 0 || pointee_count > 1)
+    rust_error_at (item.get_locus (), ErrorCode::E0802,
+                  "exactly one generic type parameter must be marked "
+                  "as %<#[pointee]%> to derive %<CoercePointee%> traits");
+}
+
+// validates all the requirements for a type to be derived as CoercePointee
+void
+DeriveCoercePointee::validate (const Item &item)
+{
+  validate_repr_transparent (item);
+  validate_number_of_fields (item);
+  validate_non_generic_pointee (item);
+}
+
+void
+DeriveCoercePointee::visit_struct (StructStruct &item)
+{
+  validate (item);
+}
+
+void
+DeriveCoercePointee::visit_tuple (TupleStruct &item)
+{
+  validate (item);
+}
+
+void
+DeriveCoercePointee::visit_enum (Enum &item)
+{
+  error_for_non_supported_objects (item);
+}
+
+void
+DeriveCoercePointee::visit_union (Union &item)
+{
+  error_for_non_supported_objects (item);
+}
+
+void
+DeriveCoercePointee::error_for_non_supported_objects (const Item &item)
+{
+  rust_error_at (item.get_locus (), ErrorCode::E0802,
+                "%<CoercePointee%> can only be derived on structs with "
+                "%<#[repr(transparent)]%>");
 }
 } // namespace AST
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-coerce-pointee.h 
b/gcc/rust/expand/rust-derive-coerce-pointee.h
index b3f4e5239..e8be9a76b 100644
--- a/gcc/rust/expand/rust-derive-coerce-pointee.h
+++ b/gcc/rust/expand/rust-derive-coerce-pointee.h
@@ -31,13 +31,18 @@ public:
 
   std::unique_ptr<Item> go (Item &item);
 
-  bool validate_repr_transparent (const Item &item);
-  bool validate_number_of_fields (const Item &item);
+  void validate (const Item &item);
+  void validate_repr_transparent (const Item &item);
+  void validate_number_of_fields (const Item &item);
+  void validate_non_generic_pointee (const Item &item);
+
+  void error_for_non_supported_objects (const Item &item);
+
 private:
-  virtual void visit_struct (StructStruct &item) override {}
-  virtual void visit_tuple (TupleStruct &item) override {}
-  virtual void visit_enum (Enum &item) override {}
-  virtual void visit_union (Union &item) override {}
+  virtual void visit_struct (StructStruct &item) override;
+  virtual void visit_tuple (TupleStruct &item) override;
+  virtual void visit_enum (Enum &item) override;
+  virtual void visit_union (Union &item) override;
 };
 
 } // namespace AST
diff --git a/gcc/rust/util/rust-attribute-values.h 
b/gcc/rust/util/rust-attribute-values.h
index e42a67296..291e43338 100644
--- a/gcc/rust/util/rust-attribute-values.h
+++ b/gcc/rust/util/rust-attribute-values.h
@@ -58,6 +58,7 @@ public:
   static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute";
   static constexpr auto &CRATE_NAME = "crate_name";
   static constexpr auto &CRATE_TYPE = "crate_type";
+  static constexpr auto &POINTEE = "pointee";
 
   static constexpr auto &TARGET_FEATURE = "target_feature";
   static constexpr auto &FEATURE = "feature";
diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs 
b/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs
new file mode 100644
index 000000000..1b4d0905e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive-coerce-pointee6.rs
@@ -0,0 +1,41 @@
+// { dg-additional-options "-frust-compat-version=1.84" }
+// { dg-prune-output "could not resolve attribute macro invocation 'pointee'" }
+
+// checks for 1 non-generic type for structs with derive CoercePointee having 
more than 1 generic
+// params
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![feature(derive_coerce_pointee)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// user-defined trait
+trait MyTrait {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T>;
+
+#[repr(transparent)]
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+                         // { dg-error "one generic type parameter must be 
marked as '#\\\[pointee\\\]'" "" { target *-*-* } .+1 }
+struct MultipleGenericStruct<T: MyTrait, U> {
+    a: *const T,
+    b: PhantomData<U>,
+}
+
+#[repr(transparent)]
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+struct MultipleMarkedPointee<#[pointee] T: MyTrait, #[pointee] U> { // { 
dg-error "one generic type parameter must be marked as '#\\\[pointee\\\]'" "" { 
target *-*-* } }
+    a: *const T,
+    b: PhantomData<U>,
+}
+
+#[repr(transparent)]
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+struct Good<#[pointee]T: MyTrait, U> {
+    a: *const T,
+    b: PhantomData<U>,
+}
diff --git a/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs 
b/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs
new file mode 100644
index 000000000..19e6c8994
--- /dev/null
+++ b/gcc/testsuite/rust/compile/derive-coerce-pointee7.rs
@@ -0,0 +1,27 @@
+// { dg-additional-options "-frust-compat-version=1.84" }
+
+// Check if derive CoercePointee errors out on Union & Enums 
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![feature(derive_coerce_pointee)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// user-defined trait
+trait MyTrait {}
+
+#[repr(transparent)]
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+// { dg-error "only be derived on structs with 
'#\\\[repr\\(transparent\\)\\\]'" "" { target *-*-* } .+1 }
+enum GenericEnum<T: MyTrait> {
+    A(T)
+}
+
+#[repr(transparent)]
+#[derive(CoercePointee)] // { dg-warning "no effect" }
+union GenericUnion<T: MyTrait> { // { dg-error "only be derived on structs 
with '#\\\[repr\\(transparent\\)\\\]'" "" { target *-*-* } }
+    a: T,
+}
-- 
2.56.0

Reply via email to