re PR c++/49808 (GCC adds an address-of somewhere!)
authorJason Merrill <jason@redhat.com>
Fri, 29 Jul 2011 07:10:21 +0000 (03:10 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 29 Jul 2011 07:10:21 +0000 (03:10 -0400)
PR c++/49808
* pt.c (tsubst) [TEMPLATE_PARM_INDEX]: Call convert_from_reference.
(convert_nontype_argument, tsubst_template_arg): Handle its output.

From-SVN: r176916

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/nontype24.C [new file with mode: 0644]

index ccaba95e8806a56ccb692e40f7dfdca4426b8705..d6330bb5a6146454264f99e09479fd84f51c4b88 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-28  Jason Merrill  <jason@redhat.com>
+
+       PR c++/49808
+       * pt.c (tsubst) [TEMPLATE_PARM_INDEX]: Call convert_from_reference.
+       (convert_nontype_argument, tsubst_template_arg): Handle its output.
+
 2011-07-28  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/49813
index b9e09af7e2638c3be18be206c66b60d9bdea3dc5..a3cd9568d23a3e59ca058e4a6af41bca56f60c95 100644 (file)
@@ -5556,41 +5556,45 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
      function). We just strip everything and get to the arg.
      See g++.old-deja/g++.oliva/template4.C and g++.dg/template/nontype9.C
      for examples.  */
-  if (TREE_CODE (expr) == NOP_EXPR)
+  if (TYPE_REF_OBJ_P (type) || TYPE_REFFN_P (type))
     {
-      if (TYPE_REF_OBJ_P (type) || TYPE_REFFN_P (type))
+      tree probe_type, probe = expr;
+      if (REFERENCE_REF_P (probe))
+       probe = TREE_OPERAND (probe, 0);
+      probe_type = TREE_TYPE (probe);
+      if (TREE_CODE (probe) == NOP_EXPR)
        {
          /* ??? Maybe we could use convert_from_reference here, but we
             would need to relax its constraints because the NOP_EXPR
             could actually change the type to something more cv-qualified,
             and this is not folded by convert_from_reference.  */
-         tree addr = TREE_OPERAND (expr, 0);
-         gcc_assert (TREE_CODE (expr_type) == REFERENCE_TYPE);
+         tree addr = TREE_OPERAND (probe, 0);
+         gcc_assert (TREE_CODE (probe_type) == REFERENCE_TYPE);
          gcc_assert (TREE_CODE (addr) == ADDR_EXPR);
          gcc_assert (TREE_CODE (TREE_TYPE (addr)) == POINTER_TYPE);
          gcc_assert (same_type_ignoring_top_level_qualifiers_p
-                     (TREE_TYPE (expr_type),
+                     (TREE_TYPE (probe_type),
                       TREE_TYPE (TREE_TYPE (addr))));
 
          expr = TREE_OPERAND (addr, 0);
          expr_type = TREE_TYPE (expr);
        }
+    }
 
-      /* We could also generate a NOP_EXPR(ADDR_EXPR()) when the
-        parameter is a pointer to object, through decay and
-        qualification conversion. Let's strip everything.  */
-      else if (TYPE_PTROBV_P (type))
-       {
-         STRIP_NOPS (expr);
-         gcc_assert (TREE_CODE (expr) == ADDR_EXPR);
-         gcc_assert (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE);
-         /* Skip the ADDR_EXPR only if it is part of the decay for
-            an array. Otherwise, it is part of the original argument
-            in the source code.  */
-         if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == ARRAY_TYPE)
-           expr = TREE_OPERAND (expr, 0);
-         expr_type = TREE_TYPE (expr);
-       }
+  /* We could also generate a NOP_EXPR(ADDR_EXPR()) when the
+     parameter is a pointer to object, through decay and
+     qualification conversion. Let's strip everything.  */
+  else if (TREE_CODE (expr) == NOP_EXPR && TYPE_PTROBV_P (type))
+    {
+      STRIP_NOPS (expr);
+      gcc_assert (TREE_CODE (expr) == ADDR_EXPR);
+      gcc_assert (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE);
+      /* Skip the ADDR_EXPR only if it is part of the decay for
+        an array. Otherwise, it is part of the original argument
+        in the source code.  */
+      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == ARRAY_TYPE)
+       expr = TREE_OPERAND (expr, 0);
+      expr_type = TREE_TYPE (expr);
     }
 
   /* [temp.arg.nontype]/5, bullet 1
@@ -8941,6 +8945,10 @@ tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                       /*integral_constant_expression_p=*/true);
       if (!(complain & tf_warning))
        --c_inhibit_evaluation_warnings;
+      /* Preserve the raw-reference nature of T.  */
+      if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
+         && REFERENCE_REF_P (r))
+       r = TREE_OPERAND (r, 0);
     }
   return r;
 }
@@ -10981,7 +10989,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              }
            else
              /* TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX.  */
-             return unshare_expr (arg);
+             return convert_from_reference (unshare_expr (arg));
          }
 
        if (level == 1)
index aebaf018f75f1a6d7050f922138eb5939a3b7b1b..c825d3bade048fc6dd99e17d5820069b9218945f 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-28  Jason Merrill  <jason@redhat.com>
+
+       PR c++/49808
+       * g++.dg/template/nontype24.C: New.
+
 2011-07-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR rtl-optimization/47958
diff --git a/gcc/testsuite/g++.dg/template/nontype24.C b/gcc/testsuite/g++.dg/template/nontype24.C
new file mode 100644 (file)
index 0000000..57fbe43
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/49808
+
+template <class X, X g>
+struct A
+{
+  A() { float r = g(0); }
+};
+
+struct f_t
+{
+  float operator() (float) const { return 1; }
+};
+
+f_t f;
+
+A<f_t&, f> x;