From: Lishin <[email protected]>
Generate runtime Drop flags for Conditional Drops.
Use BIR analysis results to identify locals that need Drop flags and the moves
that clear those flags.
The HIR backend sets a flag when initialization, clears it after a move, and
checks it before cleanup.
gcc/rust/ChangeLog:
* backend/rust-compile-context.h
(Context::insert_drop_flag): New function.
(Context::lookup_drop_flag): Likewise.
(Context::drop_flags): New member.
* backend/rust-compile-drop-builder.cc
(DropBuilder::maybe_create_drop_flag): New function.
(DropBuilder::drop_flag_assignment): Likewise.
* backend/rust-compile-drop-builder.h
(DropBuilder::maybe_create_drop_flag): New declaration.
(DropBuilder::drop_flag_assignment): Likewise.
* backend/rust-compile-drop.cc
(CompileDrop::build_current_scope_drop_cleanup): Check Drop flags before
running conditional Drops.
* backend/rust-compile-pattern.cc
(CompilePatternLet::visit): Set the Drop flag after initialization.
* backend/rust-compile-stmt.cc
(CompileStmt::visit): Create Drop flags and clear them after moves.
* checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
(ExprStmtBuilder::visit): Pass expression HirIds to BIR.
* checks/errors/borrowck/rust-bir-builder-internal.h
(AbstractBuilder::push_assignment): Pass move-site HirIds.
(AbstractExprBuilder::return_place): Likewise.
* checks/errors/borrowck/rust-bir-drop-analysis.cc
(is_straight_line): Remove.
(record_drop_for_backend): Rename from
record_drop_for_straight_line_backend.
(annotate_drop_statements): Record conditional Drops and move
sources.
(DropAnalysis::clear): Clear the new analysis results.
(DropAnalysis::needs_drop_flag): New function.
(DropAnalysis::lookup_move_source): Likewise.
(DropAnalysis::analyze): Record results for the backend.
* checks/errors/borrowck/rust-bir-drop-analysis.h
(DropAnalysis::needs_drop_flag): New declaration.
(DropAnalysis::lookup_move_source): Likewise.
(DropAnalysis::conditionally_dropped): New member.
(DropAnalysis::move_sources): Likewise.
* checks/errors/borrowck/rust-bir.h
(Statement::make_assignment): Accept a move-site HirId.
(Statement::Statement): Likewise.
(Statement::get_move_site): New function.
(Statement::move_site): New member.
gcc/testsuite/ChangeLog:
* rust/execute/drop-conditional-move.rs: New test.
---
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/074613a4207f67b622a5ebca38c9441bce0006e5
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4798
gcc/rust/backend/rust-compile-context.h | 16 +++
gcc/rust/backend/rust-compile-drop-builder.cc | 36 ++++-
gcc/rust/backend/rust-compile-drop-builder.h | 4 +-
gcc/rust/backend/rust-compile-drop.cc | 16 ++-
gcc/rust/backend/rust-compile-pattern.cc | 8 +-
gcc/rust/backend/rust-compile-stmt.cc | 18 +++
.../borrowck/rust-bir-builder-expr-stmt.cc | 3 +-
.../borrowck/rust-bir-builder-internal.h | 15 +-
.../errors/borrowck/rust-bir-drop-analysis.cc | 132 +++++++++++-------
.../errors/borrowck/rust-bir-drop-analysis.h | 10 +-
gcc/rust/checks/errors/borrowck/rust-bir.h | 20 ++-
.../rust/execute/drop-conditional-move.rs | 100 +++++++++++++
12 files changed, 312 insertions(+), 66 deletions(-)
create mode 100644 gcc/testsuite/rust/execute/drop-conditional-move.rs
diff --git a/gcc/rust/backend/rust-compile-context.h
b/gcc/rust/backend/rust-compile-context.h
index 2c71f7778..d3d4ec744 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -145,6 +145,21 @@ public:
return true;
}
+ void insert_drop_flag (HirId id, ::Bvariable *flag)
+ {
+ drop_flags[{peek_fn ().fndecl, id}] = flag;
+ }
+
+ bool lookup_drop_flag (HirId id, ::Bvariable **flag)
+ {
+ auto it = drop_flags.find ({peek_fn ().fndecl, id});
+ if (it == drop_flags.end ())
+ return false;
+
+ *flag = it->second;
+ return true;
+ }
+
void insert_function_decl (const TyTy::FnType *ref, tree fn)
{
auto id = ref->get_ty_ref ();
@@ -504,6 +519,7 @@ private:
// state
std::vector<fncontext> fn_stack;
std::map<HirId, ::Bvariable *> compiled_var_decls;
+ std::map<std::pair<tree, HirId>, ::Bvariable *> drop_flags;
std::map<hashval_t, tree> compiled_type_map;
std::map<HirId, tree> compiled_fn_map;
std::map<HirId, tree> compiled_consts;
diff --git a/gcc/rust/backend/rust-compile-drop-builder.cc
b/gcc/rust/backend/rust-compile-drop-builder.cc
index e0947a787..8cd2bb9f2 100644
--- a/gcc/rust/backend/rust-compile-drop-builder.cc
+++ b/gcc/rust/backend/rust-compile-drop-builder.cc
@@ -18,6 +18,7 @@
#include "rust-compile-drop-builder.h"
#include "rust-compile-context.h"
+#include "rust-bir-drop-analysis.h"
namespace Rust {
namespace Compile {
@@ -31,6 +32,39 @@ DropBuilder::note_simple_drop_candidate (HirId hirid,
location_t locus)
ctx.block_drop_candidates.back ().emplace_back (hirid, locus);
}
+void
+DropBuilder::maybe_create_drop_flag (HirId hirid, location_t locus,
+ bool initialized)
+{
+ if (!BIR::DropAnalysis::get ().needs_drop_flag (hirid))
+ return;
+
+ Bvariable *existing = nullptr;
+ if (ctx.lookup_drop_flag (hirid, &existing))
+ return;
+
+ tree declaration = nullptr;
+ Bvariable *flag = Backend::temporary_variable (
+ ctx.peek_fn ().fndecl, nullptr, boolean_type_node,
+ Backend::boolean_constant_expression (initialized), false, locus,
+ &declaration);
+ ctx.add_statement (declaration);
+ ctx.insert_drop_flag (hirid, flag);
+}
+
+tree
+DropBuilder::drop_flag_assignment (HirId hirid, bool value, location_t locus)
+{
+ Bvariable *flag = nullptr;
+ if (!ctx.lookup_drop_flag (hirid, &flag))
+ return nullptr;
+
+ return Backend::assignment_statement (Backend::var_expression (flag, locus),
+ Backend::boolean_constant_expression (
+ value),
+ locus);
+}
+
std::vector<DropCandidate> &
DropBuilder::peek_block_drop_candidates ()
{
@@ -39,4 +73,4 @@ DropBuilder::peek_block_drop_candidates ()
}
} // namespace Compile
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-drop-builder.h
b/gcc/rust/backend/rust-compile-drop-builder.h
index 36e3cdc1e..6d91d3124 100644
--- a/gcc/rust/backend/rust-compile-drop-builder.h
+++ b/gcc/rust/backend/rust-compile-drop-builder.h
@@ -32,6 +32,8 @@ public:
DropBuilder (Context &ctx);
void note_simple_drop_candidate (HirId hirid, location_t locus);
+ void maybe_create_drop_flag (HirId hirid, location_t locus, bool
initialized);
+ tree drop_flag_assignment (HirId hirid, bool value, location_t locus);
std::vector<DropCandidate> &peek_block_drop_candidates ();
private:
@@ -41,4 +43,4 @@ private:
} // namespace Compile
} // namespace Rust
-#endif // RUST_COMPILE_DROP_BUILDER_H
\ No newline at end of file
+#endif // RUST_COMPILE_DROP_BUILDER_H
diff --git a/gcc/rust/backend/rust-compile-drop.cc
b/gcc/rust/backend/rust-compile-drop.cc
index ca4e63f88..7e54b4cf9 100644
--- a/gcc/rust/backend/rust-compile-drop.cc
+++ b/gcc/rust/backend/rust-compile-drop.cc
@@ -115,7 +115,21 @@ CompileDrop::build_current_scope_drop_cleanup ()
tree drop_call = compile_drop_call (var, ty, it->locus);
if (drop_call != NULL_TREE)
- drop_stmts.push_back (convert_to_void (drop_call, ICV_STATEMENT));
+ {
+ tree drop_stmt = convert_to_void (drop_call, ICV_STATEMENT);
+ Bvariable *flag = nullptr;
+ if (ctx->lookup_drop_flag (it->hirid, &flag))
+ {
+ tree condition = Backend::var_expression (flag, it->locus);
+ tree clear = drop_builder.drop_flag_assignment (it->hirid, false,
+ it->locus);
+ tree guarded_drop = Backend::statement_list ({clear, drop_stmt});
+ drop_stmt
+ = Backend::if_statement (ctx->peek_fn ().fndecl, condition,
+ guarded_drop, NULL_TREE, it->locus);
+ }
+ drop_stmts.push_back (drop_stmt);
+ }
}
if (drop_stmts.empty ())
diff --git a/gcc/rust/backend/rust-compile-pattern.cc
b/gcc/rust/backend/rust-compile-pattern.cc
index 9d722358b..82cabef78 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -1353,6 +1353,13 @@ CompilePatternLet::visit (HIR::IdentifierPattern
&pattern)
ctx->add_statement (s);
}
+ DropBuilder drop_builder (*ctx);
+ tree set_drop_flag
+ = drop_builder.drop_flag_assignment (pattern.get_mappings ().get_hirid (),
+ true, pattern.get_locus ());
+ if (set_drop_flag != nullptr)
+ ctx->add_statement (set_drop_flag);
+
TyTy::BaseType *drop_ty = ty;
if (pattern.get_is_ref ())
{
@@ -1366,7 +1373,6 @@ CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
if (!pattern.has_subpattern () && !pattern.get_is_ref ())
{
- DropBuilder drop_builder (*ctx);
drop_builder.note_simple_drop_candidate (
pattern.get_mappings ().get_hirid (), pattern.get_locus ());
}
diff --git a/gcc/rust/backend/rust-compile-stmt.cc
b/gcc/rust/backend/rust-compile-stmt.cc
index 7f6e81ff8..78b87b5b4 100644
--- a/gcc/rust/backend/rust-compile-stmt.cc
+++ b/gcc/rust/backend/rust-compile-stmt.cc
@@ -21,6 +21,9 @@
#include "rust-compile-expr.h"
#include "rust-compile-type.h"
#include "rust-compile-var-decl.h"
+#include "rust-compile-drop.h"
+#include "rust-compile-drop-builder.h"
+#include "rust-bir-drop-analysis.h"
namespace Rust {
namespace Compile {
@@ -67,6 +70,11 @@ CompileStmt::visit (HIR::LetStmt &stmt)
tree translated_type = TyTyResolveCompile::compile (ctx, ty);
CompileVarDecl::compile (fndecl, translated_type, &stmt_pattern, ctx);
+ if (stmt_pattern.get_pattern_type () == HIR::Pattern::IDENTIFIER
+ && CompileDrop (ctx).type_has_drop_impl (ty))
+ DropBuilder (*ctx).maybe_create_drop_flag (stmt_id, stmt.get_locus (),
+ false);
+
// nothing to do
if (!stmt.has_init_expr ())
return;
@@ -89,6 +97,16 @@ CompileStmt::visit (HIR::LetStmt &stmt)
expected, lvalue_locus, rvalue_locus);
CompilePatternLet::Compile (&stmt_pattern, init, ty, rvalue_locus, ctx);
+
+ HirId source = UNKNOWN_HIRID;
+ if (BIR::DropAnalysis::get ().lookup_move_source (
+ stmt.get_init_expr ().get_mappings ().get_hirid (), &source))
+ {
+ tree clear
+ = DropBuilder (*ctx).drop_flag_assignment (source, false, rvalue_locus);
+ if (clear != nullptr)
+ ctx->add_statement (clear);
+ }
}
} // namespace Compile
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
index b58f2cfe9..889e4611e 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
@@ -703,7 +703,8 @@ ExprStmtBuilder::visit (HIR::PathInExpression &expr)
{
// Note: Type is only stored for the expr, not the segment.
PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr));
- return_place (result, expr.get_locus ());
+ return_place (result, expr.get_locus (), false,
+ expr.get_mappings ().get_hirid ());
}
void
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
index eabfdc6af..b5644741d 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
@@ -265,16 +265,18 @@ protected:
}
protected: // Helpers to add BIR statements
- void push_assignment (PlaceId lhs, AbstractExpr *rhs, location_t location)
+ void push_assignment (PlaceId lhs, AbstractExpr *rhs, location_t location,
+ tl::optional<HirId> move_site = tl::nullopt)
{
ctx.get_current_bb ().statements.push_back (
- Statement::make_assignment (lhs, rhs, location));
+ Statement::make_assignment (lhs, rhs, location, move_site));
translated = lhs;
}
- void push_assignment (PlaceId lhs, PlaceId rhs, location_t location)
+ void push_assignment (PlaceId lhs, PlaceId rhs, location_t location,
+ tl::optional<HirId> move_site = tl::nullopt)
{
- push_assignment (lhs, new Assignment (rhs), location);
+ push_assignment (lhs, new Assignment (rhs), location, move_site);
}
void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty,
@@ -600,12 +602,13 @@ protected:
}
/** Mark place to be a result of processed subexpression. */
- void return_place (PlaceId place, location_t location, bool can_panic =
false)
+ void return_place (PlaceId place, location_t location, bool can_panic =
false,
+ tl::optional<HirId> move_site = tl::nullopt)
{
if (expr_return_place != INVALID_PLACE)
{
// Return place is already allocated, no need to defer assignment.
- push_assignment (expr_return_place, place, location);
+ push_assignment (expr_return_place, place, location, move_site);
}
else
{
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.cc
b/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.cc
index 2bdf5e5e4..22be1553e 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.cc
@@ -38,31 +38,13 @@ struct BlockInitializationState
bool reachable;
};
-static bool
-is_straight_line (const Function &function)
+struct DropAnalysisResults
{
- std::set<BasicBlockId> visited;
- BasicBlockId current = ENTRY_BASIC_BLOCK;
-
- while (current != INVALID_BB)
- {
- // Revisiting a block means that the CFG contains a cycle.
- if (!visited.insert (current).second)
- return false;
-
- const BasicBlock &block = function.basic_blocks[current];
-
- if (block.successors.empty ())
- return true;
-
- if (block.successors.size () != 1)
- return false;
-
- current = block.successors.front ();
- }
-
- return true;
-}
+ std::unordered_set<HirId> dead_drop_hir_ids;
+ std::unordered_set<HirId> static_drop_hir_ids;
+ std::unordered_set<HirId> conditional_drop_hir_ids;
+ std::unordered_map<HirId, HirId> move_sources;
+};
static void
set_initialized (BlockInitializationState &state, PlaceId place)
@@ -247,10 +229,9 @@ compute_entry_states (Function &function)
}
static void
-record_drop_for_straight_line_backend (const Function &function, PlaceId place,
- Statement::DropStyle drop_style,
- std::set<HirId> &dead_drop_hir_ids,
- std::set<HirId> &non_dead_drop_hir_ids)
+record_drop_for_backend (const Function &function, PlaceId place,
+ Statement::DropStyle drop_style,
+ DropAnalysisResults &results)
{
const Place &dropped_place = function.place_db[place];
@@ -263,10 +244,23 @@ record_drop_for_straight_line_backend (const Function
&function, PlaceId place,
if (!hir_id.has_value ())
return;
- if (drop_style == Statement::DropStyle::DEAD)
- dead_drop_hir_ids.insert (hir_id.value ());
- else
- non_dead_drop_hir_ids.insert (hir_id.value ());
+ switch (drop_style)
+ {
+ case Statement::DropStyle::UNCLASSIFIED:
+ break;
+
+ case Statement::DropStyle::DEAD:
+ results.dead_drop_hir_ids.insert (hir_id.value ());
+ break;
+
+ case Statement::DropStyle::STATIC:
+ results.static_drop_hir_ids.insert (hir_id.value ());
+ break;
+
+ case Statement::DropStyle::CONDITIONAL:
+ results.conditional_drop_hir_ids.insert (hir_id.value ());
+ break;
+ }
}
// Walk each reachable block forward from its stable entry state and classify
@@ -274,8 +268,7 @@ record_drop_for_straight_line_backend (const Function
&function, PlaceId place,
static void
annotate_drop_statements (
Function &function, const std::vector<BlockInitializationState>
&entry_states,
- bool record_straight_line_backend_drops, std::set<HirId> &dead_drop_hir_ids,
- std::set<HirId> &non_dead_drop_hir_ids)
+ DropAnalysisResults &results)
{
const size_t block_count = function.basic_blocks.size ();
@@ -291,6 +284,29 @@ annotate_drop_statements (
for (Statement &statement : block.statements)
{
+ const auto &move_site = statement.get_move_site ();
+ if (statement.get_kind () == Statement::Kind::ASSIGNMENT
+ && move_site.has_value ())
+ {
+ AbstractExpr &expr = statement.get_expr ();
+ if (expr.get_kind () == ExprKind::ASSIGNMENT)
+ {
+ PlaceId rhs = static_cast<Assignment &> (expr).get_rhs ();
+ const Place &rhs_place = function.place_db[rhs];
+ if (rhs_place.kind == Place::VARIABLE
+ && rhs_place.should_be_moved ())
+ {
+ auto hirid
+ = Analysis::Mappings::get ().lookup_node_to_hir (
+ static_cast<NodeId> (
+ rhs_place.variable_or_field_index));
+ if (hirid.has_value ())
+ results.move_sources[move_site.value ()]
+ = hirid.value ();
+ }
+ }
+ }
+
// A Drop is classified using the state before it executes.
if (statement.get_kind () == Statement::Kind::DROP)
{
@@ -299,11 +315,7 @@ annotate_drop_statements (
statement.set_drop_style (drop_style);
- if (record_straight_line_backend_drops)
- record_drop_for_straight_line_backend (function, place,
- drop_style,
- dead_drop_hir_ids,
- non_dead_drop_hir_ids);
+ record_drop_for_backend (function, place, drop_style, results);
}
// Update the state for the following statement.
@@ -325,6 +337,8 @@ void
DropAnalysis::clear ()
{
definitely_dead.clear ();
+ conditionally_dropped.clear ();
+ move_sources.clear ();
}
bool
@@ -333,26 +347,44 @@ DropAnalysis::is_definitely_dead (HirId id) const
return definitely_dead.find (id) != definitely_dead.end ();
}
+bool
+DropAnalysis::needs_drop_flag (HirId id) const
+{
+ return conditionally_dropped.find (id) != conditionally_dropped.end ();
+}
+
+bool
+DropAnalysis::lookup_move_source (HirId move_site, HirId *source) const
+{
+ auto it = move_sources.find (move_site);
+ if (it == move_sources.end ())
+ return false;
+
+ *source = it->second;
+ return true;
+}
+
void
DropAnalysis::analyze (Function &function)
{
std::vector<BlockInitializationState> entry_states
= compute_entry_states (function);
- // Keep the existing backend handling for straight-line CFGs.
- const bool record_straight_line_backend_drops = is_straight_line (function);
-
- std::set<HirId> dead_drop_hir_ids;
- std::set<HirId> non_dead_drop_hir_ids;
-
- annotate_drop_statements (function, entry_states,
- record_straight_line_backend_drops,
- dead_drop_hir_ids, non_dead_drop_hir_ids);
+ DropAnalysisResults results;
+ annotate_drop_statements (function, entry_states, results);
// A local is definitely dead only when all of its Drops are dead.
- for (HirId hir_id : dead_drop_hir_ids)
- if (non_dead_drop_hir_ids.find (hir_id) == non_dead_drop_hir_ids.end ())
+ for (HirId hir_id : results.dead_drop_hir_ids)
+ if (results.static_drop_hir_ids.find (hir_id)
+ == results.static_drop_hir_ids.end ()
+ && results.conditional_drop_hir_ids.find (hir_id)
+ == results.conditional_drop_hir_ids.end ())
definitely_dead.insert (hir_id);
+
+ conditionally_dropped.insert (results.conditional_drop_hir_ids.begin (),
+ results.conditional_drop_hir_ids.end ());
+ move_sources.insert (results.move_sources.begin (),
+ results.move_sources.end ());
}
} // namespace BIR
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.h
b/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.h
index 17a175e08..45cb1e2f8 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-drop-analysis.h
@@ -19,6 +19,7 @@
#ifndef RUST_BIR_DROP_ANALYSIS_H
#define RUST_BIR_DROP_ANALYSIS_H
+#include "rust-system.h"
#include "rust-bir.h"
namespace Rust {
@@ -39,9 +40,16 @@ public:
void analyze (Function &function);
bool is_definitely_dead (HirId id) const;
+ bool needs_drop_flag (HirId id) const;
+ bool lookup_move_source (HirId move_site, HirId *source) const;
private:
- std::set<HirId> definitely_dead;
+ std::unordered_set<HirId> definitely_dead;
+ std::unordered_set<HirId> conditionally_dropped;
+ // This may need to be extended to
+ // std::unordered_map<HirId, std::unordered_set<HirId>>
+ // to support product moves in the future.
+ std::unordered_map<HirId, HirId> move_sources;
};
} // namespace BIR
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir.h
b/gcc/rust/checks/errors/borrowck/rust-bir.h
index 581f66165..f03cdcc14 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir.h
@@ -21,6 +21,7 @@
#include "rust-bir-place.h"
#include "rust-bir-visitor.h"
+#include "optional.h"
#include "polonius/rust-polonius-ffi.h"
#include "rust-tyty-variance-analysis.h"
@@ -113,12 +114,17 @@ private:
// currently only available when kind is ASSIGNMENT | RETURN
// FIXME: Add location for other statement kinds
location_t location;
+ // HIR expression which consumes the RHS of an assignment. This is used to
+ // attach backend drop-flag updates to the corresponding expression.
+ tl::optional<HirId> move_site;
public:
static Statement make_assignment (PlaceId place, AbstractExpr *rhs,
- location_t location)
+ location_t location,
+ tl::optional<HirId> move_site = tl::nullopt)
{
- return Statement (Kind::ASSIGNMENT, place, rhs, nullptr, location);
+ return Statement (Kind::ASSIGNMENT, place, rhs, nullptr, location,
+ move_site);
}
static Statement make_switch (PlaceId place)
{
@@ -155,8 +161,10 @@ private:
// compelete constructor, used by make_* functions
Statement (Kind kind, PlaceId place = INVALID_PLACE,
AbstractExpr *rhs = nullptr, TyTy::BaseType *type = nullptr,
- location_t location = UNKNOWN_LOCATION)
- : kind (kind), place (place), expr (rhs), type (type), location (location)
+ location_t location = UNKNOWN_LOCATION,
+ tl::optional<HirId> move_site = tl::nullopt)
+ : kind (kind), place (place), expr (rhs), type (type), location (location),
+ move_site (move_site)
{}
public:
@@ -167,6 +175,10 @@ public:
WARN_UNUSED_RESULT AbstractExpr &get_expr () const { return *expr; }
WARN_UNUSED_RESULT TyTy::BaseType *get_type () const { return type; }
WARN_UNUSED_RESULT location_t get_location () const { return location; }
+ WARN_UNUSED_RESULT const tl::optional<HirId> &get_move_site () const
+ {
+ return move_site;
+ }
};
struct BasicBlock
diff --git a/gcc/testsuite/rust/execute/drop-conditional-move.rs
b/gcc/testsuite/rust/execute/drop-conditional-move.rs
new file mode 100644
index 000000000..cb28625f9
--- /dev/null
+++ b/gcc/testsuite/rust/execute/drop-conditional-move.rs
@@ -0,0 +1,100 @@
+// { dg-output "^drop\r*\nafter conditional\r*\nafter
conditional\r*\ndrop\r*\nafter static\r*\ndrop\r*\nafter
static\r*\ndrop\r*\ndrop\r*\ndrop\r*\n$" }
+// { dg-additional-options "-frust-borrowcheck -w" }
+
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "drop"]
+pub trait Drop {
+ fn drop(&mut self);
+}
+
+struct Droppable {
+ value: i32,
+}
+
+struct AfterConditional {
+ value: i32,
+}
+
+struct AfterStatic {
+ value: i32,
+}
+
+impl Drop for Droppable {
+ fn drop(&mut self) {
+ let msg = "drop\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for AfterConditional {
+ fn drop(&mut self) {
+ let msg = "after conditional\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+impl Drop for AfterStatic {
+ fn drop(&mut self) {
+ let msg = "after static\n\0" as *const str as *const i8;
+ unsafe {
+ printf(msg);
+ }
+ }
+}
+
+fn conditional_move(condition: bool) {
+ let x = Droppable { value: 1 };
+
+ if condition {
+ let _y = x;
+ }
+
+ let _after = AfterConditional { value: 0 };
+}
+
+fn static_after_join(condition: bool) {
+ let _x = Droppable { value: 2 };
+
+ if condition {
+ let _n = 1;
+ }
+
+ let _after = AfterStatic { value: 0 };
+}
+
+fn move_on_both_branches(condition: bool) {
+ let x = Droppable { value: 3 };
+
+ if condition {
+ let _y = x;
+ } else {
+ let _z = x;
+ }
+}
+
+fn main() -> i32 {
+ conditional_move(true);
+ conditional_move(false);
+
+ static_after_join(true);
+ static_after_join(false);
+
+ move_on_both_branches(true);
+ move_on_both_branches(false);
+
+ 0
+}
\ No newline at end of file
base-commit: 63ea23dca8c1175c3e2b6a069f3ce1396196cee9
--
2.55.0