Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-08 Thread Patrick Palka via Gcc-patches
On Tue, 7 Apr 2020, Jason Merrill wrote:
> On 4/7/20 1:40 PM, Patrick Palka wrote:
> > On Mon, 6 Apr 2020, Jason Merrill wrote:
> > > On 4/6/20 11:45 AM, Patrick Palka wrote:
> > > > On Wed, 1 Apr 2020, Jason Merrill wrote:
> > > > 
> > > > > On 4/1/20 6:29 PM, Jason Merrill wrote:
> > > > > > On 3/31/20 3:50 PM, Patrick Palka wrote:
> > > > > > > On Tue, 31 Mar 2020, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 3/30/20 6:46 PM, Patrick Palka wrote:
> > > > > > > > > On Mon, 30 Mar 2020, Jason Merrill wrote:
> > > > > > > > > > On 3/30/20 3:58 PM, Patrick Palka wrote:
> > > > > > > > > > > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > > > > > > > > > > 
> > > > > > > > > > > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > > > > > > > > > > This patch relaxes an assertion in
> > > > > > > > > > > > > tsubst_default_argument
> > > > > > > > > > > > > that
> > > > > > > > > > > > > exposes
> > > > > > > > > > > > > a
> > > > > > > > > > > > > latent
> > > > > > > > > > > > > bug in how we substitute an array type into a
> > > > > > > > > > > > > cv-qualified
> > > > > > > > > > > > > wildcard
> > > > > > > > > > > > > function
> > > > > > > > > > > > > parameter type.  Concretely, the latent bug is that
> > > > > > > > > > > > > given
> > > > > > > > > > > > > the
> > > > > > > > > > > > > function
> > > > > > > > > > > > > template
> > > > > > > > > > > > > 
> > > > > > > > > > > > >     template void foo(const T t);
> > > > > > > > > > > > > 
> > > > > > > > > > > > > one would expect the type of foo to be
> > > > > > > > > > > > > void(const
> > > > > > > > > > > > > int*), but
> > > > > > > > > > > > > we
> > > > > > > > > > > > > (seemingly prematurely) strip function parameter types
> > > > > > > > > > > > > of
> > > > > > > > > > > > > their
> > > > > > > > > > > > > top-level
> > > > > > > > > > > > > cv-qualifiers when building the function's
> > > > > > > > > > > > > TYPE_ARG_TYPES,
> > > > > > > > > > > > > and
> > > > > > > > > > > > > instead
> > > > > > > > > > > > > end
> > > > > > > > > > > > > up
> > > > > > > > > > > > > obtaining void(int*) as the type of foo after
> > > > > > > > > > > > > substitution
> > > > > > > > > > > > > and
> > > > > > > > > > > > > decaying.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > We still however correctly substitute into and decay
> > > > > > > > > > > > > the
> > > > > > > > > > > > > formal
> > > > > > > > > > > > > parameter
> > > > > > > > > > > > > type,
> > > > > > > > > > > > > obtaining const int* as the type of t after
> > > > > > > > > > > > > substitution.
> > > > > > > > > > > > > But
> > > > > > > > > > > > > this
> > > > > > > > > > > > > then
> > > > > > > > > > > > > leads
> > > > > > > > > > > > > to us tripping over the assert in
> > > > > > > > > > > > > tsubst_default_argument
> > > > > > > > > > > > > that
> > > > > > > > > > > > > verifies
> > > > > > > > > > > > > the
> > > > > > > > > > > > > formal parameter type and the function type are
> > > > > > > > > > > > > consistent.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Assuming it's too late at this stage to fix the
> > > > > > > > > > > > > substitution
> > > > > > > > > > > > > bug, we
> > > > > > > > > > > > > can
> > > > > > > > > > > > > still
> > > > > > > > > > > > > relax the assertion like so.  Tested on
> > > > > > > > > > > > > x86_64-pc-linux-gnu,
> > > > > > > > > > > > > does
> > > > > > > > > > > > > this
> > > > > > > > > > > > > look
> > > > > > > > > > > > > OK?
> > > > > > > > > > > > 
> > > > > > > > > > > > This is core issues 1001/1322, which have not been
> > > > > > > > > > > > resolved.
> > > > > > > > > > > > Clang
> > > > > > > > > > > > does
> > > > > > > > > > > > the
> > > > > > > > > > > > substitution the way you suggest; EDG rejects the
> > > > > > > > > > > > testcase
> > > > > > > > > > > > because the
> > > > > > > > > > > > two
> > > > > > > > > > > > substitutions produce different results.  I think it
> > > > > > > > > > > > would
> > > > > > > > > > > > make
> > > > > > > > > > > > sense
> > > > > > > > > > > > to
> > > > > > > > > > > > follow the EDG behavior until this issue is actually
> > > > > > > > > > > > resolved.
> > > > > > > > > > > 
> > > > > > > > > > > Here is what I have so far towards that end.  When
> > > > > > > > > > > substituting
> > > > > > > > > > > into the
> > > > > > > > > > > PARM_DECLs of a function decl, we now additionally check
> > > > > > > > > > > if
> > > > > > > > > > > the
> > > > > > > > > > > aforementioned Core issues are relevant and issue a
> > > > > > > > > > > (fatal)
> > > > > > > > > > > diagnostic
> > > > > > > > > > > if so.  This patch checks this in tsubst_decl  > > > > > > > > > > PARM_DECL>
> > > > > > > > > > > rather
> > > > > > > > > > > than in tsubst_function_decl for efficiency reasons, so
> > > > > > > > > > > that
> > > > > > > > > > > we
> > > > > > > > > > > don't
> > > > > > > > > > > have to perform another traversal over the DECL_ARGUMENTS
> > > 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-07 Thread Jason Merrill via Gcc-patches

On 4/7/20 1:40 PM, Patrick Palka wrote:

On Mon, 6 Apr 2020, Jason Merrill wrote:

On 4/6/20 11:45 AM, Patrick Palka wrote:

On Wed, 1 Apr 2020, Jason Merrill wrote:


On 4/1/20 6:29 PM, Jason Merrill wrote:

On 3/31/20 3:50 PM, Patrick Palka wrote:

On Tue, 31 Mar 2020, Jason Merrill wrote:


On 3/30/20 6:46 PM, Patrick Palka wrote:

On Mon, 30 Mar 2020, Jason Merrill wrote:

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument
that
exposes
a
latent
bug in how we substitute an array type into a cv-qualified
wildcard
function
parameter type.  Concretely, the latent bug is that given
the
function
template

    template void foo(const T t);

one would expect the type of foo to be void(const
int*), but
we
(seemingly prematurely) strip function parameter types of
their
top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES,
and
instead
end
up
obtaining void(int*) as the type of foo after
substitution
and
decaying.

We still however correctly substitute into and decay the
formal
parameter
type,
obtaining const int* as the type of t after substitution.
But
this
then
leads
to us tripping over the assert in tsubst_default_argument
that
verifies
the
formal parameter type and the function type are
consistent.

Assuming it's too late at this stage to fix the
substitution
bug, we
can
still
relax the assertion like so.  Tested on
x86_64-pc-linux-gnu,
does
this
look
OK?


This is core issues 1001/1322, which have not been resolved.
Clang
does
the
substitution the way you suggest; EDG rejects the testcase
because the
two
substitutions produce different results.  I think it would
make
sense
to
follow the EDG behavior until this issue is actually
resolved.


Here is what I have so far towards that end.  When
substituting
into the
PARM_DECLs of a function decl, we now additionally check if
the
aforementioned Core issues are relevant and issue a (fatal)
diagnostic
if so.  This patch checks this in tsubst_decl 
rather
than in tsubst_function_decl for efficiency reasons, so that
we
don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very
marginal
optimization; how many function templates have so many
parameters
that
walking
over them once to compare types will have any effect on compile
time?


Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated
to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then
since
we have access to the instantiated function, it would presumably
suffice
to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would
certainly
catch the original testcase, i.e.

      template
    void foo(const T);
      int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and
its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch
the
corresponding testcase that uses a function parameter pack, i.e.

      template
    void foo(const Ts...);
      int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time,
as
we
do with regular function parameters.  So in this second testcase
both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const
int*},
and yet we would (presumably) want to reject this instantiation
too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to
do
a
variant of the trick that's done in this patch, i.e. substitute
into
each dependent parameter type stripped of its top-level
cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to
detect
this?


