public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Set TREE_ADDRESSABLE when we need to borrow any expression
@ 2022-06-08 11:53 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 11:53 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8b36f2b80ebd0e0304b6df4020b5992640662667

commit 8b36f2b80ebd0e0304b6df4020b5992640662667
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Tue Nov 23 17:09:52 2021 +0000

    Set TREE_ADDRESSABLE when we need to borrow any expression
    
    GCC requires VAR_DECL's and PARAM_DECL's to be marked with TREE_ADDRESSABLE
    when the declaration will be used in borrow's ('&' getting the address).
    This takes into account the implicit addresses when we do autoderef in
    method resolution/operator-overloading.
    
    This patch keeps a seperate side table for the VAR_DECL/PARAM_DECL hir-id's
    for lookup. The typechecker marks these id's using
    
      AddressTakenResolver::SetAddressTaken (HIR::Expr&);
    
    Its quite simple as it only cares about paths such as:
    
    - PathInExpression
    - QualifiedPathInExpression
    - IdentifierExpression
    
    The rest of the expression types will be folded into temporary values
    anyway so they don't need to be marked as needs_address.
    
    Fixes #804

Diff:
---
 gcc/rust/Make-lang.in                              |   1 +
 gcc/rust/backend/rust-compile-fnparam.h            |  33 +++--
 gcc/rust/backend/rust-compile-var-decl.h           |  23 +--
 gcc/rust/hir/tree/rust-hir-item.h                  |   2 +-
 gcc/rust/typecheck/rust-autoderef.h                |  27 +++-
 gcc/rust/typecheck/rust-hir-address-taken.cc       |  65 +++++++++
 gcc/rust/typecheck/rust-hir-address-taken.h        | 159 +++++++++++++++++++++
 gcc/rust/typecheck/rust-hir-type-check-expr.h      |  18 ++-
 .../rust/execute/torture/operator_overload_6.rs    |  40 ++++++
 9 files changed, 344 insertions(+), 24 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index f0e9bc33825..6aaa0fc3227 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -86,6 +86,7 @@ GRS_OBJS = \
     rust/rust-hir-const-fold.o \
     rust/rust-hir-type-check-type.o \
     rust/rust-hir-type-check-struct.o \
+    rust/rust-hir-address-taken.o \
     rust/rust-substitution-mapper.o \
     rust/rust-lint-marklive.o \
     rust/rust-hir-type-check-path.o \
diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h
index 629f0f5a873..126b49f690e 100644
--- a/gcc/rust/backend/rust-compile-fnparam.h
+++ b/gcc/rust/backend/rust-compile-fnparam.h
@@ -20,6 +20,7 @@
 #define RUST_COMPILE_FNPARAM
 
 #include "rust-compile-base.h"
+#include "rust-hir-address-taken.h"
 
 namespace Rust {
 namespace Compile {
@@ -33,9 +34,9 @@ public:
 			     HIR::FunctionParam *param, tree decl_type,
 			     Location locus)
   {
-    CompileFnParam compiler (ctx, fndecl, decl_type, locus);
+    CompileFnParam compiler (ctx, fndecl, decl_type, locus, *param);
     param->get_param_name ()->accept_vis (compiler);
-    return compiler.translated;
+    return compiler.compiled_param;
   }
 
   void visit (HIR::IdentifierPattern &pattern) override
@@ -43,23 +44,31 @@ public:
     if (!pattern.is_mut ())
       decl_type = ctx->get_backend ()->immutable_type (decl_type);
 
-    translated
+    bool address_taken = false;
+    address_taken_context->lookup_addess_taken (
+      param.get_mappings ().get_hirid (), &address_taken);
+
+    compiled_param
       = ctx->get_backend ()->parameter_variable (fndecl, pattern.variable_ident,
-						 decl_type,
-						 false /* address_taken */,
+						 decl_type, address_taken,
 						 locus);
   }
 
 private:
-  CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus)
+  CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus,
+		  const HIR::FunctionParam &param)
     : HIRCompileBase (ctx), fndecl (fndecl), decl_type (decl_type),
-      locus (locus), translated (nullptr)
+      locus (locus), param (param),
+      compiled_param (ctx->get_backend ()->error_variable ()),
+      address_taken_context (Resolver::AddressTakenContext::get ())
   {}
 
   tree fndecl;
   tree decl_type;
   Location locus;
-  ::Bvariable *translated;
+  const HIR::FunctionParam &param;
+  Bvariable *compiled_param;
+  const Resolver::AddressTakenContext *address_taken_context;
 };
 
 class CompileSelfParam : public HIRCompileBase
