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