I think let's go ahead with comparing TYPE_ARG_TYPES and
DECL_ARGUMENTS;
the
problem comes when they disagree.  If we're handling pack expansions
wrong,
that's a separate issue.


Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility
seems
to be exposing a latent bug with how we handle lambdas that appear in
function parameter types.  Take g++.dg/cpp2a/lambda-uneval3.C for
example:

   template  void spam(decltype([]{}) (*s)[sizeof(T)]) {}
   int main() { spam(nullptr); }

According to tsubst_function_decl in current trunk, the type of the
function paremeter 's' of spam according to its TYPE_ARG_TYPES
is
   struct ._anon_4[1] *
and according to its DECL_ARGUMENTS the type of 's' is
   struct ._anon_5[1] *

The disagreement happens because we call tsubst_lambda_expr twice
during
substitution and thereby generate two distinct lambda 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-07 Thread Patrick Palka via Gcc-patches
On Tue, 7 Apr 2020, Patrick Palka wrote:
> On Mon, 6 Apr 2020, Jason Merrill wrote:
> > On 4/6/20 11:45 AM, Patrick Palka wrote:
> > > On Wed, 1 Apr 2020, Jason Merrill wrote:
> > > 
> > > > On 4/1/20 6:29 PM, Jason Merrill wrote:
> > > > > On 3/31/20 3:50 PM, Patrick Palka wrote:
> > > > > > On Tue, 31 Mar 2020, Jason Merrill wrote:
> > > > > > 
> > > > > > > On 3/30/20 6:46 PM, Patrick Palka wrote:
> > > > > > > > On Mon, 30 Mar 2020, Jason Merrill wrote:
> > > > > > > > > On 3/30/20 3:58 PM, Patrick Palka wrote:
> > > > > > > > > > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > > > > > > > > > 
> > > > > > > > > > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > > > > > > > > > This patch relaxes an assertion in 
> > > > > > > > > > > > tsubst_default_argument
> > > > > > > > > > > > that
> > > > > > > > > > > > exposes
> > > > > > > > > > > > a
> > > > > > > > > > > > latent
> > > > > > > > > > > > bug in how we substitute an array type into a 
> > > > > > > > > > > > cv-qualified
> > > > > > > > > > > > wildcard
> > > > > > > > > > > > function
> > > > > > > > > > > > parameter type.  Concretely, the latent bug is that 
> > > > > > > > > > > > given
> > > > > > > > > > > > the
> > > > > > > > > > > > function
> > > > > > > > > > > > template
> > > > > > > > > > > > 
> > > > > > > > > > > >    template void foo(const T t);
> > > > > > > > > > > > 
> > > > > > > > > > > > one would expect the type of foo to be void(const
> > > > > > > > > > > > int*), but
> > > > > > > > > > > > we
> > > > > > > > > > > > (seemingly prematurely) strip function parameter types 
> > > > > > > > > > > > of
> > > > > > > > > > > > their
> > > > > > > > > > > > top-level
> > > > > > > > > > > > cv-qualifiers when building the function's 
> > > > > > > > > > > > TYPE_ARG_TYPES,
> > > > > > > > > > > > and
> > > > > > > > > > > > instead
> > > > > > > > > > > > end
> > > > > > > > > > > > up
> > > > > > > > > > > > obtaining void(int*) as the type of foo after
> > > > > > > > > > > > substitution
> > > > > > > > > > > > and
> > > > > > > > > > > > decaying.
> > > > > > > > > > > > 
> > > > > > > > > > > > We still however correctly substitute into and decay the
> > > > > > > > > > > > formal
> > > > > > > > > > > > parameter
> > > > > > > > > > > > type,
> > > > > > > > > > > > obtaining const int* as the type of t after 
> > > > > > > > > > > > substitution. 
> > > > > > > > > > > > But
> > > > > > > > > > > > this
> > > > > > > > > > > > then
> > > > > > > > > > > > leads
> > > > > > > > > > > > to us tripping over the assert in 
> > > > > > > > > > > > tsubst_default_argument
> > > > > > > > > > > > that
> > > > > > > > > > > > verifies
> > > > > > > > > > > > the
> > > > > > > > > > > > formal parameter type and the function type are
> > > > > > > > > > > > consistent.
> > > > > > > > > > > > 
> > > > > > > > > > > > Assuming it's too late at this stage to fix the
> > > > > > > > > > > > substitution
> > > > > > > > > > > > bug, we
> > > > > > > > > > > > can
> > > > > > > > > > > > still
> > > > > > > > > > > > relax the assertion like so.  Tested on
> > > > > > > > > > > > x86_64-pc-linux-gnu,
> > > > > > > > > > > > does
> > > > > > > > > > > > this
> > > > > > > > > > > > look
> > > > > > > > > > > > OK?
> > > > > > > > > > > 
> > > > > > > > > > > This is core issues 1001/1322, which have not been 
> > > > > > > > > > > resolved.
> > > > > > > > > > > Clang
> > > > > > > > > > > does
> > > > > > > > > > > the
> > > > > > > > > > > substitution the way you suggest; EDG rejects the testcase
> > > > > > > > > > > because the
> > > > > > > > > > > two
> > > > > > > > > > > substitutions produce different results.  I think it would
> > > > > > > > > > > make
> > > > > > > > > > > sense
> > > > > > > > > > > to
> > > > > > > > > > > follow the EDG behavior until this issue is actually
> > > > > > > > > > > resolved.
> > > > > > > > > > 
> > > > > > > > > > Here is what I have so far towards that end.  When
> > > > > > > > > > substituting
> > > > > > > > > > into the
> > > > > > > > > > PARM_DECLs of a function decl, we now additionally check if
> > > > > > > > > > the
> > > > > > > > > > aforementioned Core issues are relevant and issue a (fatal)
> > > > > > > > > > diagnostic
> > > > > > > > > > if so.  This patch checks this in tsubst_decl  > > > > > > > > > PARM_DECL>
> > > > > > > > > > rather
> > > > > > > > > > than in tsubst_function_decl for efficiency reasons, so that
> > > > > > > > > > we
> > > > > > > > > > don't
> > > > > > > > > > have to perform another traversal over the DECL_ARGUMENTS /
> > > > > > > > > > TYPE_ARG_TYPES just to implement this check.
> > > > > > > > > 
> > > > > > > > > Hmm, this seems like writing more complicated code for a very
> > > > > > > > > marginal
> > > > > > > > > optimization; how many function templates have so many
> > > > > > > > > parameters
> > > > > > > > > that
> > > > > > > > > walking
> > > > > > > > > over them once to compare types will have any effect on 
> > 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-07 Thread Patrick Palka via Gcc-patches
On Mon, 6 Apr 2020, Jason Merrill wrote:
> On 4/6/20 11:45 AM, Patrick Palka wrote:
> > On Wed, 1 Apr 2020, Jason Merrill wrote:
> > 
> > > On 4/1/20 6:29 PM, Jason Merrill wrote:
> > > > On 3/31/20 3:50 PM, Patrick Palka wrote:
> > > > > On Tue, 31 Mar 2020, Jason Merrill wrote:
> > > > > 
> > > > > > On 3/30/20 6:46 PM, Patrick Palka wrote:
> > > > > > > On Mon, 30 Mar 2020, Jason Merrill wrote:
> > > > > > > > On 3/30/20 3:58 PM, Patrick Palka wrote:
> > > > > > > > > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > > > > > > > > 
> > > > > > > > > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > > > > > > > > This patch relaxes an assertion in tsubst_default_argument
> > > > > > > > > > > that
> > > > > > > > > > > exposes
> > > > > > > > > > > a
> > > > > > > > > > > latent
> > > > > > > > > > > bug in how we substitute an array type into a cv-qualified
> > > > > > > > > > > wildcard
> > > > > > > > > > > function
> > > > > > > > > > > parameter type.  Concretely, the latent bug is that given
> > > > > > > > > > > the
> > > > > > > > > > > function
> > > > > > > > > > > template
> > > > > > > > > > > 
> > > > > > > > > > >    template void foo(const T t);
> > > > > > > > > > > 
> > > > > > > > > > > one would expect the type of foo to be void(const
> > > > > > > > > > > int*), but
> > > > > > > > > > > we
> > > > > > > > > > > (seemingly prematurely) strip function parameter types of
> > > > > > > > > > > their
> > > > > > > > > > > top-level
> > > > > > > > > > > cv-qualifiers when building the function's TYPE_ARG_TYPES,
> > > > > > > > > > > and
> > > > > > > > > > > instead
> > > > > > > > > > > end
> > > > > > > > > > > up
> > > > > > > > > > > obtaining void(int*) as the type of foo after
> > > > > > > > > > > substitution
> > > > > > > > > > > and
> > > > > > > > > > > decaying.
> > > > > > > > > > > 
> > > > > > > > > > > We still however correctly substitute into and decay the
> > > > > > > > > > > formal
> > > > > > > > > > > parameter
> > > > > > > > > > > type,
> > > > > > > > > > > obtaining const int* as the type of t after substitution. 
> > > > > > > > > > > But
> > > > > > > > > > > this
> > > > > > > > > > > then
> > > > > > > > > > > leads
> > > > > > > > > > > to us tripping over the assert in tsubst_default_argument
> > > > > > > > > > > that
> > > > > > > > > > > verifies
> > > > > > > > > > > the
> > > > > > > > > > > formal parameter type and the function type are
> > > > > > > > > > > consistent.
> > > > > > > > > > > 
> > > > > > > > > > > Assuming it's too late at this stage to fix the
> > > > > > > > > > > substitution
> > > > > > > > > > > bug, we
> > > > > > > > > > > can
> > > > > > > > > > > still
> > > > > > > > > > > relax the assertion like so.  Tested on
> > > > > > > > > > > x86_64-pc-linux-gnu,
> > > > > > > > > > > does
> > > > > > > > > > > this
> > > > > > > > > > > look
> > > > > > > > > > > OK?
> > > > > > > > > > 
> > > > > > > > > > This is core issues 1001/1322, which have not been resolved.
> > > > > > > > > > Clang
> > > > > > > > > > does
> > > > > > > > > > the
> > > > > > > > > > substitution the way you suggest; EDG rejects the testcase
> > > > > > > > > > because the
> > > > > > > > > > two
> > > > > > > > > > substitutions produce different results.  I think it would
> > > > > > > > > > make
> > > > > > > > > > sense
> > > > > > > > > > to
> > > > > > > > > > follow the EDG behavior until this issue is actually
> > > > > > > > > > resolved.
> > > > > > > > > 
> > > > > > > > > Here is what I have so far towards that end.  When
> > > > > > > > > substituting
> > > > > > > > > into the
> > > > > > > > > PARM_DECLs of a function decl, we now additionally check if
> > > > > > > > > the
> > > > > > > > > aforementioned Core issues are relevant and issue a (fatal)
> > > > > > > > > diagnostic
> > > > > > > > > if so.  This patch checks this in tsubst_decl 
> > > > > > > > > rather
> > > > > > > > > than in tsubst_function_decl for efficiency reasons, so that
> > > > > > > > > we
> > > > > > > > > don't
> > > > > > > > > have to perform another traversal over the DECL_ARGUMENTS /
> > > > > > > > > TYPE_ARG_TYPES just to implement this check.
> > > > > > > > 
> > > > > > > > Hmm, this seems like writing more complicated code for a very
> > > > > > > > marginal
> > > > > > > > optimization; how many function templates have so many
> > > > > > > > parameters
> > > > > > > > that
> > > > > > > > walking
> > > > > > > > over them once to compare types will have any effect on compile
> > > > > > > > time?
> > > > > > > 
> > > > > > > Good point... though I just tried implementing this check in
> > > > > > > tsubst_function_decl, and it seems it might be just as complicated
> > > > > > > to
> > > > > > > implement it there instead, at least if we want to handle function
> > > > > > > parameter packs correctly.
> > > > > > > 
> > > > > > > If we were to implement this check in tsubst_function_decl, then
> > > > > > > since
> > > > > > > we have access to the 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-06 Thread Jason Merrill via Gcc-patches

