[Bug c++/81043] [concepts] partially specializing on differing constraints gives cryptic error

2020-08-17 Thread shazamancan at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81043

Mike Detwiler  changed:

   What|Removed |Added

 CC||shazamancan at gmail dot com

--- Comment #2 from Mike Detwiler  ---
I would like to share a temporary workaround that I have developed for this.
Consider the usual pattern for writing a partial specialization:

original decl:

template
class my_class;

specialization:

template
class my_class;

If ORIGINAL_PARAMS, SPECIAL_PARAMS, and MODIFIED_PARAMS are all identical, then
it is an error, as it should be. Example of a true error:

template
class my_class;

template // <-- identical to ORIGINAL_PARAMS
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is also identical

All three *PARAMS are identical, so it is an error. Example of a true
non-error:

template
class my_class;

template // <-- identical to ORIGINAL_PARAMS
class my_class; // <-- T is modified, so MODIFIED_PARAMS is NOT identical

Not all three *PARAMS are identical, so it is not an error. Another example of
a true non-error:

template  concept C = (sizeof(T) <= 4);

template
class my_class;

template // <-- NOT identical to ORIGINAL_PARAMS (typename vs C)
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is also identical

[Bug c++/81043] [concepts] partially specializing on differing constraints gives cryptic error

2020-08-17 Thread shazamancan at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81043

--- Comment #3 from Mike Detwiler  ---
I would like to share a temporary workaround that I have developed for this.
Consider the usual pattern for writing a partial specialization:

original decl:

template
class my_class;

specialization:

template
class my_class;

If ORIGINAL_PARAMS, SPECIAL_PARAMS, and MODIFIED_PARAMS are all identical, then
it is an error, as it should be. Example of a true error:

template
class my_class;

template // <-- identical to ORIGINAL_PARAMS
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is also identical

All three *PARAMS are identical, so it is an error. Example of a true
non-error:

template
class my_class;

template // <-- identical to ORIGINAL_PARAMS
class my_class; // <-- T is modified, so MODIFIED_PARAMS is NOT identical

Not all three *PARAMS are identical, so it is not an error. Another example of
a true non-error:

template concept C = (sizeof(T) <= 4);

template
class my_class;

template // <-- NOT identical to ORIGINAL_PARAMS (typename vs C)
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is identical

Since not all three *PARAMS are identical it is not an error. Now for the tird
and final example of a true non-error (that GCC reports as a false error due to
this bug):

template concept C0 = (sizeof(T) <= 4);
template concept C1 = (sizeof(T) > 4);

template
class my_class;

template // <-- NOT identical to ORIGINAL_PARAMS (typename vs C0)
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is identical

template // <-- NOT identical to ORIGINAL_PARAMS (typename vs C1)
class my_class; // <-- T is unmodified, so MODIFIED_PARAMS is identical

**BUT notice: MODIFIED_PARAMS for the first and second specialization are
identical

Neither partial specialization is an error because not all three *PARAMS are
identical in each specialization. GCC gets confused and reports this as an
error though. GCC only gets confused and falsely reports an error when two or
more specializations have identical MODIFIED_PARAMS like in the third example.

So my workaround is as follows:

#include 

template concept C0 = (sizeof(T) <= 4);
template concept C1 = (sizeof(T) > 4);

template

using spec_id = void;

template
class my_class;

template
class my_class>;

template
class my_class>;

If you have two or more specializations where MODIFIED_PARAMS would be
unmodified like in the third example, you have to use spec_id with unique N for each specialization. spec_id is NOT necessary
if for the following additional specializations (so just pass void directly):

template
class my_class;

template
class my_class;

This is because MODIFIED_PARAMS for these two is not identical to any other
MODIFIED_PARAMS in some other specialization.