------- Additional Comments From aoliva at gcc dot gnu dot org  2005-03-08 
20:44 -------
Subject: Re: [PR c++/20103] failure to gimplify constructors for addressable 
types

On Mar  8, 2005, Mark Mitchell <[EMAIL PROTECTED]> wrote:

> No, because there would be no TARGET_EXPR.  In a template, you would
> just have a COMPOUND_LITERAL_EXPR, with no TARGET_EXPR, because we
> want a syntactic representation of the input program.

> Yes, and introducing TARGET_EXPRs into templates *is a bug* because in
> templates we want a syntactic representation.  The closest thing we
> have to a syntactic representation of a compound literal is a
> CONSTRUCTOR; it's certainly not a TARGET_EXPR wrapped around a
> CONSTRUCTOR.  It may be just fine to use CONSTRUCTOR, instead of
> introducing COMPOUND_LITERAL_EXPR, but TARGET_EXPRs should not be
> appearing here at all.

> Unfortunately, you've also caused me to think about this long enough
> to realize that having the TARGET_EXPR here is wrong in the first
> place, as per above.

Okie dokie, how about this?

The change to the gimplify.c is needed to avoid having
gimple_add_tmp_var twice for the variable, once while expanding the
declaration/initialization, once while expanding the clean-ups.

Ok to install?  Passed check-g++ (except for the already-broken
eh/cleanup1.C) on x86_64-linux-gnu; just started bootstrap and full
reg-testing.

Index: gcc/ChangeLog
from  Alexandre Oliva  <[EMAIL PROTECTED]>

        PR c++/20103
        * gimplify.c (gimplify_decl_expr): Don't add temp variable if it
        was already seen in a bind expr.

Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.115
diff -u -p -r2.115 gimplify.c
--- gcc/gimplify.c 8 Mar 2005 13:56:57 -0000 2.115
+++ gcc/gimplify.c 8 Mar 2005 20:33:03 -0000
@@ -1047,7 +1047,8 @@ gimplify_decl_expr (tree *stmt_p)
       /* This decl isn't mentioned in the enclosing block, so add it to the
         list of temps.  FIXME it seems a bit of a kludge to say that
         anonymous artificial vars aren't pushed, but everything else is.  */
-      if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
+      if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE
+         && !DECL_SEEN_IN_BIND_EXPR_P (decl))
        gimple_add_tmp_var (decl);
     }
 
