aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2013-01-15 09:12:30 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2013-01-15 10:12:30 +0100
commitcd61690f63612fc5e50945e446a44b9ee34c088c (patch)
treeb55d0860e61bfea46c17cab939daafaff581504a
parent955f5a07c96b8dda489e50ca8a79fb623b4cdb97 (diff)
downloadgcc-cd61690f63612fc5e50945e446a44b9ee34c088c.zip
gcc-cd61690f63612fc5e50945e446a44b9ee34c088c.tar.gz
gcc-cd61690f63612fc5e50945e446a44b9ee34c088c.tar.bz2
PR c++/55663 - constexpr function templ instantiation
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
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/pt.c64
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C20
4 files changed, 95 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index eba897f..00bcb7a 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 773afcc..8ddc143 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 b3dba49..26a479b 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 0000000..83eea47
--- /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;
+}