@@ -74,9 +83,13 @@ public:
     if (is_immutable)
       decl_type = ctx->get_backend ()->immutable_type (decl_type);
 
+    const auto &address_taken_context = Resolver::AddressTakenContext::get ();
+    bool address_taken = false;
+    address_taken_context->lookup_addess_taken (
+      self.get_mappings ().get_hirid (), &address_taken);
+
     return ctx->get_backend ()->parameter_variable (fndecl, "self", decl_type,
-						    false /* address_taken */,
-						    locus);
+						    address_taken, locus);
   }
 };
 
diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h
index a964fa2206b..097f5b8af38 100644
--- a/gcc/rust/backend/rust-compile-var-decl.h
+++ b/gcc/rust/backend/rust-compile-var-decl.h
@@ -20,6 +20,7 @@
 #define RUST_COMPILE_VAR_DECL
 
 #include "rust-compile-base.h"
+#include "rust-hir-address-taken.h"
 
 namespace Rust {
 namespace Compile {
@@ -33,10 +34,9 @@ public:
   {
     CompileVarDecl compiler (ctx, fndecl);
     stmt->accept_vis (compiler);
-    rust_assert (compiler.translated != nullptr);
     ctx->insert_var_decl (stmt->get_mappings ().get_hirid (),
-			  compiler.translated);
-    return compiler.translated;
+			  compiler.compiled_variable);
+    return compiler.compiled_variable;
   }
 
   void visit (HIR::LetStmt &stmt) override
@@ -47,6 +47,8 @@ public:
 					      &resolved_type);
     rust_assert (ok);
 
+    address_taken_context->lookup_addess_taken (
+      stmt.get_mappings ().get_hirid (), &address_taken);
     translated_type = TyTyResolveCompile::compile (ctx, resolved_type);
     stmt.get_pattern ()->accept_vis (*this);
   }
@@ -56,22 +58,27 @@ public:
     if (!pattern.is_mut ())
       translated_type = ctx->get_backend ()->immutable_type (translated_type);
 
-    translated
+    compiled_variable
       = ctx->get_backend ()->local_variable (fndecl, pattern.variable_ident,
 					     translated_type, NULL /*decl_var*/,
-					     false /*address_taken*/, locus);
+					     address_taken, locus);
   }
 
 private:
   CompileVarDecl (Context *ctx, tree fndecl)
-    : HIRCompileBase (ctx), fndecl (fndecl), translated_type (nullptr),
-      translated (nullptr)
+    : HIRCompileBase (ctx), fndecl (fndecl),
+      translated_type (ctx->get_backend ()->error_type ()),
+      compiled_variable (ctx->get_backend ()->error_variable ()),
+      address_taken (false),
+      address_taken_context (Resolver::AddressTakenContext::get ())
   {}
 
   tree fndecl;
   tree translated_type;
   Location locus;
-  ::Bvariable *translated;
+  Bvariable *compiled_variable;
+  bool address_taken;
+  const Resolver::AddressTakenContext *address_taken_context;
 };
 
 } // namespace Compile
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 0dd7ac80b65..99a3c48d4bd 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -560,7 +560,7 @@ public:
 
   Type *get_type () { return type.get (); }
 
-  Analysis::NodeMapping &get_mappings () { return mappings; }
+  const Analysis::NodeMapping &get_mappings () const { return mappings; }
 };
 
 // Visibility of item - if the item has it, then it is some form of public
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
index db347551e84..ef3827d0995 100644
--- a/gcc/rust/typecheck/rust-autoderef.h
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -73,32 +73,51 @@ class Adjuster
 public:
   Adjuster (const TyTy::BaseType *ty) : base (ty) {}
 
