From cd61690f63612fc5e50945e446a44b9ee34c088c Mon Sep 17 00:00:00 2001
From: Dodji Seketeli <dodji@redhat.com>
Date: Tue, 15 Jan 2013 09:12:30 +0000
Subject: [PATCH] PR c++/55663 - constexpr function templ instantiation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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                           |  6 ++
 gcc/cp/pt.c                                | 64 ++++++++++++++++++++++
 gcc/testsuite/ChangeLog                    |  5 ++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C | 20 +++++++
 4 files changed, 95 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index eba897fe83df..00bcb7a5202a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 773afcc02563..8ddc14376a40 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b3dba4969d68..26a479b3f52e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 000000000000..83eea471d07c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C
@@ -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;
+}
-- 
GitLab