]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[#3045] #[may_dangle] in safe impl
authorLiam Naddell <liam.naddell@mail.utoronto.ca>
Sun, 7 Jul 2024 00:34:28 +0000 (20:34 -0400)
committerP-E-P <32375388+P-E-P@users.noreply.github.com>
Thu, 25 Jul 2024 09:04:43 +0000 (09:04 +0000)
gcc/rust/ChangeLog:
* ast/rust-ast.cc:
Fix Attribute constructors to copy inner_attribute
* checks/errors/rust-unsafe-checker.cc:
Add pass for #[may_dangle] in safe impl's
* hir/rust-ast-lower-item.cc:
Add support for unsafe impl's
* hir/rust-ast-lower-type.cc:
Lower attributes in impl's from AST to HIR
* hir/rust-hir-dump.cc:
Change single attribute to AttrVec
* hir/tree/rust-hir-item.h:
Add unsafe support to Impl blocks in HIR
* hir/tree/rust-hir.cc:
Change single attribute to AttrVec
* hir/tree/rust-hir.h:
Add has/get_outer_attribute to GenericParam

gcc/testsuite/ChangeLog:
* rust/compile/issue-3045-1.rs:
Add test for #[may_dangle] Generic Type triggering error
* rust/compile/issue-3045-2.rs:
Add test for #[may_dangle] Lifetime triggering error

Signed-off-by: Liam Naddell <liam.naddell@mail.utoronto.ca>
gcc/rust/ast/rust-ast.cc
gcc/rust/checks/errors/rust-unsafe-checker.cc
gcc/rust/hir/rust-ast-lower-item.cc
gcc/rust/hir/rust-ast-lower-type.cc
gcc/rust/hir/rust-hir-dump.cc
gcc/rust/hir/tree/rust-hir-item.h
gcc/rust/hir/tree/rust-hir.cc
gcc/rust/hir/tree/rust-hir.h
gcc/testsuite/rust/compile/issue-3045-1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-3045-2.rs [new file with mode: 0644]

index 9c0b1bf82452aa4bc03db59a84a548efd5e718a5..27e62a923a5c11cc8349369d0d20d1453b425740 100644 (file)
@@ -311,7 +311,8 @@ Attribute::get_traits_to_derive ()
 
 // Copy constructor must deep copy attr_input as unique pointer
 Attribute::Attribute (Attribute const &other)
-  : path (other.path), locus (other.locus)
+  : path (other.path), locus (other.locus),
+    inner_attribute (other.inner_attribute)
 {
   // guard to protect from null pointer dereference
   if (other.attr_input != nullptr)
@@ -324,6 +325,7 @@ Attribute::operator= (Attribute const &other)
 {
   path = other.path;
   locus = other.locus;
+  inner_attribute = other.inner_attribute;
   // guard to protect from null pointer dereference
   if (other.attr_input != nullptr)
     attr_input = other.attr_input->clone_attr_input ();
index ff307ae21134c491b5c32db107fbf1cd16bb5c2a..af3cd80245d19d169241a53804395ac403c79bf8 100644 (file)
@@ -784,7 +784,23 @@ UnsafeChecker::visit (Trait &trait)
 void
 UnsafeChecker::visit (ImplBlock &impl)
 {
-  // FIXME: Handle unsafe impls
+  bool safe = !impl.is_unsafe ();
+  // Check for unsafe-only attributes on generics and lifetimes
+  if (safe)
+    for (auto &parm : impl.get_generic_params ())
+      {
+       for (auto o_attr : parm->get_outer_attrs ())
+         {
+           rust_assert (!o_attr.is_inner_attribute ());
+
+           Rust::AST::SimplePath path = o_attr.get_path ();
+           if (path == Values::Attributes::MAY_DANGLE)
+             rust_error_at (
+               o_attr.get_locus (), ErrorCode::E0569,
+               "use of %<may_dangle%> is unsafe and requires unsafe impl");
+         }
+      }
+
   for (auto &item : impl.get_impl_items ())
     item->accept_vis (*this);
 }
index f6a73cb7121f396c47f0a0f6e3d0167754659e05..f3ad72c72374f6be069b2b4f7f239116a2d14f64 100644 (file)
@@ -542,7 +542,7 @@ ASTLoweringItem::visit (AST::InherentImpl &impl_block)
     mapping, std::move (impl_items), std::move (generic_params),
     std::unique_ptr<HIR::Type> (impl_type), nullptr, where_clause, polarity,
     vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
-    impl_block.get_locus ());
+    impl_block.get_locus (), false);
   translated = hir_impl_block;
 
   mappings.insert_hir_impl_block (hir_impl_block);
@@ -623,6 +623,7 @@ void
 ASTLoweringItem::visit (AST::TraitImpl &impl_block)
 {
   std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+  bool unsafe = impl_block.is_unsafe ();
   for (auto &item : impl_block.get_where_clause ().get_items ())
     {
       HIR::WhereClauseItem *i = ASTLowerWhereClauseItem::translate (*item);
@@ -696,7 +697,7 @@ ASTLoweringItem::visit (AST::TraitImpl &impl_block)
     std::unique_ptr<HIR::Type> (impl_type),
     std::unique_ptr<HIR::TypePath> (trait_ref), where_clause, polarity, vis,
     impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
-    impl_block.get_locus ());
+    impl_block.get_locus (), unsafe);
   translated = hir_impl_block;
 
   mappings.insert_hir_impl_block (hir_impl_block);
index 091fa031ab5f96f81fcfb41db6e82484a46b283e..ad93526644e7e8675ed1949f9cab1356b9fe4323 100644 (file)
@@ -17,6 +17,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-ast-lower-type.h"
+#include "rust-attribute-values.h"
 
 namespace Rust {
 namespace HIR {
@@ -446,16 +447,17 @@ void
 ASTLowerGenericParam::visit (AST::LifetimeParam &param)
 {
   auto crate_num = mappings.get_current_crate ();
+  AST::Lifetime lifetime = param.get_lifetime ();
   Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
                                 mappings.get_next_hir_id (crate_num),
                                 mappings.get_next_localdef_id (crate_num));
 
-  HIR::Lifetime lt (mapping, param.get_lifetime ().get_lifetime_type (),
-                   param.get_lifetime ().get_lifetime_name (),
-                   param.get_lifetime ().get_locus ());
+  HIR::Lifetime lt (mapping, lifetime.get_lifetime_type (),
+                   lifetime.get_lifetime_name (), lifetime.get_locus ());
 
   translated = new HIR::LifetimeParam (mapping, lt, param.get_locus (),
-                                      std::vector<Lifetime> ());
+                                      std::vector<Lifetime> (),
+                                      param.get_outer_attrs ());
 }
 
 void
@@ -482,7 +484,6 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam &param)
 void
 ASTLowerGenericParam::visit (AST::TypeParam &param)
 {
-  AST::Attribute outer_attr = AST::Attribute::create_empty ();
   std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
   if (param.has_type_param_bounds ())
     {
@@ -506,7 +507,8 @@ ASTLowerGenericParam::visit (AST::TypeParam &param)
   translated
     = new HIR::TypeParam (mapping, param.get_type_representation (),
                          param.get_locus (), std::move (type_param_bounds),
-                         std::unique_ptr<Type> (type), std::move (outer_attr));
+                         std::unique_ptr<Type> (type),
+                         param.get_outer_attrs ());
 }
 
 HIR::TypeParamBound *