On 4/6/20 11:45 AM, Patrick Palka wrote:

On Wed, 1 Apr 2020, Jason Merrill wrote:


On 4/1/20 6:29 PM, Jason Merrill wrote:

On 3/31/20 3:50 PM, Patrick Palka wrote:

On Tue, 31 Mar 2020, Jason Merrill wrote:


On 3/30/20 6:46 PM, Patrick Palka wrote:

On Mon, 30 Mar 2020, Jason Merrill wrote:

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument
that
exposes
a
latent
bug in how we substitute an array type into a cv-qualified
wildcard
function
parameter type.  Concretely, the latent bug is that given the
function
template

   template void foo(const T t);

one would expect the type of foo to be void(const
int*), but
we
(seemingly prematurely) strip function parameter types of
their
top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and
instead
end
up
obtaining void(int*) as the type of foo after
substitution
and
decaying.

We still however correctly substitute into and decay the
formal
parameter
type,
obtaining const int* as the type of t after substitution.  But
this
then
leads
to us tripping over the assert in tsubst_default_argument that
verifies
the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution
bug, we
can
still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu,
does
this
look
OK?


This is core issues 1001/1322, which have not been resolved.
Clang
does
the
substitution the way you suggest; EDG rejects the testcase
because the
two
substitutions produce different results.  I think it would make
sense
to
follow the EDG behavior until this issue is actually resolved.


Here is what I have so far towards that end.  When substituting
into the
PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal)
diagnostic
if so.  This patch checks this in tsubst_decl 
rather
than in tsubst_function_decl for efficiency reasons, so that we
don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very
marginal
optimization; how many function templates have so many parameters
that
walking
over them once to compare types will have any effect on compile
time?


Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then since
we have access to the instantiated function, it would presumably
suffice
to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
catch the original testcase, i.e.

     template
   void foo(const T);
     int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
corresponding testcase that uses a function parameter pack, i.e.

     template
   void foo(const Ts...);
     int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time, as
we
do with regular function parameters.  So in this second testcase both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
and yet we would (presumably) want to reject this instantiation too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to do
a
variant of the trick that's done in this patch, i.e. substitute into
each dependent parameter type stripped of its top-level cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to detect
this?


I think let's go ahead with comparing TYPE_ARG_TYPES and DECL_ARGUMENTS;
the
problem comes when they disagree.  If we're handling pack expansions
wrong,
that's a separate issue.


Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility seems
to be exposing a latent bug with how we handle lambdas that appear in
function parameter types.  Take g++.dg/cpp2a/lambda-uneval3.C for
example:

  template  void spam(decltype([]{}) (*s)[sizeof(T)]) {}
  int main() { spam(nullptr); }

According to tsubst_function_decl in current trunk, the type of the
function paremeter 's' of spam according to its TYPE_ARG_TYPES is
  struct ._anon_4[1] *
and according to its DECL_ARGUMENTS the type of 's' is
  struct ._anon_5[1] *

The disagreement happens because we call tsubst_lambda_expr twice during
substitution and thereby generate two distinct lambda types, one when
substituting into the TYPE_ARG_TYPES and another when substituting into
the 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-06 Thread Patrick Palka via Gcc-patches
On Wed, 1 Apr 2020, Jason Merrill wrote:

