re PR c++/12114 ([3.3.2] Uninitialized memory accessed in dtor)

PR c++/12114
	* g++.dg/init/ref9.C: New test.

	PR c++/11972
	* g++.dg/template/nested4.C: New test.

	PR c++/12114
	* cp-tree.h (initialize_reference): Change prototype.
	* call.c (initialize_reference): Add cleanup parameter.
	* decl.c (grok_reference_init): Likewise.
	(check_initializer): Likewise.
	(cp_finish_decl): Insert a CLEANUP_STMT if necessary.
	(duplicate_decls): When replacing an anticipated builtin, do not
	honor TREE_NOTHROW.
	* typeck.c (convert_for_initialization): Correct call to
	initialize_reference.

	PR c++/11972
	* pt.c (dependent_type_p_r): Pass only the innermost template
	arguments to any_dependent_template_arguments_p.

From-SVN: r70981
This commit is contained in:
Mark Mitchell 2003-09-01 19:18:03 +00:00 committed by Mark Mitchell
parent 4b09846bef
commit 7e99327dbc
9 changed files with 140 additions and 27 deletions

View File

@ -1,3 +1,20 @@
2003-09-01 Mark Mitchell <mark@codesourcery.com>
PR c++/12114
* cp-tree.h (initialize_reference): Change prototype.
* call.c (initialize_reference): Add cleanup parameter.
* decl.c (grok_reference_init): Likewise.
(check_initializer): Likewise.
(cp_finish_decl): Insert a CLEANUP_STMT if necessary.
(duplicate_decls): When replacing an anticipated builtin, do not
honor TREE_NOTHROW.
* typeck.c (convert_for_initialization): Correct call to
initialize_reference.
PR c++/11972
* pt.c (dependent_type_p_r): Pass only the innermost template
arguments to any_dependent_template_arguments_p.
2003-09-01 Josef Zlomek <zlomekj@suse.cz>
* error.c (dump_expr): Kill BIT_ANDTC_EXPR.

View File

@ -6005,14 +6005,18 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
}
/* Convert EXPR to the indicated reference TYPE, in a way suitable for
initializing a variable of that TYPE. If DECL is non-NULL, it is
initializing a variable of that TYPE. If DECL is non-NULL, it is
the VAR_DECL being initialized with the EXPR. (In that case, the
type of DECL will be TYPE.)
type of DECL will be TYPE.) If DECL is non-NULL, then CLEANUP must
also be non-NULL, and with *CLEANUP initialized to NULL. Upon
return, if *CLEANUP is no longer NULL, it will be a CLEANUP_STMT
that should be inserted after the returned expression is used to
initialize DECL.
Return the converted expression. */
tree
initialize_reference (tree type, tree expr, tree decl)
initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
{
tree conv;
@ -6094,14 +6098,33 @@ initialize_reference (tree type, tree expr, tree decl)
type = TREE_TYPE (expr);
var = make_temporary_var_for_ref_to_temp (decl, type);
layout_decl (var, 0);
/* Create the INIT_EXPR that will initialize the temporary
variable. */
init = build (INIT_EXPR, type, var, expr);
if (at_function_scope_p ())
{
tree cleanup;
add_decl_stmt (var);
cleanup = cxx_maybe_build_cleanup (var);
if (cleanup)
finish_decl_cleanup (var, cleanup);
*cleanup = cxx_maybe_build_cleanup (var);
if (*cleanup)
/* We must be careful to destroy the temporary only
after its initialization has taken place. If the
initialization throws an exception, then the
destructor should not be run. We cannot simply
transform INIT into something like:
(INIT, ({ CLEANUP_STMT; }))
because emit_local_var always treats the
initializer as a full-expression. Thus, the
destructor would run too early; it would run at the
end of initializing the reference variable, rather
than at the end of the block enclosing the
reference variable.
The solution is to pass back a CLEANUP_STMT which
the caller is responsible for attaching to the
statement tree. */
*cleanup = build_stmt (CLEANUP_STMT, var, *cleanup);
}
else
{
@ -6110,7 +6133,6 @@ initialize_reference (tree type, tree expr, tree decl)
static_aggregates = tree_cons (NULL_TREE, var,
static_aggregates);
}
init = build (INIT_EXPR, type, var, expr);
/* Use its address to initialize the reference variable. */
expr = build_address (var);
expr = build (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);

View File

@ -3524,7 +3524,7 @@ extern tree type_passed_as (tree);
extern tree convert_for_arg_passing (tree, tree);
extern tree cp_convert_parm_for_inlining (tree, tree, tree);
extern bool is_properly_derived_from (tree, tree);
extern tree initialize_reference (tree, tree, tree);
extern tree initialize_reference (tree, tree, tree, tree *);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree);

View File

