re PR c++/12114 ([3.3.2] Uninitialized memory accessed in dtor)
authorMark Mitchell <mark@codesourcery.com>
Mon, 1 Sep 2003 19:18:03 +0000 (19:18 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 1 Sep 2003 19:18:03 +0000 (19:18 +0000)
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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/ref9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/nested4.C [new file with mode: 0644]

index 55635df2024151088f7e145efc31d22b18e55655..326da4ba433ae7cd9f7ec101d3a5b165999a13fc 100644 (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.
index a74fd63d556d993d2f1996041051a98fb682a85f..9e46282abd0a62b9a2f8a5a8b9dee17fc9c8322a 100644 (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);
index 1a2f06e1ad205edc551e5e8cf3b25bf1a2c6abd4..f17b67c2d0071dbec57f07e765852ba2b21e77ce 100644 (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);
index b4eb0192eb8100dc048f937a3901cba187b75fe2..4c287ea7158be7e5405be9ba17df18344d89d97c 100644 (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)
index 0c5714363f10a5a48bfadf470776d3e9b2659bca..8cf8d15ff8499baa0882413f33fa439ea008e5ad 100644 (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'
index 91aab2f99e8de9cb7793488b1fe9e457f25f66fd..564b3373aecc69f4a6117bcab15653cd8e9115df 100644 (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)
index 8eeca7e50c34b90b834c99eabcd1472c3174d4ba..b62f69c9ffc879c26d407afdcdcacb9cc8ca4cff 100644 (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
diff --git a/gcc/testsuite/g++.dg/init/ref9.C b/gcc/testsuite/g++.dg/init/ref9.C
new file mode 100644 (file)
index 0000000..127b7d8
--- /dev/null
@@ -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 (file)
index 0000000..6e5b99b
--- /dev/null
@@ -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> ();