@@ -2213,10 +2213,17 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
Type *t = arg->type->toBasetype ();
StructDeclaration *sd = t->baseElemOf ()->isTypeStruct ()->sym;
- /* Nested structs also have ADDRESSABLE set, but if the type has
- neither a copy constructor nor a destructor available, then we
- need to take care of copying its value before passing it. */
- if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor))
+ /* Need to take care of copying its value before passing the
+ argument in the following scenarios:
+ - The argument is a literal expression; a CONSTRUCTOR can't
+ have its address taken.
+ - The type has neither a copy constructor nor a destructor
+ available; nested structs also have ADDRESSABLE set.
+ - The ABI of the function expects the callee to destroy its
+ arguments; when the caller is handles destruction, then `targ'
+ has already been made into a temporary. */
+ if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)
+ || target.isCalleeDestroyingArgs (tf))
targ = force_target_expr (targ);
targ = convert (build_reference_type (TREE_TYPE (targ)),
@@ -860,10 +860,28 @@ public:
/* Maybe put variable on list of things needing destruction. */
if (d->needsScopeDtor ())
{
+ /* Rewrite: `decl = exp' => TARGET_EXPR(decl, exp, dtor). */
vec_safe_push (d_function_chain->vars_in_scope, decl);
+
/* Force a TARGET_EXPR to add the corresponding cleanup. */
- exp = force_target_expr (compound_expr (exp, decl));
- TARGET_EXPR_CLEANUP (exp) = build_expr (d->edtor);
+ if (TREE_CODE (exp) != TARGET_EXPR)
+ {
+ if (VOID_TYPE_P (TREE_TYPE (exp)))
+ exp = compound_expr (exp, decl);
+
+ exp = force_target_expr (exp);
+ }
+
+ TARGET_EXPR_CLEANUP (exp)
+ = compound_expr (TARGET_EXPR_CLEANUP (exp),
+ build_expr (d->edtor));
+
+ /* The decl is really an alias for the TARGET_EXPR slot. */
+ SET_DECL_VALUE_EXPR (decl, TARGET_EXPR_SLOT (exp));
+ DECL_HAS_VALUE_EXPR_P (decl) = 1;
+ /* This tells the gimplifier not to emit a clobber for the decl
+ as its lifetime ends when the slot gets cleaned up. */
+ TREE_ADDRESSABLE (decl) = 0;
}
add_stmt (exp);
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-do run }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+struct S113758
+{
+ int field;
+ ~this() { field = 0; }
+}
+
+void main()
+{
+ auto var = S113758(1);
+ f113758d(var);
+ assert(var.field == 1);
+ f113758cxx(var);
+ assert(var.field == 1);
+}
+
+extern (D) void f113758d(S113758 arg) { }
+extern (C++) void f113758cxx(S113758 arg) { }