Submitter | Dodji Seketeli |
---|---|

Date | Jan. 8, 2013, 1:58 p.m. |

Message ID | <877gnnwzdg.fsf@redhat.com> |

Download | mbox | patch |

Permalink | /patch/210391/ |

State | New |

Headers | show |

## Comments

On Tue, Jan 8, 2013 at 7:58 AM, Dodji Seketeli <dodji@redhat.com> wrote: > 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. Thanks for the detective work! We already have various predicates to test for constant expressions so I am uneasy to add yet another one. What we do no need -- which I already suggested -- is a predicate to test valid non-type template arguments. For example, we already have the predicate verify_constant and reduced_constant_expression_p, require_potential_constant_expression. I think reduced_constant_expression_p is what you want. -- Gaby

On 01/08/2013 08:58 AM, Dodji Seketeli wrote: > 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. The problem is that by the time we get to check_instantiated_arg, we should have folded the expression into something TREE_CONSTANT. convert_template_argument should have done that; don't we ever call that function for this template argument? Jason

Jason Merrill <jason@redhat.com> writes: > On 01/08/2013 08:58 AM, Dodji Seketeli wrote: >> 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. > > The problem is that by the time we get to check_instantiated_arg, we > should have folded the expression into something > TREE_CONSTANT. convert_template_argument should have done that; don't > we ever call that function for this template argument? Presumably, you mean that convert_template_argument should call convert_nontype_argument to do that folding, right? I guess the reason why it's not doing it is that the call to convert_nontype_argument is conditional on else if (!uses_template_parms (orig_arg) && !uses_template_parms (t)) /* We used to call digest_init here. However, digest_init will report errors, which we don't want when complain is zero. More importantly, digest_init will try too hard to convert things: for example, `0' should not be converted to pointer type at this point according to the standard. Accepting this is not merely an extension, since deciding whether or not these conversions can occur is part of determining which function template to call, or whether a given explicit argument specification is valid. */ val = convert_nontype_argument (t, orig_arg, complain); As the argument 'the_truth<T>()' we care about is type dependant, uses_template_parms returns true and so convert_nontype_argument is never called. What is your preferred way want to handle this?

Gabriel Dos Reis <gdr@integrable-solutions.net> writes: > We already have various predicates to test for constant > expressions so I am uneasy to add yet another one. I understand. I got lost in the number of existing predicates to test for constant expressions, to the point that I thought (wrongly) the one I wanted wasn't present. :-) > I think reduced_constant_expression_p is what you want. Thanks. I didn't realize this would work because the comment of initializer_constant_valid_p (that it uses) says: We assume that VALUE has been folded as much as possible On a side node, as Jason said in the thread, we might not even need to touch anything here, as check_instantiated_arg also assumes that its arg has been fully folded. I guess I'll propose to update the comment of that function to reflect that assumption. Thanks.

On Wed, Jan 9, 2013 at 9:30 AM, Dodji Seketeli <dodji@redhat.com> wrote: > Gabriel Dos Reis <gdr@integrable-solutions.net> writes: > >> We already have various predicates to test for constant >> expressions so I am uneasy to add yet another one. > > I understand. I got lost in the number of existing predicates to test > for constant expressions, so am I :-) > to the point that I thought (wrongly) the one I wanted wasn't present. :-) > >> I think reduced_constant_expression_p is what you want. > > Thanks. I didn't realize this would work because the comment of > initializer_constant_valid_p (that it uses) says: > > We assume that VALUE has been folded as much as possible > > On a side node, as Jason said in the thread, we might not even need to > touch anything here, as check_instantiated_arg also assumes that its arg > has been fully folded. I guess I'll propose to update the comment of > that function to reflect that assumption. I read your reply. I am now even more puzzled than before. The call to uses_template_parm indicates that we expect that code to work when are also when processing a template (e.g. for non-dependent cases inside a template.) That makes me wonder how it could possibly work for the cases at hand because for non-type template arguments we need full instantiation information to determine convertibility and "constant"ness. -- Gaby

On 01/09/2013 10:02 AM, Dodji Seketeli wrote: > As the argument 'the_truth<T>()' we care about is type dependant, > uses_template_parms returns true and so convert_nontype_argument is > never called. Right, but we should call it for the instantiated argument, too. We do that for class templates by calling lookup_template_class again, which calls coerce_template_parms. We need to make sure we call coerce_template_parms when instantiating alias templates, too. Jason

## Patch

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; +}