-  TyTy::BaseType *adjust_type (std::vector<Adjustment> adjustments)
+  static bool needs_address (const std::vector<Adjustment> &adjustments)
+  {
+    for (auto &adjustment : adjustments)
+      {
+	switch (adjustment.get_type ())
+	  {
+	  case Adjustment::AdjustmentType::IMM_REF:
+	  case Adjustment::AdjustmentType::MUT_REF:
+	    return true;
+
+	  default:
+	    break;
+	  }
+      }
+
+    return false;
+  }
+
+  TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments)
   {
     TyTy::BaseType *ty = base->clone ();
     for (auto &adjustment : adjustments)
       {
 	switch (adjustment.get_type ())
 	  {
-	  case Resolver::Adjustment::AdjustmentType::IMM_REF:
+	  case Adjustment::AdjustmentType::IMM_REF:
 	    ty = new TyTy::ReferenceType (ty->get_ref (),
 					  TyTy::TyVar (ty->get_ref ()),
 					  Mutability::Imm);
 	    break;
 
-	  case Resolver::Adjustment::AdjustmentType::MUT_REF:
+	  case Adjustment::AdjustmentType::MUT_REF:
 	    ty = new TyTy::ReferenceType (ty->get_ref (),
 					  TyTy::TyVar (ty->get_ref ()),
 					  Mutability::Mut);
 	    break;
 
-	  case Resolver::Adjustment::AdjustmentType::DEREF_REF:
+	  case Adjustment::AdjustmentType::DEREF_REF:
 	    // FIXME this really needs to support deref lang-item operator
 	    // overloads
 	    rust_assert (ty->get_kind () == TyTy::TypeKind::REF);
 	    const TyTy::ReferenceType *rr
 	      = static_cast<const TyTy::ReferenceType *> (ty);
 	    ty = rr->get_base ();
+
 	    break;
 	  }
       }
diff --git a/gcc/rust/typecheck/rust-hir-address-taken.cc b/gcc/rust/typecheck/rust-hir-address-taken.cc
new file mode 100644
index 00000000000..ae77763efb2
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-address-taken.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-hir-address-taken.h"
+#include "rust-hir-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+AddressTakenContext *
+AddressTakenContext::get ()
+{
+  static AddressTakenContext *instance;
+  if (instance == nullptr)
+    instance = new AddressTakenContext ();
+
+  return instance;
+}
+
+AddressTakenContext::~AddressTakenContext () {}
+
+bool
+AddressTakenContext::lookup_addess_taken (HirId id, bool *address_taken) const
+{
+  const auto &it = ctx.find (id);
+  if (it == ctx.end ())
+    return false;
+
+  *address_taken = it->second;
+  return true;
+}
+
+void
+AddressTakenContext::insert_address_taken (HirId id, bool address_taken)
+{
+  const auto &it = ctx.find (id);
+  if (it != ctx.end ())
+    {
+      // assert that we never change a true result to a negative
+      if (it->second == true)
+	{
+	  rust_assert (address_taken != false);
+	}
+    }
+
+  ctx[id] = address_taken;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-address-taken.h b/gcc/rust/typecheck/rust-hir-address-taken.h
new file mode 100644
index 00000000000..19cbdef3cbf
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-address-taken.h
@@ -0,0 +1,159 @@
+// Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_ADDRESS_TAKEN
+#define RUST_HIR_ADDRESS_TAKEN
+
+#include "rust-hir-type-check-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class AddressTakenContext
+{
+public:
+  static AddressTakenContext *get ();
+
+  ~AddressTakenContext ();
+
+  bool lookup_addess_taken (HirId id, bool *address_taken) const;
+
+  void insert_address_taken (HirId id, bool address_taken);
+
+private:
+  std::map<HirId, bool> ctx;
+};
+
+class AddressTakenResolver : public TypeCheckBase
+{
+  using Rust::Resolver::TypeCheckBase::visit;
+
+public:
+  static void SetAddressTaken (HIR::Expr &expr)
+  {
+    AddressTakenResolver resolver;
+    expr.accept_vis (resolver);
+  }
+
+  void visit (HIR::IdentifierExpr &expr) override
+  {
+    NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
+    NodeId ref_node_id = UNKNOWN_NODEID;
+    if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+      {
+	// these ref_node_ids will resolve to a pattern declaration but we are
+	// interested in the definition that this refers to get the parent id
+	Definition def;
+	if (!resolver->lookup_definition (ref_node_id, &def))
+	  {
+	    rust_error_at (expr.get_locus (),
+			   "unknown reference for resolved name");
+	    return;
+	  }
+	ref_node_id = def.parent;
+      }
+
+    if (ref_node_id == UNKNOWN_NODEID)
+      return;
+
+    // node back to HIR
+    HirId ref = UNKNOWN_HIRID;
+    bool reverse_lookup
+      = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+				      ref_node_id, &ref);
+    rust_assert (reverse_lookup);
+    context->insert_address_taken (ref, true);
+  }
+
+  void visit (HIR::PathInExpression &expr) override
+  {
+    NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
+    NodeId ref_node_id = UNKNOWN_NODEID;
+    if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+      {
+	// these ref_node_ids will resolve to a pattern declaration but we are
+	// interested in the definition that this refers to get the parent id
+	Definition def;
+	if (!resolver->lookup_definition (ref_node_id, &def))
+	  {
+	    rust_error_at (expr.get_locus (),
+			   "unknown reference for resolved name");
+	    return;
+	  }
+	ref_node_id = def.parent;
+      }
+
+    if (ref_node_id == UNKNOWN_NODEID)
+      return;
+
+    // node back to HIR
+    HirId ref = UNKNOWN_HIRID;
+    bool reverse_lookup
+      = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+				      ref_node_id, &ref);
+    rust_assert (reverse_lookup);
+    context->insert_address_taken (ref, true);
+  }
+
+  void visit (HIR::QualifiedPathInExpression &expr) override
+  {
+    NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
+    NodeId ref_node_id = UNKNOWN_NODEID;
+    if (resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+      {
+	// these ref_node_ids will resolve to a pattern declaration but we are
+	// interested in the definition that this refers to get the parent id
+	Definition def;
+	if (!resolver->lookup_definition (ref_node_id, &def))
+	  {
+	    rust_error_at (expr.get_locus (),
+			   "unknown reference for resolved name");
+	    return;
+	  }
+	ref_node_id = def.parent;
+      }
+
+    if (ref_node_id == UNKNOWN_NODEID)
+      return;
+
+    // node back to HIR
+    HirId ref = UNKNOWN_HIRID;
+    bool reverse_lookup
+      = mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
+				      ref_node_id, &ref);
+    rust_assert (reverse_lookup);
+    context->insert_address_taken (ref, true);
+  }
+
+  void visit (HIR::DereferenceExpr &expr) override
+  {
+    expr.get_expr ()->accept_vis (*this);
+  }
+
+private:
+  AddressTakenResolver ()
+    : TypeCheckBase (), context (AddressTakenContext::get ())
+  {}
+
+  AddressTakenContext *context;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_ADDRESS_TAKEN
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 9eef755e140..fb1cd972293 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -31,6 +31,7 @@
 #include "rust-hir-trait-resolve.h"
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-dot-operator.h"
+#include "rust-hir-address-taken.h"
 
 namespace Rust {
 namespace Resolver {
@@ -313,6 +314,10 @@ public:
     Adjuster adj (receiver_tyty);
     TyTy::BaseType *adjusted_self = adj.adjust_type (adjustments);
 
+    // mark the required tree addressable
+    if (Adjuster::needs_address (adjustments))
+      AddressTakenResolver::SetAddressTaken (*expr.get_receiver ().get ());
+
     // store the adjustments for code-generation to know what to do
     context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
 					std::move (adjustments));
@@ -1191,11 +1196,18 @@ public:
     TyTy::BaseType *resolved_base
       = TypeCheckExpr::Resolve (expr.get_expr ().get (), false);
 
-    // FIXME double_reference
+    if (expr.get_is_double_borrow ())
+      {
+	// FIXME double_reference
+	gcc_unreachable ();
+      }
 
     infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
 				       TyTy::TyVar (resolved_base->get_ref ()),
 				       expr.get_mut ());
+
+    // mark the borrowed as address_taken
+    AddressTakenResolver::SetAddressTaken (*expr.get_expr ().get ());
   }
 
   void visit (HIR::DereferenceExpr &expr) override
