PR c++/55663 - constexpr function templ instantiation
authorDodji Seketeli <dodji@redhat.com>
Tue, 15 Jan 2013 09:12:30 +0000 (09:12 +0000)
committerDodji Seketeli <dodji@gcc.gnu.org>
Tue, 15 Jan 2013 09:12:30 +0000 (10:12 +0100)
Consider the example of the problem report

     1 template <typename>
     2 constexpr bool the_truth () { return true; }
     3
     4 template <bool>
     5   struct Takes_bool { };
     6
     7 template<bool B>
     8   using Alias = Takes_bool<B>;
     9
    10 template<typename T>
    11   struct test { using type = Alias<the_truth<T>()>; };
    12
    13 int main () {
    14   test<int> a;
    15
    16   return 0;
    17 }

that yields the error:

    test.cc: In substitution of ‘template<bool B> using Alias = Takes_bool<B> [with bool B = the_truth<int>()]’:
    test.cc:11:51:   required from ‘struct test<int>’
    test.cc:14:13:   required from here
    test.cc:11:51: error: integral expression ‘the_truth<int>()’ is not constant
       struct test { using type = Alias<the_truth<T>()>; };

I think the issue happens in the course of instantiating test<int> at
line 14, when we look into instantiating Alias<the_truth<T>()> (at
line 11) (using instantiate_alias_template) with T = int.

There, when we check the argument 'the_truth<int>()' to see if it
actually is a constant expression, in check_instantiated_arg, we fail
to recognize it constexpr-ness b/c we just look at its TREE_CONSTANT.

At that point, the_truth<int> should have been folded, and it's not,
because instantiate_alias_template forgets to call
coerce_template_parms on its arguments.

Fixed thus, bootstapped and tested on x86_64-unknown-linux-gnu against
trunk.

gcc/cp/

PR c++/55663
* pt.c (coerce_innermost_template_parms): New static function.
(instantiate_alias_template):  Use it here.

gcc/testsuite/

PR c++/55663
* g++.dg/cpp0x/alias-decl-31.C: New test.

From-SVN: r195189

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C [new file with mode: 0644]

index eba897f..00bcb7a 100644 (file)
@@ -1,3 +1,9 @@
+2013-01-15  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/55663
+       * pt.c (coerce_innermost_template_parms): New static function.
+       (instantiate_alias_template):  Use it here.
+
 2013-01-09  Jason Merrill  <jason@redhat.com>
 
        PR c++/55878
index 773afcc..8ddc143 100644 (file)
@@ -128,6 +128,8 @@ static tree tsubst_initializer_list (tree, tree);
 static tree get_class_bindings (tree, tree, tree, tree);
 static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
                                   bool, bool);
+static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
+                                             bool, bool);
 static void tsubst_enum        (tree, tree, tree);
 static tree add_to_template_args (tree, tree);
 static tree add_outermost_template_args (tree, tree);
@@ -6740,6 +6742,61 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
+/* Like coerce_template_parms.  If PARMS represents all template
+   parameters levels, this function returns a vector of vectors
+   representing all the resulting argument levels.  Note that in this
+   case, only the innermost arguments are coerced because the
+   outermost ones are supposed to have been coerced already.
+
+   Otherwise, if PARMS represents only (the innermost) vector of
+   parameters, this function returns a vector containing just the
+   innermost resulting arguments.  */
+
+static tree
+coerce_innermost_template_parms (tree parms,
+                                 tree args,
+                                 tree in_decl,
+                                 tsubst_flags_t complain,
+                                 bool require_all_args,
+                                 bool use_default_args)
+{
+  int parms_depth = TMPL_PARMS_DEPTH (parms);
+  int args_depth = TMPL_ARGS_DEPTH (args);
+  tree coerced_args;
+
+  if (parms_depth > 1)
+    {
+      coerced_args = make_tree_vec (parms_depth);
+      tree level;
+      int cur_depth;
+
+      for (level = parms, cur_depth = parms_depth;
+          parms_depth > 0 && level != NULL_TREE;
+          level = TREE_CHAIN (level), --cur_depth)
+       {
+         tree l;
+         if (cur_depth == args_depth)
+           l = coerce_template_parms (TREE_VALUE (level),
+                                      args, in_decl, complain,
+                                      require_all_args,
+                                      use_default_args);
+         else
+           l = TMPL_ARGS_LEVEL (args, cur_depth);
+
+         if (l == error_mark_node)
+           return error_mark_node;
+
+         SET_TMPL_ARGS_LEVEL (coerced_args, cur_depth, l);
+       }
+    }
+  else
+    coerced_args = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parms),
+                                         args, in_decl, complain,
+                                         require_all_args,
+                                         use_default_args);
+  return coerced_args;
+}
+
 /* Returns 1 if template args OT and NT are equivalent.  */
 
 static int
@@ -14640,6 +14697,13 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
       ggc_free (tinst);
       return error_mark_node;
     }
+
+  args =
+    coerce_innermost_template_parms (DECL_TEMPLATE_PARMS (tmpl),
+                                    args, tmpl, complain,
+                                    /*require_all_args=*/true,
+                                    /*use_default_args=*/true);
+
   tree r = instantiate_template (tmpl, args, complain);
   pop_tinst_level ();
   /* We can't free this if a pending_template entry or last_error_tinst_level
index b3dba49..26a479b 100644 (file)
@@ -1,3 +1,8 @@
+2013-01-15  Dodji Seketeli  <dodji@redhat.com>
+
+       PR c++/55663
+       * g++.dg/cpp0x/alias-decl-31.C: New test.
+
 2013-01-15  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/54286
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C
new file mode 100644 (file)
index 0000000..83eea47
--- /dev/null
@@ -0,0 +1,20 @@
+// Origin: PR c++/55663
+// { dg-do compile { target c++11 } }
+
+template <typename>
+constexpr bool the_truth () { return true; }
+
+template <bool>
+  struct Takes_bool { };
+
+template<bool B>
+  using Alias = Takes_bool<B>;
+
+template<typename T>
+  struct test { using type = Alias<the_truth<T>()>; };
+
+int main () {
+  test<int> a;
+
+  return 0;
+}