re PR c++/32245 (wrong POD type initialization with pointer to member)
authorMark Mitchell <mark@codesourcery.com>
Fri, 6 Jul 2007 01:23:54 +0000 (01:23 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 6 Jul 2007 01:23:54 +0000 (01:23 +0000)
PR c++/32245
* init.c (build_zero_init): Always build an initializer for
non-static storage.
* typeck2.c (build_functional_cast): Use build_zero_init.

PR c++/32251
* init.c (build_new_1): Always pass the allocation function to
build_op_delete_call.
* call.c (build_op_delete_call): Handle operator delete with a
variable-argument list.  Do not issue an error when no matching
deallocation function is available for a new operator.

PR c++/31992
* cp-tree.h (any_value_dependent_elements_p): Declare it.
* decl.c (value_dependent_init_p): New function.
(cp_finish_decl): Use it.
* pt.c (value_dependent_expression_p): Use
any_value_dependent_elements_p.
* parser.c (cp_parser_primary_expression): Add comment about
treating dependent qualified names as integral
constant-expressions.

PR c++/32245
* g++.dg/init/ptrmem4.C: New test.

PR c++/32251
* g++.dg/init/new21.C: Likewise.

PR c++/31992
* g++.dg/template/static30.C: Likewise.

From-SVN: r126399

12 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/new21.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/ptrmem4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/static30.C [new file with mode: 0644]

index 1621175..3aac996 100644 (file)
@@ -1,3 +1,27 @@
+2007-07-05  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/32245
+       * init.c (build_zero_init): Always build an initializer for
+       non-static storage.
+       * typeck2.c (build_functional_cast): Use build_zero_init.
+
+       PR c++/32251
+       * init.c (build_new_1): Always pass the allocation function to
+       build_op_delete_call.
+       * call.c (build_op_delete_call): Handle operator delete with a
+       variable-argument list.  Do not issue an error when no matching
+       deallocation function is available for a new operator.
+
+       PR c++/31992
+       * cp-tree.h (any_value_dependent_elements_p): Declare it.
+       * decl.c (value_dependent_init_p): New function.
+       (cp_finish_decl): Use it.
+       * pt.c (value_dependent_expression_p): Use
+       any_value_dependent_elements_p.
+       * parser.c (cp_parser_primary_expression): Add comment about
+       treating dependent qualified names as integral
+       constant-expressions.
+
 2007-07-04  Douglas Gregor  <doug.gregor@gmail.com>
 
        * decl.c (build_ptrmemfunc_type): Always use structural equality
index 86d5fbc..82f8666 100644 (file)
@@ -4062,8 +4062,12 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
    GLOBAL_P is true if the delete-expression should not consider
    class-specific delete operators.
    PLACEMENT is the corresponding placement new call, or NULL_TREE.
-   If PLACEMENT is non-NULL, then ALLOC_FN is the allocation function
-   called to perform the placement new.  */
+
+   If this call to "operator delete" is being generated as part to
+   deallocate memory allocated via a new-expression (as per [expr.new]
+   which requires that if the initialization throws an exception then
+   we call a deallocation function), then ALLOC_FN is the allocation
+   function.  */
 
 tree
 build_op_delete_call (enum tree_code code, tree addr, tree size,
@@ -4151,9 +4155,13 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
              if (!a && !t)
                break;
            }
-         /* On the second pass, the second argument must be
-            "size_t".  */
+         /* On the second pass, look for a function with exactly two
+            arguments: "void *" and "size_t".  */
          else if (pass == 1
+                  /* For "operator delete(void *, ...)" there will be
+                     no second argument, but we will not get an exact
+                     match above.  */
+                  && t
                   && same_type_p (TREE_VALUE (t), size_type_node)
                   && TREE_CHAIN (t) == void_list_node)
            break;
@@ -4201,10 +4209,18 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
        }
     }
 
