aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2003-09-01 19:18:03 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2003-09-01 19:18:03 +0000
commit7e99327dbcd3f1d453088f63eebe65994aded8c2 (patch)
tree3ba8f4e6715b6c18572eca713097806119e13254
parent4b09846beff900c43203222269e235d3b6d56a47 (diff)
downloadgcc-7e99327dbcd3f1d453088f63eebe65994aded8c2.zip
gcc-7e99327dbcd3f1d453088f63eebe65994aded8c2.tar.gz
gcc-7e99327dbcd3f1d453088f63eebe65994aded8c2.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog17
-rw-r--r--gcc/cp/call.c40
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c48
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/typeck.c3
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/init/ref9.C36
-rw-r--r--gcc/testsuite/g++.dg/template/nested4.C10
9 files changed, 140 insertions, 27 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 55635df..326da4b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a74fd63..9e46282 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1a2f06e..f17b67c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b4eb019..4c287ea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0c57143..8cf8d15 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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'
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 91aab2f..564b337 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8eeca7e..b62f69c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/init/ref9.C b/gcc/testsuite/g++.dg/init/ref9.C
new file mode 100644
index 0000000..127b7d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/ref9.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/template/nested4.C b/gcc/testsuite/g++.dg/template/nested4.C
new file mode 100644
index 0000000..6e5b99b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/nested4.C
@@ -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> ();