re PR c++/67557 (Calling copy constructor of base class in constructor of derived class produces crashing code)

PR c++/67557

	* call.c (is_base_field_ref): New.
	(unsafe_copy_elision_p): New.
	(build_over_call): Use it.

From-SVN: r228602
This commit is contained in:
Jason Merrill 2015-10-08 10:42:02 -04:00 committed by Jason Merrill
parent 25a2c75d49
commit 3c769e5a5b
3 changed files with 93 additions and 1 deletions

View file

@ -1,3 +1,10 @@
2015-10-07 Jason Merrill <jason@redhat.com>
PR c++/67557
* call.c (is_base_field_ref): New.
(unsafe_copy_elision_p): New.
(build_over_call): Use it.
2015-10-07 Marek Polacek <polacek@redhat.com>
PR sanitizer/67867

View file

@ -7094,6 +7094,39 @@ call_copy_ctor (tree a, tsubst_flags_t complain)
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
@ -7513,7 +7546,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
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));

View file

@ -0,0 +1,50 @@
// 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;
}