-  /* If we are doing placement delete we do nothing if we don't find a
-     matching op delete.  */
-  if (placement)
-    return NULL_TREE;
+  /* [expr.new]
+
+     If no unambiguous matching deallocation function can be found,
+     propagating the exception does not cause the object's memory to
+     be freed.  */
+  if (alloc_fn)
+    {
+      if (!placement)
+       warning (0, "no corresponding deallocation function for `%D'", 
+                alloc_fn);
+      return NULL_TREE;
+    }
 
   error ("no suitable %<operator %s%> for %qT",
         operator_name_info[(int)code].name, type);
index 654e258..68aeace 100644 (file)
@@ -4444,6 +4444,7 @@ extern bool dependent_template_id_p               (tree, tree);
 extern bool type_dependent_expression_p                (tree);
 extern bool any_type_dependent_arguments_p      (tree);
 extern bool value_dependent_expression_p       (tree);
+extern bool any_value_dependent_elements_p      (tree);
 extern tree resolve_typename_type              (tree, bool);
 extern tree template_for_substitution          (tree);
 extern tree build_non_dependent_expr           (tree);
index 630cec1..bed426b 100644 (file)
@@ -5099,6 +5099,36 @@ initialize_artificial_var (tree decl, tree init)
   make_rtl_for_nonlocal_decl (decl, init, /*asmspec=*/NULL);
 }
 
+/* INIT is the initializer for a variable, as represented by the
+   parser.  Returns true iff INIT is value-dependent.  */
+
+static bool
+value_dependent_init_p (tree init)
+{
+  if (TREE_CODE (init) == TREE_LIST)
+    /* A parenthesized initializer, e.g.: int i (3, 2); ? */
+    return any_value_dependent_elements_p (init);
+  else if (TREE_CODE (init) == CONSTRUCTOR)
+  /* A brace-enclosed initializer, e.g.: int i = { 3 }; ? */
+    {
+      VEC(constructor_elt, gc) *elts;
+      size_t nelts;
+      size_t i;
+
+      elts = CONSTRUCTOR_ELTS (init);
+      nelts = VEC_length (constructor_elt, elts);
+      for (i = 0; i < nelts; ++i)
+       if (value_dependent_init_p (VEC_index (constructor_elt,
+                                              elts, i)->value))
+         return true;
+    }
+  else
+    /* It must be a simple expression, e.g., int i = 3;  */
+    return value_dependent_expression_p (init);
+  
+  return false;
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -5171,18 +5201,16 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
            TREE_CONSTANT (decl) = 1;
        }
 
-      if (!init
-         || !DECL_CLASS_SCOPE_P (decl)
-         || !DECL_INTEGRAL_CONSTANT_VAR_P (decl)
-         || type_dependent_p
-         || value_dependent_expression_p (init)
-            /* Check also if initializer is a value dependent
-               { integral_constant_expression }.  */
-         || (TREE_CODE (init) == CONSTRUCTOR
-             && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) == 1
-             && value_dependent_expression_p
-                  (VEC_index (constructor_elt,
-                              CONSTRUCTOR_ELTS (init), 0)->value)))
+      /* Generally, initializers in templates are expanded when the
+        template is instantiated.  But, if DECL is an integral
+        constant static data member, then it can be used in future
+        integral constant expressions, and its value must be
+        available. */
+      if (!(init
+           && DECL_CLASS_SCOPE_P (decl)
+           && DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+           && !type_dependent_p
+           && !value_dependent_init_p (init)))
        {
          if (init)
            DECL_INITIAL (decl) = init;
index b000cfd..288d0fa 100644 (file)
@@ -196,7 +196,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
             corresponding to base classes as well.  Thus, iterating
             over TYPE_FIELDs will result in correct initialization of
             all of the subobjects.  */
-         if (static_storage_p && !zero_init_p (TREE_TYPE (field)))
+         if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
            {
              tree value = build_zero_init (TREE_TYPE (field),
                                            /*nelts=*/NULL_TREE,
@@ -2038,8 +2038,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
                                          globally_qualified_p,
                                          (placement_allocation_fn_p
                                           ? alloc_call : NULL_TREE),
-                                         (placement_allocation_fn_p
-                                          ? alloc_fn : NULL_TREE));
+                                         alloc_fn);
 
          if (!cleanup)
            /* We're done.  */;
index ae970d6..0bd33d6 100644 (file)
@@ -3368,7 +3368,19 @@ cp_parser_primary_expression (cp_parser *parser,
            /* If name lookup gives us a SCOPE_REF, then the
               qualifying scope was dependent.  */
            if (TREE_CODE (decl) == SCOPE_REF)
-             return decl;
+             {
+               /* At this point, we do not know if DECL is a valid
+                  integral constant expression.  We assume that it is
+                  in fact such an expression, so that code like:
+
+                     template <int N> struct A {
+                       int a[B<N>::i];
+                     };
+                    
+                  is accepted.  At template-instantiation time, we
+                  will check that B<N>::i is actually a constant.  */
+               return decl;
+             }
            /* Check to see if DECL is a local variable in a context
               where that is forbidden.  */
            if (parser->local_variables_forbidden_p
index 63f8247..b822d95 100644 (file)
@@ -15074,12 +15074,7 @@ value_dependent_expression_p (tree expression)
          }
 
        if (TREE_CODE (expression) == TREE_LIST)
-         {
-           for (; expression; expression = TREE_CHAIN (expression))
-             if (value_dependent_expression_p (TREE_VALUE (expression)))
-               return true;
-           return false;
-         }
+         return any_value_dependent_elements_p (expression);
 
        return value_dependent_expression_p (expression);
       }
@@ -15308,6 +15303,19 @@ any_type_dependent_arguments_p (tree args)
   return false;
 }
 