index 57500e4169fc302fc6e44acaf4ed2bf05c682ab5..d9e02f5d2416af32cb8f7469fa72f44491153065 100644 (file)
@@ -1508,7 +1508,8 @@ void
 Dump::visit (TypeParam &e)
 {
   begin ("TypeParam");
-  put_field ("outer_attr", e.get_outer_attribute ().as_string ());
+  auto &outer_attrs = e.get_outer_attrs ();
+  do_outer_attrs (outer_attrs);
 
   put_field ("type_representation", e.get_type_representation ().as_string ());
 
index 7e0c8c6ffca914fd150ca580e2bcb07533c99ac9..86fdabd74b33b47cc4c44e61f4273af7ba8bac5b 100644 (file)
@@ -35,9 +35,7 @@ class TypePath;
 // A type generic parameter (as opposed to a lifetime generic parameter)
 class TypeParam : public GenericParam
 {
-  // bool has_outer_attribute;
-  // std::unique_ptr<Attribute> outer_attr;
-  AST::Attribute outer_attr;
+  AST::AttrVec outer_attrs;
 
   Identifier type_representation;
 
@@ -59,16 +57,16 @@ public:
   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
 
   // Returns whether the type param has an outer attribute.
-  bool has_outer_attribute () const { return !outer_attr.is_empty (); }
-  AST::Attribute &get_outer_attribute () { return outer_attr; }
+  bool has_outer_attribute () const override { return outer_attrs.size () > 0; }
+  AST::AttrVec &get_outer_attrs () override { return outer_attrs; }
 
   TypeParam (Analysis::NodeMapping mappings, Identifier type_representation,
             location_t locus = UNDEF_LOCATION,
             std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds
             = std::vector<std::unique_ptr<TypeParamBound>> (),
             std::unique_ptr<Type> type = nullptr,
-            AST::Attribute outer_attr = AST::Attribute::create_empty ())
-    : GenericParam (mappings), outer_attr (std::move (outer_attr)),
+            AST::AttrVec outer_attrs = std::vector<AST::Attribute> ())
+    : GenericParam (mappings), outer_attrs (std::move (outer_attrs)),
       type_representation (std::move (type_representation)),
       type_param_bounds (std::move (type_param_bounds)),
       type (std::move (type)), locus (locus)
@@ -76,7 +74,7 @@ public:
 
   // Copy constructor uses clone
   TypeParam (TypeParam const &other)
-    : GenericParam (other.mappings), outer_attr (other.outer_attr),
+    : GenericParam (other.mappings), outer_attrs (other.outer_attrs),
       type_representation (other.type_representation), locus (other.locus)
   {
     // guard to prevent null pointer dereference
@@ -92,7 +90,7 @@ public:
   TypeParam &operator= (TypeParam const &other)
   {
     type_representation = other.type_representation;
-    outer_attr = other.outer_attr;
+    outer_attrs = other.outer_attrs;
     locus = other.locus;
     mappings = other.mappings;
 
@@ -2741,6 +2739,7 @@ class ImplBlock : public VisItem, public WithInnerAttrs
   BoundPolarity polarity;
   location_t locus;
   std::vector<std::unique_ptr<ImplItem>> impl_items;
+  bool unsafe;
 
 public:
   ImplBlock (Analysis::NodeMapping mappings,
@@ -2749,20 +2748,20 @@ public:
             std::unique_ptr<Type> impl_type,
             std::unique_ptr<TypePath> trait_ref, WhereClause where_clause,
             BoundPolarity polarity, Visibility vis, AST::AttrVec inner_attrs,
-            AST::AttrVec outer_attrs, location_t locus)
+            AST::AttrVec outer_attrs, location_t locus, bool unsafe = false)
     : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)),
       WithInnerAttrs (std::move (inner_attrs)),
       generic_params (std::move (generic_params)),
       impl_type (std::move (impl_type)), trait_ref (std::move (trait_ref)),
       where_clause (std::move (where_clause)), polarity (polarity),
