* [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
@ 2022-03-07 18:41 Patrick Palka
2022-03-07 19:09 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Patrick Palka @ 2022-03-07 18:41 UTC (permalink / raw)
To: gcc-patches
instantiate_non_dependent_expr_sfinae instantiates only potentially
constant expressions, but when processing a non-dependent decltype
operand we want to instantiate it even if it's non-constant since
such non-dependent decltype is always resolved ahead of time.
Currently finish_decltype_type uses the former function, which causes us
to miss issuing a narrowing diagnostic for S{id(v)} in the below testcase
because we never instantiate this non-constant non-dependent decltype
operand.
So this patch makes finish_decltype_type use i_n_d_e_internal instead of
_sfinae. And afterward, we need to keep processing_template_decl cleared
for sake of the later call to lvalue_kind, which handles templated and
non-templated COND_EXPR differently. Otherwise we'd incorrectly reject
the declaration of g in cpp0x/cond2.C with:
error: ‘g’ declared as function returning a function
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
PR c++/104823
gcc/cp/ChangeLog:
* semantics.cc (finish_decltype_type): Use i_n_d_e_internal
instead of _sfinae when instantiating a non-dependent decltype
operand, and keep processing_template_decl cleared afterward.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/Wnarrowing19.C: New test.
---
gcc/cp/semantics.cc | 11 ++++++++++-
gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C | 8 ++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 07cae993efe..66d90c2f7be 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
/* decltype is an unevaluated context. */
cp_unevaluated u;
+ processing_template_decl_sentinel ptds (/*reset=*/false);
+
/* Depending on the resolution of DR 1172, we may later need to distinguish
instantiation-dependent but not type-dependent expressions so that, say,
A<decltype(sizeof(T))>::U doesn't require 'typename'. */
@@ -11232,7 +11234,14 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
}
else if (processing_template_decl)
{
- expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+ /* Instantiate the non-dependent operand to diagnose any ill-formed
+ expressions. And keep processing_template_decl cleared for the rest
+ of the function (for sake of the call to lvalue_kind below, which
+ handles templated and non-templated COND_EXPR differently). */
+ processing_template_decl = 0;
+ /* Since we want to do this even for non-constant expressions, we
+ use i_n_d_e_internal here instead of _sfinae. */
+ expr = instantiate_non_dependent_expr_internal (expr, complain);
if (expr == error_mark_node)
return error_mark_node;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
new file mode 100644
index 00000000000..bd9fd2eb6f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
@@ -0,0 +1,8 @@
+// PR c++/104823
+// { dg-do compile { target c++11 } }
+
+struct S { S(int); };
+
+double id(double v);
+
+template<class> auto f(double v) -> decltype(S{id(v)}); // { dg-error "narrowing" }
--
2.35.1.354.g715d08a9e5
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
2022-03-07 18:41 [PATCH] c++: non-constant non-dependent decltype folding [PR104823] Patrick Palka
@ 2022-03-07 19:09 ` Jason Merrill
2022-03-08 16:54 ` Patrick Palka
0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2022-03-07 19:09 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 3/7/22 14:41, Patrick Palka wrote:
> instantiate_non_dependent_expr_sfinae instantiates only potentially
> constant expressions
Hmm, that now strikes me as a problematic interface, as we don't know
whether what we get back is template or non-template trees.
Maybe we want to change instantiate_non_dependent_expr to
checking_assert that the argument is non-dependent (callers are already
checking that), and drop the potentially-constant test?
> but when processing a non-dependent decltype
> operand we want to instantiate it even if it's non-constant since
> such non-dependent decltype is always resolved ahead of time.
>
> Currently finish_decltype_type uses the former function, which causes us
> to miss issuing a narrowing diagnostic for S{id(v)} in the below testcase
> because we never instantiate this non-constant non-dependent decltype
> operand.
>
> So this patch makes finish_decltype_type use i_n_d_e_internal instead of
> _sfinae. And afterward, we need to keep processing_template_decl cleared
> for sake of the later call to lvalue_kind, which handles templated and
> non-templated COND_EXPR differently. Otherwise we'd incorrectly reject
> the declaration of g in cpp0x/cond2.C with:
>
> error: ‘g’ declared as function returning a function
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
>
> PR c++/104823
>
> gcc/cp/ChangeLog:
>
> * semantics.cc (finish_decltype_type): Use i_n_d_e_internal
> instead of _sfinae when instantiating a non-dependent decltype
> operand, and keep processing_template_decl cleared afterward.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/Wnarrowing19.C: New test.
> ---
> gcc/cp/semantics.cc | 11 ++++++++++-
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C | 8 ++++++++
> 2 files changed, 18 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
>
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 07cae993efe..66d90c2f7be 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
> /* decltype is an unevaluated context. */
> cp_unevaluated u;
>
> + processing_template_decl_sentinel ptds (/*reset=*/false);
> +
> /* Depending on the resolution of DR 1172, we may later need to distinguish
> instantiation-dependent but not type-dependent expressions so that, say,
> A<decltype(sizeof(T))>::U doesn't require 'typename'. */
> @@ -11232,7 +11234,14 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
> }
> else if (processing_template_decl)
> {
> - expr = instantiate_non_dependent_expr_sfinae (expr, complain);
> + /* Instantiate the non-dependent operand to diagnose any ill-formed
> + expressions. And keep processing_template_decl cleared for the rest
> + of the function (for sake of the call to lvalue_kind below, which
> + handles templated and non-templated COND_EXPR differently). */
> + processing_template_decl = 0;
> + /* Since we want to do this even for non-constant expressions, we
> + use i_n_d_e_internal here instead of _sfinae. */
> + expr = instantiate_non_dependent_expr_internal (expr, complain);
> if (expr == error_mark_node)
> return error_mark_node;
> }
> diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
> new file mode 100644
> index 00000000000..bd9fd2eb6f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
> @@ -0,0 +1,8 @@
> +// PR c++/104823
> +// { dg-do compile { target c++11 } }
> +
> +struct S { S(int); };
> +
> +double id(double v);
> +
> +template<class> auto f(double v) -> decltype(S{id(v)}); // { dg-error "narrowing" }
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
2022-03-07 19:09 ` Jason Merrill
@ 2022-03-08 16:54 ` Patrick Palka
2022-03-08 18:27 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Patrick Palka @ 2022-03-08 16:54 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Mon, 7 Mar 2022, Jason Merrill wrote:
> On 3/7/22 14:41, Patrick Palka wrote:
> > instantiate_non_dependent_expr_sfinae instantiates only potentially
> > constant expressions
>
> Hmm, that now strikes me as a problematic interface, as we don't know whether
> what we get back is template or non-template trees.
>
> Maybe we want to change instantiate_non_dependent_expr to checking_assert that
> the argument is non-dependent (callers are already checking that), and drop
> the potentially-constant test?
That sounds like a nice improvement. But it happens to break
template<int N> using type = decltype(N);
beause finish_decltype_type checks instantiation_dependent_uneval_expression_p
(which is false here) instead of instantiation_dependent_expression_p
(which is true here) before calling instantiate_non_dependent_expr, so
we end up tripping over the proposed checking_assert (which checks the
latter stronger form of dependence).
I suspect other callers of instantiate_non_dependent_expr might have a
similar problem if they use a weaker dependence check than
instantiation_dependent_expression_p, e.g. build_noexcept_spec only
checks value_dependent_expression_p.
I wonder if we should relax the proposed checking_assert in i_n_d_e, or
strengthen the dependence checks performed by its callers, or something
else?
Here's the diff I'm working with:
-- >8 --
gcc/cp/parser.cc | 2 +-
gcc/cp/pt.cc | 21 ++++++---------------
gcc/cp/semantics.cc | 11 ++++-------
3 files changed, 11 insertions(+), 23 deletions(-)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 20aab5eb6b1..a570a9163b9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7986,7 +7986,7 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
if (fold_expr_p)
- expr = instantiate_non_dependent_expr (expr);
+ expr = fold_non_dependent_expr (expr);
/* If we have an ellipsis, then this is an expression expansion. */
if (allow_expansion_p
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 53a74636279..1b2d9a7e4b1 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6350,8 +6350,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
/* The actual substitution part of instantiate_non_dependent_expr_sfinae,
to be used when the caller has already checked
(processing_template_decl
- && !instantiation_dependent_expression_p (expr)
- && potential_constant_expression (expr))
+ && !instantiation_dependent_expression_p (expr))
and cleared processing_template_decl. */
tree
@@ -6365,8 +6364,7 @@ instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
/*integral_constant_expression_p=*/true);
}
-/* Simplify EXPR if it is a non-dependent expression. Returns the
- (possibly simplified) expression. */
+/* Instantiate the non-dependent expression EXPR. */
tree
instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
@@ -6374,16 +6372,9 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
if (expr == NULL_TREE)
return NULL_TREE;
- /* If we're in a template, but EXPR isn't value dependent, simplify
- it. We're supposed to treat:
-
- template <typename T> void f(T[1 + 1]);
- template <typename T> void f(T[2]);
-
- as two declarations of the same function, for example. */
- if (processing_template_decl
- && is_nondependent_constant_expression (expr))
+ if (processing_template_decl)
{
+ gcc_checking_assert (!instantiation_dependent_expression_p (expr));
processing_template_decl_sentinel s;
expr = instantiate_non_dependent_expr_internal (expr, complain);
}
@@ -6396,8 +6387,8 @@ instantiate_non_dependent_expr (tree expr)
return instantiate_non_dependent_expr_sfinae (expr, tf_error);
}
-/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
- an uninstantiated expression. */
+/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
+ expression is dependent or non-constant. */
tree
instantiate_non_dependent_or_null (tree expr)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 66d90c2f7be..8f744eb21b6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11234,16 +11234,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
}
else if (processing_template_decl)
{
- /* Instantiate the non-dependent operand to diagnose any ill-formed
- expressions. And keep processing_template_decl cleared for the rest
+ expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+ if (expr == error_mark_node)
+ return error_mark_node;
+ /* Keep processing_template_decl cleared for the rest
of the function (for sake of the call to lvalue_kind below, which
handles templated and non-templated COND_EXPR differently). */
processing_template_decl = 0;
- /* Since we want to do this even for non-constant expressions, we
- use i_n_d_e_internal here instead of _sfinae. */
- expr = instantiate_non_dependent_expr_internal (expr, complain);
- if (expr == error_mark_node)
- return error_mark_node;
}
/* The type denoted by decltype(e) is defined as follows: */
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
2022-03-08 16:54 ` Patrick Palka
@ 2022-03-08 18:27 ` Jason Merrill
2022-03-08 20:57 ` Patrick Palka
0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2022-03-08 18:27 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 3/8/22 12:54, Patrick Palka wrote:
>
>
> On Mon, 7 Mar 2022, Jason Merrill wrote:
>
>> On 3/7/22 14:41, Patrick Palka wrote:
>>> instantiate_non_dependent_expr_sfinae instantiates only potentially
>>> constant expressions
>>
>> Hmm, that now strikes me as a problematic interface, as we don't know whether
>> what we get back is template or non-template trees.
>>
>> Maybe we want to change instantiate_non_dependent_expr to checking_assert that
>> the argument is non-dependent (callers are already checking that), and drop
>> the potentially-constant test?
>
> That sounds like a nice improvement. But it happens to break
>
> template<int N> using type = decltype(N);
>
> beause finish_decltype_type checks instantiation_dependent_uneval_expression_p
> (which is false here) instead of instantiation_dependent_expression_p
> (which is true here) before calling instantiate_non_dependent_expr, so
> we end up tripping over the proposed checking_assert (which checks the
> latter stronger form of dependence).
>
> I suspect other callers of instantiate_non_dependent_expr might have a
> similar problem if they use a weaker dependence check than
> instantiation_dependent_expression_p, e.g. build_noexcept_spec only
> checks value_dependent_expression_p.
>
> I wonder if we should relax the proposed checking_assert in i_n_d_e, or
> strengthen the dependence checks performed by its callers, or something
> else?
I think relax the assert to _uneval and strengthen callers that use
value_dep.
> Here's the diff I'm working with:
>
> -- >8 --
>
> gcc/cp/parser.cc | 2 +-
> gcc/cp/pt.cc | 21 ++++++---------------
> gcc/cp/semantics.cc | 11 ++++-------
> 3 files changed, 11 insertions(+), 23 deletions(-)
>
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 20aab5eb6b1..a570a9163b9 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -7986,7 +7986,7 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
> expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
>
> if (fold_expr_p)
> - expr = instantiate_non_dependent_expr (expr);
> + expr = fold_non_dependent_expr (expr);
>
> /* If we have an ellipsis, then this is an expression expansion. */
> if (allow_expansion_p
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 53a74636279..1b2d9a7e4b1 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -6350,8 +6350,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
> /* The actual substitution part of instantiate_non_dependent_expr_sfinae,
> to be used when the caller has already checked
> (processing_template_decl
> - && !instantiation_dependent_expression_p (expr)
> - && potential_constant_expression (expr))
> + && !instantiation_dependent_expression_p (expr))
> and cleared processing_template_decl. */
>
> tree
> @@ -6365,8 +6364,7 @@ instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
> /*integral_constant_expression_p=*/true);
> }
>
> -/* Simplify EXPR if it is a non-dependent expression. Returns the
> - (possibly simplified) expression. */
> +/* Instantiate the non-dependent expression EXPR. */
>
> tree
> instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
> @@ -6374,16 +6372,9 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
> if (expr == NULL_TREE)
> return NULL_TREE;
>
> - /* If we're in a template, but EXPR isn't value dependent, simplify
> - it. We're supposed to treat:
> -
> - template <typename T> void f(T[1 + 1]);
> - template <typename T> void f(T[2]);
> -
> - as two declarations of the same function, for example. */
> - if (processing_template_decl
> - && is_nondependent_constant_expression (expr))
> + if (processing_template_decl)
> {
> + gcc_checking_assert (!instantiation_dependent_expression_p (expr));
> processing_template_decl_sentinel s;
> expr = instantiate_non_dependent_expr_internal (expr, complain);
> }
> @@ -6396,8 +6387,8 @@ instantiate_non_dependent_expr (tree expr)
> return instantiate_non_dependent_expr_sfinae (expr, tf_error);
> }
>
> -/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
> - an uninstantiated expression. */
> +/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
> + expression is dependent or non-constant. */
>
> tree
> instantiate_non_dependent_or_null (tree expr)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 66d90c2f7be..8f744eb21b6 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -11234,16 +11234,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
> }
> else if (processing_template_decl)
> {
> - /* Instantiate the non-dependent operand to diagnose any ill-formed
> - expressions. And keep processing_template_decl cleared for the rest
> + expr = instantiate_non_dependent_expr_sfinae (expr, complain);
> + if (expr == error_mark_node)
> + return error_mark_node;
> + /* Keep processing_template_decl cleared for the rest
> of the function (for sake of the call to lvalue_kind below, which
> handles templated and non-templated COND_EXPR differently). */
> processing_template_decl = 0;
> - /* Since we want to do this even for non-constant expressions, we
> - use i_n_d_e_internal here instead of _sfinae. */
> - expr = instantiate_non_dependent_expr_internal (expr, complain);
> - if (expr == error_mark_node)
> - return error_mark_node;
> }
>
> /* The type denoted by decltype(e) is defined as follows: */
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
2022-03-08 18:27 ` Jason Merrill
@ 2022-03-08 20:57 ` Patrick Palka
2022-03-08 22:23 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Patrick Palka @ 2022-03-08 20:57 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Tue, 8 Mar 2022, Jason Merrill wrote:
> On 3/8/22 12:54, Patrick Palka wrote:
> >
> >
> > On Mon, 7 Mar 2022, Jason Merrill wrote:
> >
> > > On 3/7/22 14:41, Patrick Palka wrote:
> > > > instantiate_non_dependent_expr_sfinae instantiates only potentially
> > > > constant expressions
> > >
> > > Hmm, that now strikes me as a problematic interface, as we don't know
> > > whether
> > > what we get back is template or non-template trees.
> > >
> > > Maybe we want to change instantiate_non_dependent_expr to checking_assert
> > > that
> > > the argument is non-dependent (callers are already checking that), and
> > > drop
> > > the potentially-constant test?
> >
> > That sounds like a nice improvement. But it happens to break
> >
> > template<int N> using type = decltype(N);
> >
> > beause finish_decltype_type checks
> > instantiation_dependent_uneval_expression_p
> > (which is false here) instead of instantiation_dependent_expression_p
> > (which is true here) before calling instantiate_non_dependent_expr, so
> > we end up tripping over the proposed checking_assert (which checks the
> > latter stronger form of dependence).
> >
> > I suspect other callers of instantiate_non_dependent_expr might have a
> > similar problem if they use a weaker dependence check than
> > instantiation_dependent_expression_p, e.g. build_noexcept_spec only
> > checks value_dependent_expression_p.
> >
> > I wonder if we should relax the proposed checking_assert in i_n_d_e, or
> > strengthen the dependence checks performed by its callers, or something
> > else?
>
> I think relax the assert to _uneval and strengthen callers that use value_dep.
Sounds good, like so? Note this patch doesn't touch
instantiate_non_dependent_or_null or fold_non_dependent_expr, since the
former already never returns a templated tree, and callers of the latter
should only care about the constant-ness not template-ness of the result
IIUC.
Boostrapped and regtested on x86_64-pc-linux-gnu.
-- >8 --
Subject: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
When processing a non-dependent decltype operand we want to instantiate
it even if it's non-constant since non-dependent decltype is always
resolved ahead of time. But currently finish_decltype_type uses
instantiate_non_dependent_expr, which instantiates only potentially
constant expressions, and this causes us to miss diagnosing the narrowing
conversion in S{id(v)} in the below testcase because we never instantiate
this non-constant non-dependent decltype operand.
In light of
> On Mon, 7 Mar 2022, Jason Merrill wrote:
>> On 3/7/22 14:41, Patrick Palka wrote:
>>> instantiate_non_dependent_expr instantiates only potentially constant
>>> expressions
>>
>> Hmm, that now strikes me as a problematic interface, as we don't know whether
>> what we get back is template or non-template trees.
this patch drops the potentially-constant check in i_n_d_e, and turns
its dependence check into a checking_assert, since most callers already
check that the argument is non-dependent. This patch also relaxes the
dependence check in i_n_d_e to use the _uneval version and strengthens
the dependence checks used by callers accordingly.
In cp_parser_parenthesized_expression_list_elt we were calling
instantiate_non_dependent_expr without first checking for non-dependence.
We could fix this by guarding the call appropriately, but I noticed we
also fold non-dependent attributes later from cp_check_const_attribute.
This double instantiation causes us to reject constexpr-attribute4.C
below due to the second folding seeing non-templated trees (an existing
bug). Thus the right solution here seems to be to remove this unguarded
call to i_n_d_e so that we end up folding non-dependent attributes only
once.
Finally, after calling i_n_d_e in finish_decltype_type we need to keep
processing_template_decl cleared for sake of the later call to
lvalue_kind, which handles templated and non-templated COND_EXPR
differently. Otherwise we'd incorrectly reject the declaration of g in
cpp0x/cond2.C with:
error: 'g' declared as function returning a function
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
PR c++/104823
gcc/cp/ChangeLog:
* except.cc (build_noexcept_spec): Strengthen dependence check
to instantiation_dependent_expression_p.
* parser.cc (cp_parser_parenthesized_expression_list_elt):
Remove fold_expr_p parameter and call
instantiate_non_dependent_expr.
(cp_parser_parenthesized_expression_list): Adjust accordingly.
* pt.cc (expand_integer_pack): Strengthen dependence check
to instantiation_dependent_expression_p.
(instantiate_non_dependent_expr_internal): Adjust comment.
(instantiate_non_dependent_expr_sfinae): Likewise. Drop
the potentially-constant check, and relax and turn the
dependence check into a checking assert.
(instantiate_non_dependent_or_null): Adjust comment.
* semantics.cc (finish_decltype_type): Keep
processing_template_decl cleared after calling
instantiate_non_dependent_expr_sfinae.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/Wnarrowing19.C: New test.
---
gcc/cp/except.cc | 2 +-
gcc/cp/parser.cc | 8 -------
gcc/cp/pt.cc | 24 ++++++-------------
gcc/cp/semantics.cc | 6 +++++
gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C | 8 +++++++
.../g++.dg/cpp0x/constexpr-attribute4.C | 14 +++++++++++
6 files changed, 36 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 9b746be231a..da0a65c613d 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -1253,7 +1253,7 @@ build_noexcept_spec (tree expr, tsubst_flags_t complain)
if (check_for_bare_parameter_packs (expr))
return error_mark_node;
if (TREE_CODE (expr) != DEFERRED_NOEXCEPT
- && !value_dependent_expression_p (expr))
+ && !instantiation_dependent_expression_p (expr))
{
expr = build_converted_constant_bool_expr (expr, complain);
expr = instantiate_non_dependent_expr_sfinae (expr, complain);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 20aab5eb6b1..c9de8e8d050 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7958,7 +7958,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
static cp_expr
cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
bool allow_expansion_p,
- bool fold_expr_p,
bool *non_constant_p)
{
cp_expr expr (NULL_TREE);
@@ -7985,9 +7984,6 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
else
expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
- if (fold_expr_p)
- expr = instantiate_non_dependent_expr (expr);
-
/* If we have an ellipsis, then this is an expression expansion. */
if (allow_expansion_p
&& cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
@@ -8053,8 +8049,6 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
false,
/*allow_exp_p=*/
true,
- /*fold_expr_p=*/
- false,
/*non_cst_p=*/
NULL);
@@ -8424,7 +8418,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
bool wrap_locations_p)
{
vec<tree, va_gc> *expression_list;
- bool fold_expr_p = is_attribute_list != non_attr;
tree identifier = NULL_TREE;
bool saved_greater_than_is_operator_p;
@@ -8467,7 +8460,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
expr
= cp_parser_parenthesized_expression_list_elt (parser, cast_p,
allow_expansion_p,
- fold_expr_p,
non_constant_p);
if (wrap_locations_p)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e8b5d8fbb73..75b43ba60fe 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3817,7 +3817,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
tree hi = tsubst_copy_and_build (ohi, args, complain, in_decl,
false/*fn*/, true/*int_cst*/);
- if (value_dependent_expression_p (hi))
+ if (instantiation_dependent_expression_p (hi))
{
if (hi != ohi)
{
@@ -6349,9 +6349,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
/* The actual substitution part of instantiate_non_dependent_expr_sfinae,
to be used when the caller has already checked
- (processing_template_decl
- && !instantiation_dependent_expression_p (expr)
- && potential_constant_expression (expr))
+ !instantiation_dependent_uneval_expression_p (expr)
and cleared processing_template_decl. */
tree
@@ -6365,8 +6363,7 @@ instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
/*integral_constant_expression_p=*/true);
}
-/* Simplify EXPR if it is a non-dependent expression. Returns the
- (possibly simplified) expression. */
+/* Instantiate the non-dependent expression EXPR. */
tree
instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
@@ -6374,16 +6371,9 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
if (expr == NULL_TREE)
return NULL_TREE;
- /* If we're in a template, but EXPR isn't value dependent, simplify
- it. We're supposed to treat:
-
- template <typename T> void f(T[1 + 1]);
- template <typename T> void f(T[2]);
-
- as two declarations of the same function, for example. */
- if (processing_template_decl
- && is_nondependent_constant_expression (expr))
+ if (processing_template_decl)
{
+ gcc_checking_assert (!instantiation_dependent_uneval_expression_p (expr));
processing_template_decl_sentinel s;
expr = instantiate_non_dependent_expr_internal (expr, complain);
}
@@ -6396,8 +6386,8 @@ instantiate_non_dependent_expr (tree expr)
return instantiate_non_dependent_expr_sfinae (expr, tf_error);
}
-/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
- an uninstantiated expression. */
+/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
+ expression is dependent or non-constant. */
tree
instantiate_non_dependent_or_null (tree expr)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 07cae993efe..773a83eec3d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
/* decltype is an unevaluated context. */
cp_unevaluated u;
+ processing_template_decl_sentinel ptds (/*reset=*/false);
+
/* Depending on the resolution of DR 1172, we may later need to distinguish
instantiation-dependent but not type-dependent expressions so that, say,
A<decltype(sizeof(T))>::U doesn't require 'typename'. */
@@ -11235,6 +11237,10 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
expr = instantiate_non_dependent_expr_sfinae (expr, complain);
if (expr == error_mark_node)
return error_mark_node;
+ /* Keep processing_template_decl cleared for the rest of the function
+ (for sake of the call to lvalue_kind below, which handles templated
+ and non-templated COND_EXPR differently). */
+ processing_template_decl = 0;
}
/* The type denoted by decltype(e) is defined as follows: */
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
new file mode 100644
index 00000000000..bd9fd2eb6f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
@@ -0,0 +1,8 @@
+// PR c++/104823
+// { dg-do compile { target c++11 } }
+
+struct S { S(int); };
+
+double id(double v);
+
+template<class> auto f(double v) -> decltype(S{id(v)}); // { dg-error "narrowing" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
new file mode 100644
index 00000000000..2cff6d333f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
@@ -0,0 +1,14 @@
+// Verify we correctly handle the non-dependent attribute expression which,
+// if we were to instantiate it twice, would result in a bogus error.
+// { dg-do compile { target { c++11 } } }
+
+struct A {
+ constexpr int f() const { return __alignof__(int); };
+};
+
+template<class...>
+void f() {
+ int a __attribute__((aligned(A{}.f())));
+}
+
+template void f();
--
2.35.1.415.gc2162907e9
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
2022-03-08 20:57 ` Patrick Palka
@ 2022-03-08 22:23 ` Jason Merrill
0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2022-03-08 22:23 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 3/8/22 16:57, Patrick Palka wrote:
> On Tue, 8 Mar 2022, Jason Merrill wrote:
>
>> On 3/8/22 12:54, Patrick Palka wrote:
>>>
>>>
>>> On Mon, 7 Mar 2022, Jason Merrill wrote:
>>>
>>>> On 3/7/22 14:41, Patrick Palka wrote:
>>>>> instantiate_non_dependent_expr_sfinae instantiates only potentially
>>>>> constant expressions
>>>>
>>>> Hmm, that now strikes me as a problematic interface, as we don't know
>>>> whether
>>>> what we get back is template or non-template trees.
>>>>
>>>> Maybe we want to change instantiate_non_dependent_expr to checking_assert
>>>> that
>>>> the argument is non-dependent (callers are already checking that), and
>>>> drop
>>>> the potentially-constant test?
>>>
>>> That sounds like a nice improvement. But it happens to break
>>>
>>> template<int N> using type = decltype(N);
>>>
>>> beause finish_decltype_type checks
>>> instantiation_dependent_uneval_expression_p
>>> (which is false here) instead of instantiation_dependent_expression_p
>>> (which is true here) before calling instantiate_non_dependent_expr, so
>>> we end up tripping over the proposed checking_assert (which checks the
>>> latter stronger form of dependence).
>>>
>>> I suspect other callers of instantiate_non_dependent_expr might have a
>>> similar problem if they use a weaker dependence check than
>>> instantiation_dependent_expression_p, e.g. build_noexcept_spec only
>>> checks value_dependent_expression_p.
>>>
>>> I wonder if we should relax the proposed checking_assert in i_n_d_e, or
>>> strengthen the dependence checks performed by its callers, or something
>>> else?
>>
>> I think relax the assert to _uneval and strengthen callers that use value_dep.
>
> Sounds good, like so? Note this patch doesn't touch
> instantiate_non_dependent_or_null or fold_non_dependent_expr, since the
> former already never returns a templated tree, and callers of the latter
> should only care about the constant-ness not template-ness of the result
> IIUC.
>
> Boostrapped and regtested on x86_64-pc-linux-gnu.
>
> -- >8 --
>
> Subject: [PATCH] c++: non-constant non-dependent decltype folding [PR104823]
>
> When processing a non-dependent decltype operand we want to instantiate
> it even if it's non-constant since non-dependent decltype is always
> resolved ahead of time. But currently finish_decltype_type uses
> instantiate_non_dependent_expr, which instantiates only potentially
> constant expressions, and this causes us to miss diagnosing the narrowing
> conversion in S{id(v)} in the below testcase because we never instantiate
> this non-constant non-dependent decltype operand.
>
> In light of
>
> > On Mon, 7 Mar 2022, Jason Merrill wrote:
> >> On 3/7/22 14:41, Patrick Palka wrote:
> >>> instantiate_non_dependent_expr instantiates only potentially constant
> >>> expressions
> >>
> >> Hmm, that now strikes me as a problematic interface, as we don't know whether
> >> what we get back is template or non-template trees.
>
> this patch drops the potentially-constant check in i_n_d_e, and turns
> its dependence check into a checking_assert, since most callers already
> check that the argument is non-dependent. This patch also relaxes the
> dependence check in i_n_d_e to use the _uneval version and strengthens
> the dependence checks used by callers accordingly.
>
> In cp_parser_parenthesized_expression_list_elt we were calling
> instantiate_non_dependent_expr without first checking for non-dependence.
> We could fix this by guarding the call appropriately, but I noticed we
> also fold non-dependent attributes later from cp_check_const_attribute.
> This double instantiation causes us to reject constexpr-attribute4.C
> below due to the second folding seeing non-templated trees (an existing
> bug). Thus the right solution here seems to be to remove this unguarded
> call to i_n_d_e so that we end up folding non-dependent attributes only
> once.
>
> Finally, after calling i_n_d_e in finish_decltype_type we need to keep
> processing_template_decl cleared for sake of the later call to
> lvalue_kind, which handles templated and non-templated COND_EXPR
> differently. Otherwise we'd incorrectly reject the declaration of g in
> cpp0x/cond2.C with:
>
> error: 'g' declared as function returning a function
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
>
> PR c++/104823
>
> gcc/cp/ChangeLog:
>
> * except.cc (build_noexcept_spec): Strengthen dependence check
> to instantiation_dependent_expression_p.
> * parser.cc (cp_parser_parenthesized_expression_list_elt):
> Remove fold_expr_p parameter and call
> instantiate_non_dependent_expr.
> (cp_parser_parenthesized_expression_list): Adjust accordingly.
> * pt.cc (expand_integer_pack): Strengthen dependence check
> to instantiation_dependent_expression_p.
> (instantiate_non_dependent_expr_internal): Adjust comment.
> (instantiate_non_dependent_expr_sfinae): Likewise. Drop
> the potentially-constant check, and relax and turn the
> dependence check into a checking assert.
> (instantiate_non_dependent_or_null): Adjust comment.
> * semantics.cc (finish_decltype_type): Keep
> processing_template_decl cleared after calling
> instantiate_non_dependent_expr_sfinae.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/Wnarrowing19.C: New test.
> ---
> gcc/cp/except.cc | 2 +-
> gcc/cp/parser.cc | 8 -------
> gcc/cp/pt.cc | 24 ++++++-------------
> gcc/cp/semantics.cc | 6 +++++
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C | 8 +++++++
> .../g++.dg/cpp0x/constexpr-attribute4.C | 14 +++++++++++
> 6 files changed, 36 insertions(+), 26 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
>
> diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
> index 9b746be231a..da0a65c613d 100644
> --- a/gcc/cp/except.cc
> +++ b/gcc/cp/except.cc
> @@ -1253,7 +1253,7 @@ build_noexcept_spec (tree expr, tsubst_flags_t complain)
> if (check_for_bare_parameter_packs (expr))
> return error_mark_node;
> if (TREE_CODE (expr) != DEFERRED_NOEXCEPT
> - && !value_dependent_expression_p (expr))
> + && !instantiation_dependent_expression_p (expr))
> {
> expr = build_converted_constant_bool_expr (expr, complain);
> expr = instantiate_non_dependent_expr_sfinae (expr, complain);
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 20aab5eb6b1..c9de8e8d050 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -7958,7 +7958,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
> static cp_expr
> cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
> bool allow_expansion_p,
> - bool fold_expr_p,
> bool *non_constant_p)
> {
> cp_expr expr (NULL_TREE);
> @@ -7985,9 +7984,6 @@ cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p,
> else
> expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p);
>
> - if (fold_expr_p)
> - expr = instantiate_non_dependent_expr (expr);
> -
> /* If we have an ellipsis, then this is an expression expansion. */
> if (allow_expansion_p
> && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
> @@ -8053,8 +8049,6 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
> false,
> /*allow_exp_p=*/
> true,
> - /*fold_expr_p=*/
> - false,
> /*non_cst_p=*/
> NULL);
>
> @@ -8424,7 +8418,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
> bool wrap_locations_p)
> {
> vec<tree, va_gc> *expression_list;
> - bool fold_expr_p = is_attribute_list != non_attr;
> tree identifier = NULL_TREE;
> bool saved_greater_than_is_operator_p;
>
> @@ -8467,7 +8460,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
> expr
> = cp_parser_parenthesized_expression_list_elt (parser, cast_p,
> allow_expansion_p,
> - fold_expr_p,
> non_constant_p);
>
> if (wrap_locations_p)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index e8b5d8fbb73..75b43ba60fe 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -3817,7 +3817,7 @@ expand_integer_pack (tree call, tree args, tsubst_flags_t complain,
> tree hi = tsubst_copy_and_build (ohi, args, complain, in_decl,
> false/*fn*/, true/*int_cst*/);
>
> - if (value_dependent_expression_p (hi))
> + if (instantiation_dependent_expression_p (hi))
> {
> if (hi != ohi)
> {
> @@ -6349,9 +6349,7 @@ redeclare_class_template (tree type, tree parms, tree cons)
>
> /* The actual substitution part of instantiate_non_dependent_expr_sfinae,
> to be used when the caller has already checked
> - (processing_template_decl
> - && !instantiation_dependent_expression_p (expr)
> - && potential_constant_expression (expr))
> + !instantiation_dependent_uneval_expression_p (expr)
> and cleared processing_template_decl. */
>
> tree
> @@ -6365,8 +6363,7 @@ instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
> /*integral_constant_expression_p=*/true);
> }
>
> -/* Simplify EXPR if it is a non-dependent expression. Returns the
> - (possibly simplified) expression. */
> +/* Instantiate the non-dependent expression EXPR. */
>
> tree
> instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
> @@ -6374,16 +6371,9 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
> if (expr == NULL_TREE)
> return NULL_TREE;
>
> - /* If we're in a template, but EXPR isn't value dependent, simplify
> - it. We're supposed to treat:
> -
> - template <typename T> void f(T[1 + 1]);
> - template <typename T> void f(T[2]);
> -
> - as two declarations of the same function, for example. */
> - if (processing_template_decl
> - && is_nondependent_constant_expression (expr))
> + if (processing_template_decl)
> {
> + gcc_checking_assert (!instantiation_dependent_uneval_expression_p (expr));
Let's add a comment that the caller should have checked this already.
OK with that change.
> processing_template_decl_sentinel s;
> expr = instantiate_non_dependent_expr_internal (expr, complain);
> }
> @@ -6396,8 +6386,8 @@ instantiate_non_dependent_expr (tree expr)
> return instantiate_non_dependent_expr_sfinae (expr, tf_error);
> }
>
> -/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
> - an uninstantiated expression. */
> +/* Like instantiate_non_dependent_expr, but return NULL_TREE if the
> + expression is dependent or non-constant. */
>
> tree
> instantiate_non_dependent_or_null (tree expr)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 07cae993efe..773a83eec3d 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -11217,6 +11217,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
> /* decltype is an unevaluated context. */
> cp_unevaluated u;
>
> + processing_template_decl_sentinel ptds (/*reset=*/false);
> +
> /* Depending on the resolution of DR 1172, we may later need to distinguish
> instantiation-dependent but not type-dependent expressions so that, say,
> A<decltype(sizeof(T))>::U doesn't require 'typename'. */
> @@ -11235,6 +11237,10 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
> expr = instantiate_non_dependent_expr_sfinae (expr, complain);
> if (expr == error_mark_node)
> return error_mark_node;
> + /* Keep processing_template_decl cleared for the rest of the function
> + (for sake of the call to lvalue_kind below, which handles templated
> + and non-templated COND_EXPR differently). */
> + processing_template_decl = 0;
> }
>
> /* The type denoted by decltype(e) is defined as follows: */
> diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
> new file mode 100644
> index 00000000000..bd9fd2eb6f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing19.C
> @@ -0,0 +1,8 @@
> +// PR c++/104823
> +// { dg-do compile { target c++11 } }
> +
> +struct S { S(int); };
> +
> +double id(double v);
> +
> +template<class> auto f(double v) -> decltype(S{id(v)}); // { dg-error "narrowing" }
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
> new file mode 100644
> index 00000000000..2cff6d333f9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-attribute4.C
> @@ -0,0 +1,14 @@
> +// Verify we correctly handle the non-dependent attribute expression which,
> +// if we were to instantiate it twice, would result in a bogus error.
> +// { dg-do compile { target { c++11 } } }
> +
> +struct A {
> + constexpr int f() const { return __alignof__(int); };
> +};
> +
> +template<class...>
> +void f() {
> + int a __attribute__((aligned(A{}.f())));
> +}
> +
> +template void f();
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2022-03-08 22:24 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-07 18:41 [PATCH] c++: non-constant non-dependent decltype folding [PR104823] Patrick Palka
2022-03-07 19:09 ` Jason Merrill
2022-03-08 16:54 ` Patrick Palka
2022-03-08 18:27 ` Jason Merrill
2022-03-08 20:57 ` Patrick Palka
2022-03-08 22:23 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).