return r;
}
+/* Return true iff T refers to a base field. */
+
+static bool
+is_base_field_ref (tree t)
+{
+ STRIP_NOPS (t);
+ if (TREE_CODE (t) == ADDR_EXPR)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == COMPONENT_REF)
+ t = TREE_OPERAND (t, 1);
+ if (TREE_CODE (t) == FIELD_DECL)
+ return DECL_FIELD_IS_BASE (t);
+ return false;
+}
+
+/* We can't elide a copy from a function returning by value to a base
+ subobject, as the callee might clobber tail padding. Return true iff this
+ could be that case. */
+
+static bool
+unsafe_copy_elision_p (tree target, tree exp)
+{
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ if (type == CLASSTYPE_AS_BASE (type))
+ return false;
+ if (!is_base_field_ref (target)
+ && resolves_to_fixed_type_p (target, NULL))
+ return false;
+ tree init = TARGET_EXPR_INITIAL (exp);
+ return (TREE_CODE (init) == AGGR_INIT_EXPR
+ && !AGGR_INIT_VIA_CTOR_P (init));
+}
+
/* Subroutine of the various build_*_call functions. Overload resolution
has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a
else if (trivial)
return force_target_expr (DECL_CONTEXT (fn), arg, complain);
}
- else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
+ else if (trivial
+ || (TREE_CODE (arg) == TARGET_EXPR
+ && !unsafe_copy_elision_p (fa, arg)))
{
tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL,
complain));
--- /dev/null
+// PR c++/67557
+// { dg-do run }
+
+namespace std
+{
+ struct string
+ {
+ typedef unsigned long size_type;
+ const char* _M_p;
+ char _M_local_buf[1];
+
+ string(const char* s) : _M_p(_M_local_buf)
+ {
+ __builtin_printf("%p constructed\n", this);
+ }
+
+ string(const string& s) : _M_p(_M_local_buf)
+ {
+ __builtin_printf("%p copied from %p\n", this, &s);
+ }
+
+ ~string()
+ {
+ __builtin_printf("%p destroyed\n", this);
+ if (_M_p != _M_local_buf)
+ __builtin_abort();
+ }
+ };
+}
+
+struct StartTag
+{
+ explicit StartTag(std::string const & tag) : tag_(tag), keepempty_(false) {}
+ std::string tag_;
+ bool keepempty_;
+};
+
+StartTag fontToStartTag() { return StartTag(""); }
+
+struct FontTag : public StartTag
+{
+ FontTag() : StartTag(fontToStartTag()) {}
+};
+
+int main()
+{
+ FontTag x;
+ __builtin_printf("%p x.tag_ in main()\n", &x.tag_);
+ return 0;
+}