-      locus (locus), impl_items (std::move (impl_items))
+      locus (locus), impl_items (std::move (impl_items)), unsafe (unsafe)
   {}
 
   ImplBlock (ImplBlock const &other)
     : VisItem (other), WithInnerAttrs (other.inner_attrs),
       impl_type (other.impl_type->clone_type ()),
       where_clause (other.where_clause), polarity (other.polarity),
-      locus (other.locus)
+      locus (other.locus), unsafe (other.unsafe)
   {
     generic_params.reserve (other.generic_params.size ());
     for (const auto &e : other.generic_params)
@@ -2781,6 +2780,7 @@ public:
     polarity = other.polarity;
     inner_attrs = other.inner_attrs;
     locus = other.locus;
+    unsafe = other.unsafe;
 
     generic_params.reserve (other.generic_params.size ());
     for (const auto &e : other.generic_params)
@@ -2801,6 +2801,8 @@ public:
   // Returns whether inherent impl block has inherent impl items.
   bool has_impl_items () const { return !impl_items.empty (); }
 
+  bool is_unsafe () const { return unsafe; }
+
   void accept_vis (HIRFullVisitor &vis) override;
   void accept_vis (HIRStmtVisitor &vis) override;
   void accept_vis (HIRVisItemVisitor &vis) override;
index 80878fe18a1beabf3819dba189e6ac7dac1348fd..35aa5851f69d22cff23c389816e7d14d3c10e6c1 100644 (file)
@@ -2017,14 +2017,19 @@ LifetimeParam::as_string () const
 {
   std::string str ("LifetimeParam: ");
 
-  str += "\n Outer attribute: ";
-  if (!has_outer_attribute ())
+  str += "\n Outer attributes: ";
+  if (outer_attrs.empty ())
     {
       str += "none";
     }
   else
     {
-      str += outer_attr.as_string ();
+      /* note that this does not print them with "outer attribute" syntax -
+       * just the body */
+      for (const auto &attr : outer_attrs)
+       {
+         str += "\n " + attr.as_string ();
+       }
     }
 
   str += "\n Lifetime: " + lifetime.as_string ();
@@ -2106,14 +2111,19 @@ TypeParam::as_string () const
 {
   std::string str ("TypeParam: ");
 
-  str += "\n Outer attribute: ";
-  if (!has_outer_attribute ())
+  str += "\n Outer attributes: ";
+  if (outer_attrs.empty ())
     {
       str += "none";
     }
   else
     {
-      str += outer_attr.as_string ();
+      /* note that this does not print them with "outer attribute" syntax -
+       * just the body */
+      for (const auto &attr : outer_attrs)
+       {
+         str += "\n " + attr.as_string ();
+       }
     }
 
   str += "\n Identifier: " + type_representation.as_string ();
index b427f1d204dcdbddea6c1ada7034f6bc4fcb0f6e..3fb97b2f12186ac208b17094d89ee86ad6524613 100644 (file)
@@ -617,6 +617,9 @@ public:
     CONST,
   };
 
+  virtual AST::AttrVec &get_outer_attrs () = 0;
+  virtual bool has_outer_attribute () const = 0;
+
   // Unique pointer custom clone function
   std::unique_ptr<GenericParam> clone_generic_param () const
   {
@@ -654,9 +657,7 @@ class LifetimeParam : public GenericParam
   // LifetimeBounds lifetime_bounds;
   std::vector<Lifetime> lifetime_bounds; // inlined LifetimeBounds
 
-  // bool has_outer_attribute;
-  // std::unique_ptr<Attribute> outer_attr;
-  AST::Attribute outer_attr;
+  AST::AttrVec outer_attrs;
 
   location_t locus;
 
@@ -669,7 +670,9 @@ public:
   std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; }
 
   // Returns whether the lifetime param has an outer attribute.
-  bool has_outer_attribute () const { return !outer_attr.is_empty (); }
+  bool has_outer_attribute () const override { return outer_attrs.size () > 1; }
+
+  AST::AttrVec &get_outer_attrs () { return outer_attrs; }
 
   // Returns whether the lifetime param is in an error state.
   bool is_error () const { return lifetime.is_error (); }
@@ -679,11 +682,11 @@ public:
                 location_t locus = UNDEF_LOCATION,
                 std::vector<Lifetime> lifetime_bounds
                 = std::vector<Lifetime> (),
-                AST::Attribute outer_attr = AST::Attribute::create_empty ())
+                AST::AttrVec outer_attrs = std::vector<AST::Attribute> ())
     : GenericParam (mappings, GenericKind::LIFETIME),
       lifetime (std::move (lifetime)),
       lifetime_bounds (std::move (lifetime_bounds)),