@ -68,7 +68,7 @@ static cxx_saved_binding *store_bindings (tree, cxx_saved_binding *);
static tree lookup_tag_reverse (tree, tree);
static void push_local_name (tree);
static void warn_extern_redeclared_static (tree, tree);
static tree grok_reference_init (tree, tree, tree);
static tree grok_reference_init (tree, tree, tree, tree *);
static tree grokfndecl (tree, tree, tree, tree, int,
enum overload_flags, tree,
tree, int, int, int, int, int, int, tree);
@ -117,7 +117,7 @@ static void pop_labels (tree);
static void maybe_deduce_size_from_array_init (tree, tree);
static void layout_var_decl (tree);
static void maybe_commonize_var (tree);
static tree check_initializer (tree, tree, int);
static tree check_initializer (tree, tree, int, tree *);
static void make_rtl_for_nonlocal_decl (tree, tree, const char *);
static void save_function_data (tree);
static void check_function_type (tree, tree);
@ -2940,9 +2940,9 @@ duplicate_decls (tree newdecl, tree olddecl)
if (DECL_ANTICIPATED (olddecl))
; /* Do nothing yet. */
else if ((DECL_EXTERN_C_P (newdecl)
&& DECL_EXTERN_C_P (olddecl))
|| compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
&& DECL_EXTERN_C_P (olddecl))
|| compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
{
/* A near match; override the builtin. */
@ -2969,6 +2969,10 @@ duplicate_decls (tree newdecl, tree olddecl)
else if (DECL_ANTICIPATED (olddecl))
TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
/* Whether or not the builtin can throw exceptions has no
bearing on this declarator. */
TREE_NOTHROW (olddecl) = 0;
if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
{
/* If a builtin function is redeclared as `static', merge
@ -7174,14 +7178,18 @@ start_decl_1 (tree decl)
DECL_INITIAL (decl) = NULL_TREE;
}
/* Handle initialization of references.
These three arguments are from `cp_finish_decl', and have the
same meaning here that they do there.
/* Handle initialization of references. DECL, TYPE, and INIT have the
same meaning as in cp_finish_decl. *CLEANUP must be NULL on entry,
but will be set to a new CLEANUP_STMT if a temporary is created
that must be destroeyd subsequently.
Returns an initializer expression to use to initialize DECL, or
NULL if the initialization can be performed statically.
Quotes on semantics can be found in ARM 8.4.3. */
static tree
grok_reference_init (tree decl, tree type, tree init)
grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
{
tree tmp;
@ -7218,7 +7226,7 @@ grok_reference_init (tree decl, tree type, tree init)
DECL_INITIAL for local references (instead assigning to them
explicitly); we need to allow the temporary to be initialized
first. */
tmp = initialize_reference (type, init, decl);
tmp = initialize_reference (type, init, decl, cleanup);
if (tmp == error_mark_node)
return NULL_TREE;
@ -7638,13 +7646,14 @@ reshape_init (tree type, tree *initp)
}
/* Verify INIT (the initializer for DECL), and record the
initialization in DECL_INITIAL, if appropriate.
initialization in DECL_INITIAL, if appropriate. CLEANUP is as for
grok_reference_init.
If the return value is non-NULL, it is an expression that must be
evaluated dynamically to initialize DECL. */
static tree
check_initializer (tree decl, tree init, int flags)
check_initializer (tree decl, tree init, int flags, tree *cleanup)
{
tree type = TREE_TYPE (decl);
@ -7694,7 +7703,7 @@ check_initializer (tree decl, tree init, int flags)
init = NULL_TREE;
}
else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
init = grok_reference_init (decl, type, init);
init = grok_reference_init (decl, type, init, cleanup);
else if (init)
{
if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
@ -8001,8 +8010,9 @@ initialize_local_var (tree decl, tree init)
void
cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
{
register tree type;
tree type;
tree ttype = NULL_TREE;
tree cleanup;
const char *asmspec = NULL;
int was_readonly = 0;
@ -8015,6 +8025,9 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
my_friendly_assert (TREE_CODE (decl) != RESULT_DECL, 20030619);
/* Assume no cleanup is required. */
cleanup = NULL_TREE;
/* If a name was specified, get the string. */
if (global_scope_p (current_binding_level))
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
@ -8128,7 +8141,7 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
is *not* defined. */
&& (!DECL_EXTERNAL (decl) || init))
{
init = check_initializer (decl, init, flags);
init = check_initializer (decl, init, flags, &cleanup);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL (decl) && init)
{
@ -8244,6 +8257,11 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
}
}
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
reference, insert it in the statement-tree now. */
if (cleanup)
add_stmt (cleanup);
finish_end:
if (was_readonly)

View File

@ -11332,7 +11332,8 @@ dependent_type_p_r (tree type)
/* ... or any of the template arguments is a dependent type or
an expression that is type-dependent or value-dependent. */
else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type)
&& any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (type)))
&& (any_dependent_template_arguments_p
(INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
return true;
/* All TYPEOF_TYPEs are dependent; if the argument of the `typeof'

View File

@ -5657,7 +5657,8 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
if (fndecl)
savew = warningcount, savee = errorcount;
rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE);
rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
/*cleanup=*/NULL);
if (fndecl)
{
if (warningcount > savew)

View File

@ -1,3 +1,11 @@
2003-09-01 Mark Mitchell <mark@codesourcery.com>
PR c++/12114
* g++.dg/init/ref9.C: New test.
PR c++/11972
* g++.dg/template/nested4.C: New test.
2003-08-29 Mark Mitchell <mark@codesourcery.com>
PR c++/12093

View File

@ -0,0 +1,36 @@
// { dg-do run }
struct ex;
struct basic {
int refcount;
ex eval() const;
basic() : refcount(0) {}
};
struct ex {
basic *bp;
ex() : bp(0) { }
ex(const basic &);
virtual ~ex();
void construct_from_basic(const basic &);
};
ex basic::eval() const {
throw 1;
}
inline ex::ex(const basic &b) { construct_from_basic (b); }
inline ex::~ex() { if (--bp->refcount == 0) delete bp; }
void ex::construct_from_basic(const basic &b) {
const ex & tmpex = b.eval();
bp = tmpex.bp;
bp->refcount++;
}
ex pow() { return basic(); }
int main()
{
try { pow (); } catch (int) {}
return 0;
}

View File

@ -0,0 +1,10 @@
template <typename T> struct A {
template<typename S> struct B { typedef A<S> X; };
};
template<typename> void f() {
typedef A<int>::B<double>::X X;
}
template void f<int> ();