> On 4/1/20 6:29 PM, Jason Merrill wrote:
> > On 3/31/20 3:50 PM, Patrick Palka wrote:
> > > On Tue, 31 Mar 2020, Jason Merrill wrote:
> > > 
> > > > On 3/30/20 6:46 PM, Patrick Palka wrote:
> > > > > On Mon, 30 Mar 2020, Jason Merrill wrote:
> > > > > > On 3/30/20 3:58 PM, Patrick Palka wrote:
> > > > > > > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > > > > > > 
> > > > > > > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > > > > > > This patch relaxes an assertion in tsubst_default_argument
> > > > > > > > > that
> > > > > > > > > exposes
> > > > > > > > > a
> > > > > > > > > latent
> > > > > > > > > bug in how we substitute an array type into a cv-qualified
> > > > > > > > > wildcard
> > > > > > > > > function
> > > > > > > > > parameter type.  Concretely, the latent bug is that given the
> > > > > > > > > function
> > > > > > > > > template
> > > > > > > > > 
> > > > > > > > >   template void foo(const T t);
> > > > > > > > > 
> > > > > > > > > one would expect the type of foo to be void(const
> > > > > > > > > int*), but
> > > > > > > > > we
> > > > > > > > > (seemingly prematurely) strip function parameter types of
> > > > > > > > > their
> > > > > > > > > top-level
> > > > > > > > > cv-qualifiers when building the function's TYPE_ARG_TYPES, and
> > > > > > > > > instead
> > > > > > > > > end
> > > > > > > > > up
> > > > > > > > > obtaining void(int*) as the type of foo after
> > > > > > > > > substitution
> > > > > > > > > and
> > > > > > > > > decaying.
> > > > > > > > > 
> > > > > > > > > We still however correctly substitute into and decay the
> > > > > > > > > formal
> > > > > > > > > parameter
> > > > > > > > > type,
> > > > > > > > > obtaining const int* as the type of t after substitution.  But
> > > > > > > > > this
> > > > > > > > > then
> > > > > > > > > leads
> > > > > > > > > to us tripping over the assert in tsubst_default_argument that
> > > > > > > > > verifies
> > > > > > > > > the
> > > > > > > > > formal parameter type and the function type are consistent.
> > > > > > > > > 
> > > > > > > > > Assuming it's too late at this stage to fix the substitution
> > > > > > > > > bug, we
> > > > > > > > > can
> > > > > > > > > still
> > > > > > > > > relax the assertion like so.  Tested on x86_64-pc-linux-gnu,
> > > > > > > > > does
> > > > > > > > > this
> > > > > > > > > look
> > > > > > > > > OK?
> > > > > > > > 
> > > > > > > > This is core issues 1001/1322, which have not been resolved. 
> > > > > > > > Clang
> > > > > > > > does
> > > > > > > > the
> > > > > > > > substitution the way you suggest; EDG rejects the testcase
> > > > > > > > because the
> > > > > > > > two
> > > > > > > > substitutions produce different results.  I think it would make
> > > > > > > > sense
> > > > > > > > to
> > > > > > > > follow the EDG behavior until this issue is actually resolved.
> > > > > > > 
> > > > > > > Here is what I have so far towards that end.  When substituting
> > > > > > > into the
> > > > > > > PARM_DECLs of a function decl, we now additionally check if the
> > > > > > > aforementioned Core issues are relevant and issue a (fatal)
> > > > > > > diagnostic
> > > > > > > if so.  This patch checks this in tsubst_decl 
> > > > > > > rather
> > > > > > > than in tsubst_function_decl for efficiency reasons, so that we
> > > > > > > don't
> > > > > > > have to perform another traversal over the DECL_ARGUMENTS /
> > > > > > > TYPE_ARG_TYPES just to implement this check.
> > > > > > 
> > > > > > Hmm, this seems like writing more complicated code for a very
> > > > > > marginal
> > > > > > optimization; how many function templates have so many parameters
> > > > > > that
> > > > > > walking
> > > > > > over them once to compare types will have any effect on compile
> > > > > > time?
> > > > > 
> > > > > Good point... though I just tried implementing this check in
> > > > > tsubst_function_decl, and it seems it might be just as complicated to
> > > > > implement it there instead, at least if we want to handle function
> > > > > parameter packs correctly.
> > > > > 
> > > > > If we were to implement this check in tsubst_function_decl, then since
> > > > > we have access to the instantiated function, it would presumably
> > > > > suffice
> > > > > to compare its substituted DECL_ARGUMENTS with its substituted
> > > > > TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
> > > > > catch the original testcase, i.e.
> > > > > 
> > > > >     template
> > > > >   void foo(const T);
> > > > >     int main() { foo(0); }
> > > > > 
> > > > > because the DECL_ARGUMENTS of foo would be {const int*} and its
> > > > > TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
> > > > > corresponding testcase that uses a function parameter pack, i.e.
> > > > > 
> > > > >     template
> > > > >   void foo(const Ts...);
> > > > >     int main() { foo(0); }
> > > > > 
> > > > > because it turns out we don't strip top-level 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-01 Thread Jason Merrill via Gcc-patches

On 4/1/20 6:29 PM, Jason Merrill wrote:

On 3/31/20 3:50 PM, Patrick Palka wrote:

On Tue, 31 Mar 2020, Jason Merrill wrote:


On 3/30/20 6:46 PM, Patrick Palka wrote:

On Mon, 30 Mar 2020, Jason Merrill wrote:

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument that
exposes
a
latent
bug in how we substitute an array type into a cv-qualified wildcard
function
parameter type.  Concretely, the latent bug is that given the
function
template

  template void foo(const T t);

one would expect the type of foo to be void(const int*), but
we
(seemingly prematurely) strip function parameter types of their
top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and
instead
end
up
obtaining void(int*) as the type of foo after substitution
and
decaying.

We still however correctly substitute into and decay the formal
parameter
type,
obtaining const int* as the type of t after substitution.  But this
then
leads
to us tripping over the assert in tsubst_default_argument that
verifies
the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution 
bug, we

can
still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does
this
look
OK?


This is core issues 1001/1322, which have not been resolved.  Clang
does
the
substitution the way you suggest; EDG rejects the testcase 
because the

two
substitutions produce different results.  I think it would make 
sense

to
follow the EDG behavior until this issue is actually resolved.


Here is what I have so far towards that end.  When substituting 
into the

PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal) 
diagnostic

if so.  This patch checks this in tsubst_decl  rather
than in tsubst_function_decl for efficiency reasons, so that we don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very marginal
optimization; how many function templates have so many parameters that
walking
over them once to compare types will have any effect on compile time?


Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then since
we have access to the instantiated function, it would presumably 
suffice

to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
catch the original testcase, i.e.

    template
  void foo(const T);
    int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
corresponding testcase that uses a function parameter pack, i.e.

    template
  void foo(const Ts...);
    int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time, as we
do with regular function parameters.  So in this second testcase both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
and yet we would (presumably) want to reject this instantiation too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to do a
variant of the trick that's done in this patch, i.e. substitute into
each dependent parameter type stripped of its top-level cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to detect
this?


I think let's go ahead with comparing TYPE_ARG_TYPES and 
DECL_ARGUMENTS; the
problem comes when they disagree.  If we're handling pack expansions 
wrong,

that's a separate issue.


Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility seems
to be exposing a latent bug with how we handle lambdas that appear in
function parameter types.  Take g++.dg/cpp2a/lambda-uneval3.C for
example:

 template  void spam(decltype([]{}) (*s)[sizeof(T)]) {}
 int main() { spam(nullptr); }

According to tsubst_function_decl in current trunk, the type of the
function paremeter 's' of spam according to its TYPE_ARG_TYPES is
 struct ._anon_4[1] *
and according to its DECL_ARGUMENTS the type of 's' is
 struct ._anon_5[1] *

The disagreement happens because we call tsubst_lambda_expr twice during
substitution and thereby generate two distinct lambda types, one when
substituting into the TYPE_ARG_TYPES and another when substituting into
the DECL_ARGUMENTS.  I'm not sure how to work around this
bug/false-positive..


Oof.

I 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-04-01 Thread Jason Merrill via Gcc-patches

On 3/31/20 3:50 PM, Patrick Palka wrote:

On Tue, 31 Mar 2020, Jason Merrill wrote:


On 3/30/20 6:46 PM, Patrick Palka wrote:

On Mon, 30 Mar 2020, Jason Merrill wrote:

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument that
exposes
a
latent
bug in how we substitute an array type into a cv-qualified wildcard
function
parameter type.  Concretely, the latent bug is that given the
function
template

  template void foo(const T t);

one would expect the type of foo to be void(const int*), but
we
(seemingly prematurely) strip function parameter types of their
top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and
instead
end
up
obtaining void(int*) as the type of foo after substitution
and
decaying.

We still however correctly substitute into and decay the formal
parameter
type,
obtaining const int* as the type of t after substitution.  But this
then
leads
to us tripping over the assert in tsubst_default_argument that
verifies
the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution bug, we
can
still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does
this
look
OK?


This is core issues 1001/1322, which have not been resolved.  Clang
does
the
substitution the way you suggest; EDG rejects the testcase because the
two
substitutions produce different results.  I think it would make sense
to
follow the EDG behavior until this issue is actually resolved.


Here is what I have so far towards that end.  When substituting into the
PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal) diagnostic
if so.  This patch checks this in tsubst_decl  rather
than in tsubst_function_decl for efficiency reasons, so that we don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very marginal
optimization; how many function templates have so many parameters that
walking
over them once to compare types will have any effect on compile time?


Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then since
we have access to the instantiated function, it would presumably suffice
to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
catch the original testcase, i.e.

template
  void foo(const T);
int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
corresponding testcase that uses a function parameter pack, i.e.

template
  void foo(const Ts...);