@@ -2123,7 +2124,8 @@ gimple_boolify (tree expr)
      *EXPR_P should be stored.  */
 
 static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target)
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
+                   fallback_t fallback)
 {
   tree expr = *expr_p;
   tree tmp, tmp2, type;
@@ -2137,18 +2139,40 @@ gimplify_cond_expr (tree *expr_p, tree *
      the arms.  */
   else if (! VOID_TYPE_P (type))
     {
+      tree result;
+
       if (target)
        {
          ret = gimplify_expr (&target, pre_p, post_p,
                               is_gimple_min_lval, fb_lvalue);
          if (ret != GS_ERROR)
            ret = GS_OK;
-         tmp = target;
+         result = tmp = target;
          tmp2 = unshare_expr (target);
        }
+      else if ((fallback & fb_lvalue) == 0)
+       {
+         result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         ret = GS_ALL_DONE;
+       }
       else
        {
-         tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         tree type = build_pointer_type (TREE_TYPE (expr));
+
+         if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+           TREE_OPERAND (expr, 1) =
+             build_fold_addr_expr (TREE_OPERAND (expr, 1));
+
+         if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+           TREE_OPERAND (expr, 2) =
+             build_fold_addr_expr (TREE_OPERAND (expr, 2));
+         
+         tmp2 = tmp = create_tmp_var (type, "iftmp");
+
+         expr = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
+                       TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
+
+         result = build_fold_indirect_ref (tmp);
          ret = GS_ALL_DONE;
        }
 
@@ -2169,7 +2193,7 @@ gimplify_cond_expr (tree *expr_p, tree *
       /* Move the COND_EXPR to the prequeue.  */
       gimplify_and_add (expr, pre_p);
 
-      *expr_p = tmp;
+      *expr_p = result;
       return ret;
     }
 
@@ -2907,7 +2931,8 @@ gimplify_modify_expr_rhs (tree *expr_p, 
        if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
          {
            *expr_p = *from_p;
-           return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p);
+           return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
+                                      fb_rvalue);
          }
        else
          ret = GS_UNHANDLED;
@@ -3721,7 +3746,8 @@ gimplify_expr (tree *expr_p, tree *pre_p
          break;
 
        case COND_EXPR:
-         ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE);
+         ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
+                                   fallback);
          break;
 
        case CALL_EXPR:
Index: gcc/cp/ChangeLog
from  Alexandre Oliva  <[EMAIL PROTECTED]>

        PR c++/20103
        * cp-tree.h (build_compound_literal): Declare.
        * semantics.c (finish_compound_literal): Move most of the code...
        * tree.c (build_compound_literal): ... here.  New function.
        (lvalue_p_1): Handle COMPOUND_LITERAL_EXPR.
        (stabilize_init): Likewise.
        * pt.c (tsubst_copy_and_build): Likewise.
        * call.c (build_over_call): Likewise.
        * class.c (fixed_type_or_null): Likewise.
        * cp-gimplify.c (cp_gimplify_init_expr): Likewise.
        * cvt.c (force_rvalue, ocp_convert): Likewise.

Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1107
diff -u -p -r1.1107 cp-tree.h
--- gcc/cp/cp-tree.h 1 Mar 2005 09:57:38 -0000 1.1107
+++ gcc/cp/cp-tree.h 8 Mar 2005 20:33:12 -0000
@@ -4218,6 +4218,7 @@ extern tree build_min_nt                  (enum tree_co
 extern tree build_min_non_dep                  (enum tree_code, tree, ...);
 extern tree build_cplus_new                    (tree, tree);
 extern tree get_target_expr                    (tree);
+extern tree build_compound_literal             (tree, tree);
 extern tree build_cplus_array_type             (tree, tree);
 extern tree hash_tree_cons                     (tree, tree, tree);
 extern tree hash_tree_chain                    (tree, tree);
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.463
diff -u -p -r1.463 semantics.c
--- gcc/cp/semantics.c 23 Feb 2005 05:30:48 -0000 1.463
+++ gcc/cp/semantics.c 8 Mar 2005 20:33:13 -0000
@@ -1980,23 +1980,8 @@ finish_compound_literal (tree type, tree
   compound_literal = build_constructor (NULL_TREE, initializer_list);
   /* Mark it as a compound-literal.  */
   TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
-  if (processing_template_decl)
-    TREE_TYPE (compound_literal) = type;
-  else
-    {
-      /* Check the initialization.  */
-      compound_literal = digest_init (type, compound_literal, NULL);
-      /* If the TYPE was an array type with an unknown bound, then we can
-        figure out the dimension now.  For example, something like:
-
-          `(int []) { 2, 3 }'
-
-        implies that the array has two elements.  */
-      if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
-       complete_array_type (type, compound_literal, 1);
-    }
 
-  return compound_literal;
+  return build_compound_literal (type, compound_literal);
 }
 
 /* Return the declaration for the function-name variable indicated by
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.427
diff -u -p -r1.427 tree.c
--- gcc/cp/tree.c 21 Feb 2005 23:12:27 -0000 1.427
+++ gcc/cp/tree.c 8 Mar 2005 20:33:15 -0000
@@ -154,6 +154,7 @@ lvalue_p_1 (tree ref,
                         treat_class_rvalues_as_lvalues);
 
     case TARGET_EXPR:
+    case COMPOUND_LITERAL_EXPR:
       return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
 
     case CALL_EXPR:
@@ -365,6 +366,47 @@ get_target_expr (tree init)
   return build_target_expr_with_type (init, TREE_TYPE (init));
 }
 
+/* Build a COMPOUND_LITERAL_EXPR.  TYPE is the type given in the
+   compound literal, which may be an incomplete array type completed
+   by the initializer; COMPOUND_LITERAL is a CONSTRUCTOR that
+   initializes the compound literal.  */
+
+tree
+build_compound_literal (tree type, tree compound_literal)
+{
+  /* We do not use start_decl here because we have a type, not a declarator;
+     and do not use finish_decl because the decl should be stored inside
+     the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_EXPR.  */
+  tree decl;
+  tree complit;
+  tree stmt;
+
+  if (type == error_mark_node || compound_literal == error_mark_node)
+    return error_mark_node;
+
+  if (!processing_template_decl)
+    {
+      /* Check the initialization.  */
+      compound_literal = digest_init (type, compound_literal, NULL);
+      /* If the TYPE was an array type with an unknown bound, then we can
+        figure out the dimension now.  For example, something like:
+
+          `(int []) { 2, 3 }'
+
+        implies that the array has two elements.  */
+      if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
+       complete_array_type (type, compound_literal, 1);
+    }
+
+  decl = build_local_temp (type);
+  DECL_INITIAL (decl) = compound_literal;
+
+  stmt = build_stmt (DECL_EXPR, decl);
+  complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), stmt);
+  TREE_SIDE_EFFECTS (complit) = 1;
+
+  return complit;
+}
 
 static tree
 build_cplus_array_type_1 (tree elt_type, tree index_type)