@@ -1277,6 +1289,10 @@ protected:
     PathProbeCandidate *resolved_candidate
       = MethodResolution::Select (candidates, lhs, adjustments);
 
+    // mark the required tree addressable
+    if (Adjuster::needs_address (adjustments))
+      AddressTakenResolver::SetAddressTaken (*expr.get_expr ().get ());
+
     // is this the case we are recursive
     // handle the case where we are within the impl block for this lang_item
     // otherwise we end up with a recursive operator overload such as the i32
diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_6.rs b/gcc/testsuite/rust/execute/torture/operator_overload_6.rs
new file mode 100644
index 00000000000..f6ad5c41316
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/operator_overload_6.rs
@@ -0,0 +1,40 @@
+/* { dg-output "add_assign\n3\n" } */
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+#[lang = "add_assign"]
+pub trait AddAssign<Rhs = Self> {
+    fn add_assign(&mut self, rhs: Rhs);
+    // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+    // { dg-warning "unused name .rhs." "" { target *-*-* } .-2 }
+    // { dg-warning "unused name .AddAssign::add_assign." "" { target *-*-* } .-3 }
+}
+
+impl AddAssign for i32 {
+    fn add_assign(&mut self, other: i32) {
+        unsafe {
+            let a = "add_assign\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+        *self += other
+    }
+}
+
+fn main() -> i32 {
+    let mut res = 1;
+    res += 2;
+
+    unsafe {
+        let a = "%i\n\0";
+        let b = a as *const str;
+        let c = b as *const i8;
+
+        printf(c, res);
+    }
+
+    0
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 11:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 11:53 [gcc/devel/rust/master] Set TREE_ADDRESSABLE when we need to borrow any expression Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).