Hello, 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), 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 its constexpr-ness b/c we just look at its TREE_CONSTANT. Would the patch below be ok-ish in testing for the const-ness of that argument in a general enough way that takes into account its constexpr-ness? Bootstapped and tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ PR c++/55663 * cp-tree.h (cxx_is_constant_expression): Declare ... * semantics.c (cxx_is_constant_expression): ... new function. * pt.c (check_instantiated_arg): Use the new cxx_is_constant_expression in lieu of TREE_CONSTANT. gcc/testsuite/ PR c++/55663 * g++.dg/cpp0x/alias-decl-31.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/pt.c | 2 +- gcc/cp/semantics.c | 9 +++++++++ gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-31.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 810df7d..9d52ba7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5608,6 +5608,7 @@ extern bool potential_rvalue_constant_expression (tree); extern bool require_potential_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree); extern tree cxx_constant_value (tree); +extern bool cxx_is_constant_expression (tree); extern tree maybe_constant_value (tree); extern tree maybe_constant_init (tree); extern bool is_sub_constant_expr (tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 30bafa0..74ccfbf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14426,7 +14426,7 @@ check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain) constant. */ else if (TREE_TYPE (t) && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t)) - && !TREE_CONSTANT (t)) + && !cxx_is_constant_expression (t)) { if (complain & tf_error) error ("integral expression %qE is not constant", t); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2e02295..e40d48f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8077,6 +8077,15 @@ cxx_constant_value (tree t) return cxx_eval_outermost_constant_expr (t, false); } +/* Return TRUE iff E is a constant expression. */ + +bool +cxx_is_constant_expression (tree e) +{ + tree t = cxx_constant_value (e); + return (t != error_mark_node && t != NULL_TREE); +} + /* If T is a constant expression, returns its reduced value. Otherwise, if T does not have TREE_CONSTANT set, returns T. Otherwise, returns a version of T without TREE_CONSTANT. */ 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; +} -- Dodji