@@ -2241,6 +2283,8 @@ stabilize_init (tree init, tree *initp)
        t = TREE_OPERAND (t, 1);
       if (TREE_CODE (t) == TARGET_EXPR)
        t = TARGET_EXPR_INITIAL (t);
+      if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
+       t = DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (t));
       if (TREE_CODE (t) == COMPOUND_EXPR)
        t = expr_last (t);
       if (TREE_CODE (t) == CONSTRUCTOR
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.979
diff -u -p -r1.979 pt.c
--- gcc/cp/pt.c 5 Mar 2005 15:44:20 -0000 1.979
+++ gcc/cp/pt.c 8 Mar 2005 20:33:22 -0000
@@ -8744,6 +8744,11 @@ tsubst_copy_and_build (tree t, 
       return build_throw
        (RECUR (TREE_OPERAND (t, 0)));
 
+    case COMPOUND_LITERAL_EXPR:
+      return build_compound_literal
+       (RECUR (TREE_TYPE (COMPOUND_LITERAL_EXPR_DECL (t))),
+        RECUR (DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (t))));
+
     case CONSTRUCTOR:
       {
        tree r;
Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.531
diff -u -p -r1.531 call.c
--- gcc/cp/call.c 24 Feb 2005 21:55:10 -0000 1.531
+++ gcc/cp/call.c 8 Mar 2005 20:33:26 -0000
@@ -3655,6 +3655,54 @@ build_new_op (enum tree_code code, int f
                        TYPE_BINFO (TREE_TYPE (arg1)),
                        flags, &candidates);
     }
+  /* Per 13.3.1.2/3, 2nd bullet, if no operand has a class type, then
+     only non-member functions that have type T1 or reference to
+     cv-qualified-opt T1 for the first argument, if the first argument
+     has an enumeration type, or T2 or reference to cv-qualified-opt
+     T2 for the second argument, if the the second argument has an
+     enumeration type.  Filter out those that don't match.  */
+  else if (! arg2 || ! CLASS_TYPE_P (TREE_TYPE (arg2)))
+    {
+      struct z_candidate **candp, **next;
+
+      for (candp = &candidates; *candp; candp = next)
+       {
+         tree parmlist, parmtype;
+
+         cand = *candp;
+         next = &cand->next;
+
+         parmlist = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
+         parmtype = TREE_VALUE (parmlist);
+
+         if (TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE
+             && (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)),
+                              TYPE_MAIN_VARIANT (parmtype))
+                 || (TREE_CODE (parmtype) == REFERENCE_TYPE
+                     && reference_related_p (TREE_TYPE (arg1),
+                                             TREE_TYPE (parmtype)))))
+           continue;
+
+         if (! arg2)
+           continue;
+
+         parmlist = TREE_CHAIN (parmlist);
+         parmtype = TREE_VALUE (parmlist);
+
+         if (TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE
+             && (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (arg2)),
+                              TYPE_MAIN_VARIANT (parmtype))
+                 || (TREE_CODE (parmtype) == REFERENCE_TYPE
+                     && reference_related_p (TREE_TYPE (arg2),
+                                             TREE_TYPE (parmtype)))))
+           continue;
+
+         /* Neither argument has an appropriate type, so remove this
+            candidate function from the list.  */
+         *candp = cand->next;
+         next = candp;
+       }
+    }
 
   /* Rearrange the arguments for ?: so that add_builtin_candidate only has
      to know about two args; a builtin candidate will always have a first
@@ -4850,12 +4898,14 @@ build_over_call (struct z_candidate *can
          temp or an INIT_EXPR otherwise.  */
       if (integer_zerop (TREE_VALUE (args)))
        {
-         if (TREE_CODE (arg) == TARGET_EXPR)
+         if (TREE_CODE (arg) == TARGET_EXPR
+             || TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
            return arg;
          else if (TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
            return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
        }
       else if (TREE_CODE (arg) == TARGET_EXPR
+              || TREE_CODE (arg) == COMPOUND_LITERAL_EXPR
               || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
        {
          tree to = stabilize_reference
Index: gcc/cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.709
diff -u -p -r1.709 class.c
--- gcc/cp/class.c 7 Mar 2005 23:08:57 -0000 1.709
+++ gcc/cp/class.c 8 Mar 2005 20:33:31 -0000
@@ -5234,6 +5234,7 @@ fixed_type_or_null (tree instance, int* 
        }
       /* fall through...  */
     case TARGET_EXPR:
+    case COMPOUND_LITERAL_EXPR:
     case PARM_DECL:
     case RESULT_DECL:
       if (IS_AGGR_TYPE (TREE_TYPE (instance)))
Index: gcc/cp/cp-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-gimplify.c,v
retrieving revision 1.17
diff -u -p -r1.17 cp-gimplify.c
--- gcc/cp/cp-gimplify.c 22 Dec 2004 18:00:38 -0000 1.17
+++ gcc/cp/cp-gimplify.c 8 Mar 2005 20:33:31 -0000
@@ -1,6 +1,6 @@
 /* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c.
 
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Jason Merrill <[EMAIL PROTECTED]>
 
 This file is part of GCC.
@@ -125,6 +125,8 @@ cp_gimplify_init_expr (tree *expr_p, tre
     from = TARGET_EXPR_INITIAL (from);
   if (TREE_CODE (from) == CLEANUP_POINT_EXPR)
     from = TREE_OPERAND (from, 0);
+  if (TREE_CODE (from) == COMPOUND_LITERAL_EXPR)
+    from = DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (from));
 
   /* Look through any COMPOUND_EXPRs.  */
   sub = expr_last (from);
Index: gcc/cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.180
diff -u -p -r1.180 cvt.c
--- gcc/cp/cvt.c 9 Feb 2005 02:53:37 -0000 1.180
+++ gcc/cp/cvt.c 8 Mar 2005 20:33:32 -0000
@@ -575,7 +575,8 @@ convert_from_reference (tree val)
 tree
 force_rvalue (tree expr)
 {
-  if (IS_AGGR_TYPE (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
+  if (IS_AGGR_TYPE (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR
+      && TREE_CODE (expr) != COMPOUND_LITERAL_EXPR)
     expr = ocp_convert (TREE_TYPE (expr), expr,
                        CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);
   else
@@ -640,6 +641,16 @@ ocp_convert (tree type, tree expr, int c
          TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
          return e;
        }
+      else if (TREE_CODE (e) == COMPOUND_LITERAL_EXPR)
+       {
+         /* Don't build a NOP_EXPR of class type.  Instead, change the
+            type of the temporary.  Only allow this for cv-qual changes,
+            though.  */
+         gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)),
+                                  TYPE_MAIN_VARIANT (type)));
+         TREE_TYPE (e) = TREE_TYPE (COMPOUND_LITERAL_EXPR_DECL (e)) = type;
+         return e;
+       }         
       else
        {
          /* We shouldn't be treating objects of ADDRESSABLE type as
Index: gcc/testsuite/ChangeLog
from  Alexandre Oliva  <[EMAIL PROTECTED]>

        * g++.dg/tree-ssa/pr20103.C: New test.

Index: gcc/testsuite/g++.dg/tree-ssa/pr20103.C
===================================================================
RCS file: gcc/testsuite/g++.dg/tree-ssa/pr20103.C
diff -N gcc/testsuite/g++.dg/tree-ssa/pr20103.C
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/tree-ssa/pr20103.C 8 Mar 2005 20:33:46 -0000
@@ -0,0 +1,59 @@
+// PR c++/20103
+
+// { dg-do compile }
+
+// { dg-options "" }
+
+// Gimplification used to fail for (B){x}, because create_tmp_var
+// required a non-addressable type, and we didn't wrap the constructor
+// in a target_expr, ensuring it's moved to a separate decl.
+
+// Whether it is an lvalue, like in C, or an rvalue, is up to the ISO
+// C++ Commitete to decide in the second version of the C++ Standard.
+// We're going with rvalues for now.
+
+struct A
+{
+    A(const A&);
+};
+
+struct B
+{
+    A a;
+};
+
+void foo(B);
+void bar(B&); // { dg-error "in passing argument" }
+void bac(const B&);
+void bap(const B*);
+
+void baz(A &x)
+{
+    foo ((B){x});
+    bar ((B){x}); // { dg-error "non-const reference" }
+    bac ((B){x});
+    bap (&(B){x}); // { dg-error "address of temporary" }
+
+    foo ((const B&)(B){x});
+    bar ((B&)(B){x}); // { dg-error "invalid cast" }
+    bac ((const B&)(B){x});
+    bap (&(const B&)(B){x});
+}
+
+template <typename T, typename U>
+void baz(T &x)
+{
+    foo ((U){x});
+    bar ((U){x}); // { dg-error "non-const reference" }
+    bac ((U){x});
+    bap (&(U){x}); // { dg-error "address of temporary" }
+
+    foo ((const U&)(U){x});
+    bar ((U&)(U){x}); // { dg-error "invalid cast" }
+    bac ((const U&)(U){x});
+    bap (&(const U&)(U){x});
+}
+
+void bazT(A &x) {
+  baz<A,B>(x);
+}

-- 
Alexandre Oliva             http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer   [EMAIL PROTECTED], gcc.gnu.org}
Free Software Evangelist  [EMAIL PROTECTED], gnu.org}


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20103

Reply via email to