-      outer_attr (std::move (outer_attr)), locus (locus)
+      outer_attrs (std::move (outer_attrs)), locus (locus)
   {}
 
   // TODO: remove copy and assignment operator definitions - not required
@@ -692,7 +695,7 @@ public:
   LifetimeParam (LifetimeParam const &other)
     : GenericParam (other.mappings, GenericKind::LIFETIME),
       lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds),
-      outer_attr (other.outer_attr), locus (other.locus)
+      outer_attrs (other.outer_attrs), locus (other.locus)
   {}
 
   // Overloaded assignment operator to clone attribute
@@ -700,7 +703,7 @@ public:
   {
     lifetime = other.lifetime;
     lifetime_bounds = other.lifetime_bounds;
-    outer_attr = other.outer_attr;
+    outer_attrs = other.outer_attrs;
     locus = other.locus;
     mappings = other.mappings;
 
@@ -748,6 +751,10 @@ public:
       default_expression = other.default_expression->clone_expr ();
   }
 
+  bool has_outer_attribute () const override { return false; }
+
+  AST::AttrVec &get_outer_attrs () override { return outer_attrs; }
+
   std::string as_string () const override final;
 
   void accept_vis (HIRFullVisitor &vis) override final;
@@ -775,6 +782,9 @@ private:
   std::string name;
   std::unique_ptr<Type> type;
 
+  /* const params have no outer attrs, should be empty */
+  AST::AttrVec outer_attrs = std::vector<AST::Attribute> ();
+
   /* Optional - can be a null pointer if there is no default expression */
   std::unique_ptr<Expr> default_expression;
 
diff --git a/gcc/testsuite/rust/compile/issue-3045-1.rs b/gcc/testsuite/rust/compile/issue-3045-1.rs
new file mode 100644 (file)
index 0000000..a1328f2
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(dropck_eyepatch)]
+#[allow(dead_code)]
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Test<T> {
+    _inner: T,
+}
+
+struct Test2<T> {
+    _inner: T,
+}
+
+trait Action {}
+
+impl<#[may_dangle] T> Action for Test<T> {} // { dg-error "use of 'may_dangle' is unsafe and requires unsafe impl" "" { target *-*-* } 0 }
+
+unsafe impl<#[may_dangle] T> Action for Test2<T> {}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issue-3045-2.rs b/gcc/testsuite/rust/compile/issue-3045-2.rs
new file mode 100644 (file)
index 0000000..177707f
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(dropck_eyepatch)]
+#[allow(dead_code)]
+
+#[lang = "sized"]
+trait Sized {}
+
+
+trait Action {}
+
+struct Inspector<'a>(&'a u8);
+struct Inspector2<'a>(&'a u8);
+
+impl<#[may_dangle] 'a> Action for Inspector<'a> {} // { dg-error "use of 'may_dangle' is unsafe and requires unsafe impl" "" { target *-*-* } 0 }
+
+unsafe impl<#[may_dangle] 'a> Action for Inspector2<'a> {}
+
+
+fn main() {
+
+}