+/* Returns TRUE if LIST (a TREE_LIST whose TREE_VALUEs are
+   expressions) contains any value-dependent expressions.  */
+
+bool
+any_value_dependent_elements_p (tree list)
+{
+  for (; list; list = TREE_CHAIN (list))
+    if (value_dependent_expression_p (TREE_VALUE (list)))
+      return true;
+
+  return false;
+}
+
 /* Returns TRUE if the ARG (a template argument) is dependent.  */
 
 bool
index 66c8b9c..4ef082d 100644 (file)
@@ -1340,7 +1340,9 @@ build_functional_cast (tree exp, tree parms)
       && !CLASSTYPE_NON_POD_P (type)
       && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
     {
-      exp = build_constructor (type, NULL);
+      exp = build_zero_init (type, 
+                            /*nelts=*/NULL_TREE,
+                            /*static_storage_p=*/false);
       return get_target_expr (exp);
     }
 
index d2ff6b2..266cc59 100644 (file)
@@ -1,3 +1,14 @@
+2007-07-05  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/32245
+       * g++.dg/init/ptrmem4.C: New test.
+
+       PR c++/32251
+       * g++.dg/init/new21.C: Likewise.
+
+       PR c++/31992
+       * g++.dg/template/static30.C: Likewise.
+
 2007-07-05  Dorit Nuzman  <dorit@il.ibm.com>
 
        * gcc.dg/vect/costmodel/ppc: New directory.
diff --git a/gcc/testsuite/g++.dg/init/new21.C b/gcc/testsuite/g++.dg/init/new21.C
new file mode 100644 (file)
index 0000000..5797ea9
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/32251
+
+struct A {
+  A();
+  void operator delete(void *, ...);
+};
+
+void foo () {
+  new A; // { dg-warning "deallocation" }
+}
diff --git a/gcc/testsuite/g++.dg/init/ptrmem4.C b/gcc/testsuite/g++.dg/init/ptrmem4.C
new file mode 100644 (file)
index 0000000..44ab8cf
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/32245
+// { dg-do run } 
+
+struct foo {
+  int mem1;
+  int foo::* mem2;
+};
+
+int main () {
+  foo x = { 0 } ;
+  if (x.mem2 != foo().mem2)
+    return 1;
+}
diff --git a/gcc/testsuite/g++.dg/template/static30.C b/gcc/testsuite/g++.dg/template/static30.C
new file mode 100644 (file)
index 0000000..01fa5dc
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/31992
+
+template <int> struct A 
+{
+  static const int i1;
+  static const int i2;
+};
+
+template <int N> const int A<N>::i1(A<N>::i);
+template <int N> const int A<N>::i2(3, A<N>::i);