int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time, as we
do with regular function parameters.  So in this second testcase both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
and yet we would (presumably) want to reject this instantiation too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to do a
variant of the trick that's done in this patch, i.e. substitute into
each dependent parameter type stripped of its top-level cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to detect
this?


I think let's go ahead with comparing TYPE_ARG_TYPES and DECL_ARGUMENTS; the
problem comes when they disagree.  If we're handling pack expansions wrong,
that's a separate issue.


Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility seems
to be exposing a latent bug with how we handle lambdas that appear in
function parameter types.  Take g++.dg/cpp2a/lambda-uneval3.C for
example:

 template  void spam(decltype([]{}) (*s)[sizeof(T)]) {}
 int main() { spam(nullptr); }

According to tsubst_function_decl in current trunk, the type of the
function paremeter 's' of spam according to its TYPE_ARG_TYPES is
 struct ._anon_4[1] *
and according to its DECL_ARGUMENTS the type of 's' is
 struct ._anon_5[1] *

The disagreement happens because we call tsubst_lambda_expr twice during
substitution and thereby generate two distinct lambda types, one when
substituting into the TYPE_ARG_TYPES and another when substituting into
the DECL_ARGUMENTS.  I'm not sure how to work around this
bug/false-positive..


Oof.

I think probably the right answer is to rebuild 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-31 Thread Patrick Palka via Gcc-patches
On Tue, 31 Mar 2020, Jason Merrill wrote:

> On 3/30/20 6:46 PM, Patrick Palka wrote:
> > On Mon, 30 Mar 2020, Jason Merrill wrote:
> > > On 3/30/20 3:58 PM, Patrick Palka wrote:
> > > > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > > > 
> > > > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > > > This patch relaxes an assertion in tsubst_default_argument that
> > > > > > exposes
> > > > > > a
> > > > > > latent
> > > > > > bug in how we substitute an array type into a cv-qualified wildcard
> > > > > > function
> > > > > > parameter type.  Concretely, the latent bug is that given the
> > > > > > function
> > > > > > template
> > > > > > 
> > > > > >  template void foo(const T t);
> > > > > > 
> > > > > > one would expect the type of foo to be void(const int*), but
> > > > > > we
> > > > > > (seemingly prematurely) strip function parameter types of their
> > > > > > top-level
> > > > > > cv-qualifiers when building the function's TYPE_ARG_TYPES, and
> > > > > > instead
> > > > > > end
> > > > > > up
> > > > > > obtaining void(int*) as the type of foo after substitution
> > > > > > and
> > > > > > decaying.
> > > > > > 
> > > > > > We still however correctly substitute into and decay the formal
> > > > > > parameter
> > > > > > type,
> > > > > > obtaining const int* as the type of t after substitution.  But this
> > > > > > then
> > > > > > leads
> > > > > > to us tripping over the assert in tsubst_default_argument that
> > > > > > verifies
> > > > > > the
> > > > > > formal parameter type and the function type are consistent.
> > > > > > 
> > > > > > Assuming it's too late at this stage to fix the substitution bug, we
> > > > > > can
> > > > > > still
> > > > > > relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does
> > > > > > this
> > > > > > look
> > > > > > OK?
> > > > > 
> > > > > This is core issues 1001/1322, which have not been resolved.  Clang
> > > > > does
> > > > > the
> > > > > substitution the way you suggest; EDG rejects the testcase because the
> > > > > two
> > > > > substitutions produce different results.  I think it would make sense
> > > > > to
> > > > > follow the EDG behavior until this issue is actually resolved.
> > > > 
> > > > Here is what I have so far towards that end.  When substituting into the
> > > > PARM_DECLs of a function decl, we now additionally check if the
> > > > aforementioned Core issues are relevant and issue a (fatal) diagnostic
> > > > if so.  This patch checks this in tsubst_decl  rather
> > > > than in tsubst_function_decl for efficiency reasons, so that we don't
> > > > have to perform another traversal over the DECL_ARGUMENTS /
> > > > TYPE_ARG_TYPES just to implement this check.
> > > 
> > > Hmm, this seems like writing more complicated code for a very marginal
> > > optimization; how many function templates have so many parameters that
> > > walking
> > > over them once to compare types will have any effect on compile time?
> > 
> > Good point... though I just tried implementing this check in
> > tsubst_function_decl, and it seems it might be just as complicated to
> > implement it there instead, at least if we want to handle function
> > parameter packs correctly.
> > 
> > If we were to implement this check in tsubst_function_decl, then since
> > we have access to the instantiated function, it would presumably suffice
> > to compare its substituted DECL_ARGUMENTS with its substituted
> > TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
> > catch the original testcase, i.e.
> > 
> >template
> >  void foo(const T);
> >int main() { foo(0); }
> > 
> > because the DECL_ARGUMENTS of foo would be {const int*} and its
> > TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
> > corresponding testcase that uses a function parameter pack, i.e.
> > 
> >template
> >  void foo(const Ts...);
> >int main() { foo(0); }
> > 
> > because it turns out we don't strip top-level cv-qualifiers from
> > function parameter packs from TYPE_ARG_TYPES at declaration time, as we
> > do with regular function parameters.  So in this second testcase both
> > DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
> > and yet we would (presumably) want to reject this instantiation too.
> > 
> > So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
> > tsubst_function_decl would not suffice, and we would still need to do a
> > variant of the trick that's done in this patch, i.e. substitute into
> > each dependent parameter type stripped of its top-level cv-qualifiers,
> > to see if these cv-qualifiers make a material difference in the
> > resulting function type.  Or maybe there's yet another way to detect
> > this?
> 
> I think let's go ahead with comparing TYPE_ARG_TYPES and DECL_ARGUMENTS; the
> problem comes when they disagree.  If we're handling pack expansions wrong,
> that's a separate issue.

Hm, comparing TYPE_ARG_TYPES and DECL_ARGUMENTS for compatibility seems
to be exposing a latent 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-31 Thread Jason Merrill via Gcc-patches

On 3/30/20 6:46 PM, Patrick Palka wrote:

On Mon, 30 Mar 2020, Jason Merrill wrote:

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument that exposes
a
latent
bug in how we substitute an array type into a cv-qualified wildcard
function
parameter type.  Concretely, the latent bug is that given the function
template

 template void foo(const T t);

one would expect the type of foo to be void(const int*), but we
(seemingly prematurely) strip function parameter types of their
top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead
end
up
obtaining void(int*) as the type of foo after substitution and
decaying.

We still however correctly substitute into and decay the formal
parameter
type,
obtaining const int* as the type of t after substitution.  But this then
leads
to us tripping over the assert in tsubst_default_argument that verifies
the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution bug, we can
still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this
look
OK?


This is core issues 1001/1322, which have not been resolved.  Clang does
the
substitution the way you suggest; EDG rejects the testcase because the two
substitutions produce different results.  I think it would make sense to
follow the EDG behavior until this issue is actually resolved.


Here is what I have so far towards that end.  When substituting into the
PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal) diagnostic
if so.  This patch checks this in tsubst_decl  rather
than in tsubst_function_decl for efficiency reasons, so that we don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very marginal
optimization; how many function templates have so many parameters that walking
over them once to compare types will have any effect on compile time?


Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then since
we have access to the instantiated function, it would presumably suffice
to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
catch the original testcase, i.e.

   template
 void foo(const T);
   int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
corresponding testcase that uses a function parameter pack, i.e.

   template
 void foo(const Ts...);
   int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time, as we
do with regular function parameters.  So in this second testcase both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
and yet we would (presumably) want to reject this instantiation too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to do a
variant of the trick that's done in this patch, i.e. substitute into
each dependent parameter type stripped of its top-level cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to detect
this?


I think let's go ahead with comparing TYPE_ARG_TYPES and DECL_ARGUMENTS; 
the problem comes when they disagree.  If we're handling pack expansions 
wrong, that's a separate issue.


