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:
parent
25a2c75d49
commit
3c769e5a5b
3 changed files with 93 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
50
gcc/testsuite/g++.dg/init/elide3.C
Normal file
50
gcc/testsuite/g++.dg/init/elide3.C
Normal 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;
|
||||
}
|
Loading…
Add table
Reference in a new issue