public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).