Jason



Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-30 Thread Patrick Palka via Gcc-patches
On Mon, 30 Mar 2020, Jason Merrill wrote:
> On 3/30/20 3:58 PM, Patrick Palka wrote:
> > On Thu, 26 Mar 2020, Jason Merrill wrote:
> > 
> > > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > > This patch relaxes an assertion in tsubst_default_argument that exposes
> > > > a
> > > > latent
> > > > bug in how we substitute an array type into a cv-qualified wildcard
> > > > function
> > > > parameter type.  Concretely, the latent bug is that given the function
> > > > template
> > > > 
> > > > template void foo(const T t);
> > > > 
> > > > one would expect the type of foo to be void(const int*), but we
> > > > (seemingly prematurely) strip function parameter types of their
> > > > top-level
> > > > cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead
> > > > end
> > > > up
> > > > obtaining void(int*) as the type of foo after substitution and
> > > > decaying.
> > > > 
> > > > We still however correctly substitute into and decay the formal
> > > > parameter
> > > > type,
> > > > obtaining const int* as the type of t after substitution.  But this then
> > > > leads
> > > > to us tripping over the assert in tsubst_default_argument that verifies
> > > > the
> > > > formal parameter type and the function type are consistent.
> > > > 
> > > > Assuming it's too late at this stage to fix the substitution bug, we can
> > > > still
> > > > relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this
> > > > look
> > > > OK?
> > > 
> > > This is core issues 1001/1322, which have not been resolved.  Clang does
> > > the
> > > substitution the way you suggest; EDG rejects the testcase because the two
> > > substitutions produce different results.  I think it would make sense to
> > > follow the EDG behavior until this issue is actually resolved.
> > 
> > Here is what I have so far towards that end.  When substituting into the
> > PARM_DECLs of a function decl, we now additionally check if the
> > aforementioned Core issues are relevant and issue a (fatal) diagnostic
> > if so.  This patch checks this in tsubst_decl  rather
> > than in tsubst_function_decl for efficiency reasons, so that we don't
> > have to perform another traversal over the DECL_ARGUMENTS /
> > TYPE_ARG_TYPES just to implement this check.
> 
> Hmm, this seems like writing more complicated code for a very marginal
> optimization; how many function templates have so many parameters that walking
> over them once to compare types will have any effect on compile time?

Good point... though I just tried implementing this check in
tsubst_function_decl, and it seems it might be just as complicated to
implement it there instead, at least if we want to handle function
parameter packs correctly.

If we were to implement this check in tsubst_function_decl, then since
we have access to the instantiated function, it would presumably suffice
to compare its substituted DECL_ARGUMENTS with its substituted
TYPE_ARG_TYPES to see if they're consistent.  Doing so would certainly
catch the original testcase, i.e.

  template
void foo(const T);
  int main() { foo(0); }

because the DECL_ARGUMENTS of foo would be {const int*} and its
TYPE_ARG_TYPES would be {int*}.  But apparently it doesn't catch the
corresponding testcase that uses a function parameter pack, i.e.

  template
void foo(const Ts...);
  int main() { foo(0); }

because it turns out we don't strip top-level cv-qualifiers from
function parameter packs from TYPE_ARG_TYPES at declaration time, as we
do with regular function parameters.  So in this second testcase both
DECL_ARGUMENTS and TYPE_ARG_TYPES of foo would be {const int*},
and yet we would (presumably) want to reject this instantiation too.

So it seems comparing TYPE_ARG_TYPES and DECL_ARGUMENTS from
tsubst_function_decl would not suffice, and we would still need to do a
variant of the trick that's done in this patch, i.e. substitute into
each dependent parameter type stripped of its top-level cv-qualifiers,
to see if these cv-qualifiers make a material difference in the
resulting function type.  Or maybe there's yet another way to detect
this?

> 
> > Is something like this what you have in mind?
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: Reject some instantiations that depend on resolution
> > of
> >   Core issues 1001/1322
> > 
> > gcc/cp/ChangeLog:
> > 
> > Core issues 1001 and 1322
> > PR c++/92010
> > * pt.c (tsubst_decl) : Detect and reject the case
> > where
> > the function type depends on whether we strip top-level qualifiers
> > from
> > the type of T before or after substitution.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > Core issues 1001 and 1322
> > PR c++/92010
> > * g++.dg/template/array33.C: New test.
> > * g++.dg/template/array34.C: New test.
> > ---
> >   gcc/cp/pt.c | 70 -
> >   gcc/testsuite/g++.dg/template/array33.C | 39 ++
> >   gcc/testsuite/g++.dg/template/array34.C | 63 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-30 Thread Jason Merrill via Gcc-patches

On 3/30/20 3:58 PM, Patrick Palka wrote:

On Thu, 26 Mar 2020, Jason Merrill wrote:


On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument that exposes a
latent
bug in how we substitute an array type into a cv-qualified wildcard function
parameter type.  Concretely, the latent bug is that given the function
template

template void foo(const T t);

one would expect the type of foo to be void(const int*), but we
(seemingly prematurely) strip function parameter types of their top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end
up
obtaining void(int*) as the type of foo after substitution and
decaying.

We still however correctly substitute into and decay the formal parameter
type,
obtaining const int* as the type of t after substitution.  But this then
leads
to us tripping over the assert in tsubst_default_argument that verifies the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution bug, we can
still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this look
OK?


This is core issues 1001/1322, which have not been resolved.  Clang does the
substitution the way you suggest; EDG rejects the testcase because the two
substitutions produce different results.  I think it would make sense to
follow the EDG behavior until this issue is actually resolved.


Here is what I have so far towards that end.  When substituting into the
PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal) diagnostic
if so.  This patch checks this in tsubst_decl  rather
than in tsubst_function_decl for efficiency reasons, so that we don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.


Hmm, this seems like writing more complicated code for a very marginal 
optimization; how many function templates have so many parameters that 
walking over them once to compare types will have any effect on compile 
time?



Is something like this what you have in mind?

-- >8 --

Subject: [PATCH] c++: Reject some instantiations that depend on resolution of
  Core issues 1001/1322

gcc/cp/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* pt.c (tsubst_decl) : Detect and reject the case where
the function type depends on whether we strip top-level qualifiers from
the type of T before or after substitution.

gcc/testsuite/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* g++.dg/template/array33.C: New test.
* g++.dg/template/array34.C: New test.
---
  gcc/cp/pt.c | 70 -
  gcc/testsuite/g++.dg/template/array33.C | 39 ++
  gcc/testsuite/g++.dg/template/array34.C | 63 ++
  3 files changed, 171 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/template/array33.C
  create mode 100644 gcc/testsuite/g++.dg/template/array34.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8564eb11df4..fd99053df36 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14072,9 +14072,77 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
/* We're dealing with a normal parameter.  */
type = tsubst (TREE_TYPE (t), args, complain, in_decl);
  
+	const int type_quals = cp_type_quals (type);

