mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-19 06:29:00 +08:00
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:
parent
4b09846bef
commit
7e99327dbc
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
36
gcc/testsuite/g++.dg/init/ref9.C
Normal file
36
gcc/testsuite/g++.dg/init/ref9.C
Normal 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;
|
||||
}
|
10
gcc/testsuite/g++.dg/template/nested4.C
Normal file
10
gcc/testsuite/g++.dg/template/nested4.C
Normal 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> ();
|
Loading…
Reference in New Issue
Block a user