+
+   /* Determine whether the function type after substitution into the
+  type of the function parameter T depends on the resolution of
+  Core issues 1001/1322, which have not been resolved.  In
+  particular, the following detects the case where the resulting
+  function type depends on whether we strip top-level qualifiers
+  from the type of T before or after substitution.
+
+  This can happen only when the dependent type of T is a
+  cv-qualified wildcard type, and substitution yields a
+  (cv-qualified) array type before array-to-pointer conversion.  */
+   tree unqual_expanded_types = NULL_TREE;
+   if (TREE_CODE (type) == ARRAY_TYPE
+   && (type_quals & (TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE))
+   && DECL_FUNCTION_SCOPE_P (t)
+   && !DECL_TEMPLATE_PARM_P (t))
+ {
+   tree type_pattern = (PACK_EXPANSION_P (TREE_TYPE (t))
+? PACK_EXPANSION_PATTERN (TREE_TYPE (t))
+: TREE_TYPE (t));
+   if (WILDCARD_TYPE_P (type_pattern)
+   && cv_qualified_p (type_pattern))
+ {
+   /* Substitute into the corresponding wildcard type that is
+  stripped of its own top-level cv-qualifiers.  */
+   tree unqual_type;
+   if (PACK_EXPANSION_P (TREE_TYPE 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-30 Thread Patrick Palka via Gcc-patches
On Mon, 30 Mar 2020, Patrick Palka wrote:

> On Thu, 26 Mar 2020, Jason Merrill wrote:
> 
> > On 3/22/20 9:21 PM, Patrick Palka wrote:
> > > This patch relaxes an assertion in tsubst_default_argument that exposes a
> > > latent
> > > bug in how we substitute an array type into a cv-qualified wildcard 
> > > function
> > > parameter type.  Concretely, the latent bug is that given the function
> > > template
> > > 
> > >template void foo(const T t);
> > > 
> > > one would expect the type of foo to be void(const int*), but we
> > > (seemingly prematurely) strip function parameter types of their top-level
> > > cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end
> > > up
> > > obtaining void(int*) as the type of foo after substitution and
> > > decaying.
> > > 
> > > We still however correctly substitute into and decay the formal parameter
> > > type,
> > > obtaining const int* as the type of t after substitution.  But this then
> > > leads
> > > to us tripping over the assert in tsubst_default_argument that verifies 
> > > the
> > > formal parameter type and the function type are consistent.
> > > 
> > > Assuming it's too late at this stage to fix the substitution bug, we can
> > > still
> > > relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this 
> > > look
> > > OK?
> > 
> > This is core issues 1001/1322, which have not been resolved.  Clang does the
> > substitution the way you suggest; EDG rejects the testcase because the two
> > substitutions produce different results.  I think it would make sense to
> > follow the EDG behavior until this issue is actually resolved.
> 
> Here is what I have so far towards that end.  When substituting into the
> PARM_DECLs of a function decl, we now additionally check if the
> aforementioned Core issues are relevant and issue a (fatal) diagnostic
> if so.  This patch checks this in tsubst_decl  rather
> than in tsubst_function_decl for efficiency reasons, so that we don't
> have to perform another traversal over the DECL_ARGUMENTS /
> TYPE_ARG_TYPES just to implement this check.
> 
> Is something like this what you have in mind?

Oops, noticed a few bugs in the patch as soon as I hit send.  Please
consider this patch instead, which compared to the previous patch
declares unqual_expanded_types in the correct scope and refrains from
doing a potentially incorrect CSE of "cp_type_quals (type)".

-- >8 --

gcc/cp/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* pt.c (tsubst_decl) : Detect and reject the case where
the function type depends on whether we strip top-level qualifiers from
the type of T before or after substitution.

gcc/testsuite/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* g++.dg/template/array33.C: New test.
* g++.dg/template/array34.C: New test.
---
 gcc/cp/pt.c | 68 +
 gcc/testsuite/g++.dg/template/array33.C | 39 ++
 gcc/testsuite/g++.dg/template/array34.C | 63 +++
 3 files changed, 170 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/array33.C
 create mode 100644 gcc/testsuite/g++.dg/template/array34.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8564eb11df4..a1efaef2c1e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14046,6 +14046,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
   }
   }
 
+   tree unqual_expanded_types = NULL_TREE;
+
 /* Loop through all of the parameters we'll build. When T is
a function parameter pack, LEN is the number of expanded
types in EXPANDED_TYPES; otherwise, LEN is 1.  */
@@ -14072,6 +14074,72 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
   /* We're dealing with a normal parameter.  */
   type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 
+   /* Determine whether the function type after substitution into the
+  type of the function parameter T depends on the resolution of
+  Core issues 1001/1322, which have not been resolved.  In
+  particular, the following detects when the resulting function
+  type depends on whether we strip top-level qualifiers from the
+  type of T before or after substitution.
+
+  This can happen only when the dependent type of T is a
+  cv-qualified wildcard type, and substitution yields a
+  (cv-qualified) array type before array-to-pointer conversion.  */
+   if (TREE_CODE (type) == ARRAY_TYPE
+   && cv_qualified_p (type)
+   && DECL_FUNCTION_SCOPE_P (t)
+   && !DECL_TEMPLATE_PARM_P (t))
+ {
+   tree type_pattern = (PACK_EXPANSION_P (TREE_TYPE (t))
+? PACK_EXPANSION_PATTERN (TREE_TYPE (t))
+: TREE_TYPE (t));
+  

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-30 Thread Patrick Palka via Gcc-patches
On Thu, 26 Mar 2020, Jason Merrill wrote:

> On 3/22/20 9:21 PM, Patrick Palka wrote:
> > This patch relaxes an assertion in tsubst_default_argument that exposes a
> > latent
> > bug in how we substitute an array type into a cv-qualified wildcard function
> > parameter type.  Concretely, the latent bug is that given the function
> > template
> > 
> >template void foo(const T t);
> > 
> > one would expect the type of foo to be void(const int*), but we
> > (seemingly prematurely) strip function parameter types of their top-level
> > cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end
> > up
> > obtaining void(int*) as the type of foo after substitution and
> > decaying.
> > 
> > We still however correctly substitute into and decay the formal parameter
> > type,
> > obtaining const int* as the type of t after substitution.  But this then
> > leads
> > to us tripping over the assert in tsubst_default_argument that verifies the
> > formal parameter type and the function type are consistent.
> > 
> > Assuming it's too late at this stage to fix the substitution bug, we can
> > still
> > relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this look
> > OK?
> 
> This is core issues 1001/1322, which have not been resolved.  Clang does the
> substitution the way you suggest; EDG rejects the testcase because the two
> substitutions produce different results.  I think it would make sense to
> follow the EDG behavior until this issue is actually resolved.

Here is what I have so far towards that end.  When substituting into the
PARM_DECLs of a function decl, we now additionally check if the
aforementioned Core issues are relevant and issue a (fatal) diagnostic
if so.  This patch checks this in tsubst_decl  rather
than in tsubst_function_decl for efficiency reasons, so that we don't
have to perform another traversal over the DECL_ARGUMENTS /
TYPE_ARG_TYPES just to implement this check.

Is something like this what you have in mind?

-- >8 --

Subject: [PATCH] c++: Reject some instantiations that depend on resolution of
 Core issues 1001/1322

gcc/cp/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* pt.c (tsubst_decl) : Detect and reject the case where
the function type depends on whether we strip top-level qualifiers from
the type of T before or after substitution.

gcc/testsuite/ChangeLog:

Core issues 1001 and 1322
PR c++/92010
* g++.dg/template/array33.C: New test.
* g++.dg/template/array34.C: New test.
---
 gcc/cp/pt.c | 70 -
 gcc/testsuite/g++.dg/template/array33.C | 39 ++
 gcc/testsuite/g++.dg/template/array34.C | 63 ++
 3 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/array33.C
 create mode 100644 gcc/testsuite/g++.dg/template/array34.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8564eb11df4..fd99053df36 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14072,9 +14072,77 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
   /* We're dealing with a normal parameter.  */
   type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 
+   const int type_quals = cp_type_quals (type);
+
+   /* Determine whether the function type after substitution into the
+  type of the function parameter T depends on the resolution of
+  Core issues 1001/1322, which have not been resolved.  In
+  particular, the following detects the case where the resulting
+  function type depends on whether we strip top-level qualifiers
+  from the type of T before or after substitution.
+
+  This can happen only when the dependent type of T is a
+  cv-qualified wildcard type, and substitution yields a
+  (cv-qualified) array type before array-to-pointer conversion.  */
+   tree unqual_expanded_types = NULL_TREE;
+   if (TREE_CODE (type) == ARRAY_TYPE
+   && (type_quals & (TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE))
+   && DECL_FUNCTION_SCOPE_P (t)
+   && !DECL_TEMPLATE_PARM_P (t))
+ {
+   tree type_pattern = (PACK_EXPANSION_P (TREE_TYPE (t))
+? PACK_EXPANSION_PATTERN (TREE_TYPE (t))
+: TREE_TYPE (t));
+   if (WILDCARD_TYPE_P (type_pattern)
+   && cv_qualified_p (type_pattern))
+ {
+   /* Substitute into the corresponding wildcard type that is
+  stripped of its own top-level cv-qualifiers.  */
+   tree unqual_type;
+   if (PACK_EXPANSION_P (TREE_TYPE (t)))
+ {
+   if (unqual_expanded_types == NULL_TREE)
+ {
+   tree 

Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-26 Thread Jason Merrill via Gcc-patches

On 3/22/20 9:21 PM, Patrick Palka wrote:

This patch relaxes an assertion in tsubst_default_argument that exposes a latent
bug in how we substitute an array type into a cv-qualified wildcard function
parameter type.  Concretely, the latent bug is that given the function template

   template void foo(const T t);

one would expect the type of foo to be void(const int*), but we
(seemingly prematurely) strip function parameter types of their top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end up
obtaining void(int*) as the type of foo after substitution and decaying.

We still however correctly substitute into and decay the formal parameter type,
obtaining const int* as the type of t after substitution.  But this then leads
to us tripping over the assert in tsubst_default_argument that verifies the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution bug, we can still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this look OK?


This is core issues 1001/1322, which have not been resolved.  Clang does 
the substitution the way you suggest; EDG rejects the testcase because 
the two substitutions produce different results.  I think it would make 
sense to follow the EDG behavior until this issue is actually resolved.



gcc/cp/ChangeLog:

PR c++/92010
* pt.c (tsubst_default_argument): Relax assertion to permit
disagreements between the function type and the parameter type
about the cv-qualification of the pointed-to type.

gcc/testsuite/ChangeLog:

PR c++/92010
* g++.dg/template/defarg22.C: New test.
---
  gcc/cp/pt.c  | 17 -
  gcc/testsuite/g++.dg/template/defarg22.C | 11 +++
  2 files changed, 27 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/template/defarg22.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9e1eb9416c9..923166276b8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13337,7 +13337,22 @@ tsubst_default_argument (tree fn, int parmnum, tree 
type, tree arg,
if (parmtype == error_mark_node)
  return error_mark_node;
  
-  gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, parmtype));

+  if (same_type_ignoring_top_level_qualifiers_p (type, parmtype))
+;
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (parmtype))
+{
+  /* The function type and the parameter type can disagree about the
+cv-qualification of the pointed-to type; see PR92010.  */
+  gcc_assert (same_type_p (TREE_TYPE (type),
+  strip_top_quals (TREE_TYPE (parmtype;
+  /* Verify that this happens only when the dependent parameter type is a
+cv-qualified wildcard type.  */
+  tree pattern_parm = get_pattern_parm (parm, DECL_TI_TEMPLATE (fn));
+  gcc_assert (WILDCARD_TYPE_P (TREE_TYPE (pattern_parm))
+ && cv_qualified_p (TREE_TYPE (pattern_parm)));
+}
+  else
+gcc_unreachable ();
  
tree *slot;

if (defarg_inst && (slot = defarg_inst->get (parm)))
diff --git a/gcc/testsuite/g++.dg/template/defarg22.C 
b/gcc/testsuite/g++.dg/template/defarg22.C
new file mode 100644
index 000..cf6261916d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/defarg22.C
@@ -0,0 +1,11 @@
+// PR c++/92010
+// { dg-do compile }
+
+template 
+void foo(const T t = 0)
+{ }
+
+int main()
+{
+  foo();
+}





Re: [PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-22 Thread Patrick Palka via Gcc-patches
On Sun, 22 Mar 2020, Patrick Palka wrote:

> This patch relaxes an assertion in tsubst_default_argument that exposes a 
> latent
> bug in how we substitute an array type into a cv-qualified wildcard function
> parameter type.  Concretely, the latent bug is that given the function 
> template
> 
>   template void foo(const T t);
> 
> one would expect the type of foo to be void(const int*), but we
> (seemingly prematurely) strip function parameter types of their top-level
> cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end up
> obtaining void(int*) as the type of foo after substitution and 
> decaying.
> 
> We still however correctly substitute into and decay the formal parameter 
> type,
> obtaining const int* as the type of t after substitution.  But this then leads
> to us tripping over the assert in tsubst_default_argument that verifies the
> formal parameter type and the function type are consistent.
> 
> Assuming it's too late at this stage to fix the substitution bug, we can still
> relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this look 
> OK?
> 
> gcc/cp/ChangeLog:
> 
>   PR c++/92010
>   * pt.c (tsubst_default_argument): Relax assertion to permit
>   disagreements between the function type and the parameter type
>   about the cv-qualification of the pointed-to type.
> 
> gcc/testsuite/ChangeLog:
> 
>   PR c++/92010
>   * g++.dg/template/defarg22.C: New test.
> ---

Here's a slightly simpler version of the patch that moves the
POINTER_TYPE_P checks into the gcc_assert:

-- >8 --
---
 gcc/cp/pt.c  | 16 +++-
 gcc/testsuite/g++.dg/template/defarg22.C | 11 +++
 2 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/defarg22.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 03a8dfbd37c..849628840d6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13337,7 +13337,21 @@ tsubst_default_argument (tree fn, int parmnum, tree 
type, tree arg,
   if (parmtype == error_mark_node)
 return error_mark_node;
 
-  gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, parmtype));
+  if (same_type_ignoring_top_level_qualifiers_p (type, parmtype))
+;
+  else
+{
+  /* The function type and the parameter type can disagree about the
+cv-qualification of the pointed-to type; see PR92010.  */
+  gcc_assert (POINTER_TYPE_P (type) && POINTER_TYPE_P (parmtype)
+ && same_type_p (TREE_TYPE (type),
+ strip_top_quals (TREE_TYPE (parmtype;
+  /* Verify that this happens only when the dependent parameter type is a
+cv-qualified wildcard type.  */
+  tree pattern_parm = get_pattern_parm (parm, DECL_TI_TEMPLATE (fn));
+  gcc_assert (WILDCARD_TYPE_P (TREE_TYPE (pattern_parm))
+ && cv_qualified_p (TREE_TYPE (pattern_parm)));
+}
 
   tree *slot;
   if (defarg_inst && (slot = defarg_inst->get (parm)))
diff --git a/gcc/testsuite/g++.dg/template/defarg22.C 
b/gcc/testsuite/g++.dg/template/defarg22.C
new file mode 100644
index 000..cf6261916d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/defarg22.C
@@ -0,0 +1,11 @@
+// PR c++/92010
+// { dg-do compile }
+
+template 
+void foo(const T t = 0)
+{ }
+
+int main()
+{
+  foo();
+}
-- 
2.26.0.rc1.11.g30e9940356



[PATCH] c++: Fix ICE in tsubst_default_argument [PR92010]

2020-03-22 Thread Patrick Palka via Gcc-patches
This patch relaxes an assertion in tsubst_default_argument that exposes a latent
bug in how we substitute an array type into a cv-qualified wildcard function
parameter type.  Concretely, the latent bug is that given the function template

  template void foo(const T t);

one would expect the type of foo to be void(const int*), but we
(seemingly prematurely) strip function parameter types of their top-level
cv-qualifiers when building the function's TYPE_ARG_TYPES, and instead end up
obtaining void(int*) as the type of foo after substitution and decaying.

We still however correctly substitute into and decay the formal parameter type,
obtaining const int* as the type of t after substitution.  But this then leads
to us tripping over the assert in tsubst_default_argument that verifies the
formal parameter type and the function type are consistent.

Assuming it's too late at this stage to fix the substitution bug, we can still
relax the assertion like so.  Tested on x86_64-pc-linux-gnu, does this look OK?

gcc/cp/ChangeLog:

PR c++/92010
* pt.c (tsubst_default_argument): Relax assertion to permit
disagreements between the function type and the parameter type
about the cv-qualification of the pointed-to type.

gcc/testsuite/ChangeLog:

PR c++/92010
* g++.dg/template/defarg22.C: New test.
---
 gcc/cp/pt.c  | 17 -
 gcc/testsuite/g++.dg/template/defarg22.C | 11 +++
 2 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/defarg22.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9e1eb9416c9..923166276b8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13337,7 +13337,22 @@ tsubst_default_argument (tree fn, int parmnum, tree 
type, tree arg,
   if (parmtype == error_mark_node)
 return error_mark_node;
 
-  gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, parmtype));
+  if (same_type_ignoring_top_level_qualifiers_p (type, parmtype))
+;
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (parmtype))
+{
+  /* The function type and the parameter type can disagree about the
+cv-qualification of the pointed-to type; see PR92010.  */
+  gcc_assert (same_type_p (TREE_TYPE (type),
+  strip_top_quals (TREE_TYPE (parmtype;
+  /* Verify that this happens only when the dependent parameter type is a
+cv-qualified wildcard type.  */
+  tree pattern_parm = get_pattern_parm (parm, DECL_TI_TEMPLATE (fn));
+  gcc_assert (WILDCARD_TYPE_P (TREE_TYPE (pattern_parm))
+ && cv_qualified_p (TREE_TYPE (pattern_parm)));
+}
+  else
+gcc_unreachable ();
 
   tree *slot;
   if (defarg_inst && (slot = defarg_inst->get (parm)))
diff --git a/gcc/testsuite/g++.dg/template/defarg22.C 
b/gcc/testsuite/g++.dg/template/defarg22.C
new file mode 100644
index 000..cf6261916d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/defarg22.C
@@ -0,0 +1,11 @@
+// PR c++/92010
+// { dg-do compile }
+
+template 
+void foo(const T t = 0)
+{ }
+
+int main()
+{
+  foo();
+}
-- 
2.26.0.rc1.11.g30e9940356