[Bug c++/104230] Non-type template arguments of reference and pointer type fail when initialized by pointer to member operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104230 --- Comment #3 from anton at socialhacker dot com --- I've found the relevant discussion about the correct way to mangle subobject references in template parameters here: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 It looks like Clang already has this implemented. but I'm not sure which version of the compiler has the referenced commits.
[Bug c++/104230] Non-type template arguments of reference and pointer type fail when initialized by pointer to member operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104230 --- Comment #2 from anton at socialhacker dot com --- Hmm, sorry, still learning the bugzilla UI. I thought that patch would be attached to my next comment. I don't believe that patch is a solution to the problem. It was just a way I was able to make progress debugging the issue. I followed that patch with one that allowed GCC to mangle the resulting POINTER_PLUS_EXPR. But the end result was that the two template instantiations were not considered the same (as far as __is_same was concerned). I'm pretty sure that the problem is upstream instead of downstream from the location where the diagnostic is generated (in invalid_tparm_referent_p). And I've been working my way backwards into the parser, but it's much slower going for me. I've found where the two different parse trees are generated for the two different version of the template parameters. But they happen in such different portions of the parser I'm not sure at all how to have them generate the same tree eventually, which is I'm guessing the right answer to the problem. That is, instead of generating a COMPONENT_REF for the accepted form, and a POINTER_PLUS_EXPR for the rejected form, GCC should probably be generating COMPONENT_REF for both. But I think it's forgotten the required information to do that conversion from POINTER_PLUS_EXPR by the time it's needed. I'm guessing someone who knows the parser side well might have a better chance at seeing how that should be done.
[Bug c++/104230] Non-type template arguments of reference and pointer type fail when initialized by pointer to member operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104230 --- Comment #1 from anton at socialhacker dot com --- Created attachment 52321 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52321=edit Patch to get member references via pointers accepted as template arguments
[Bug c++/104230] New: Non-type template arguments of reference and pointer type fail when initialized by pointer to member operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104230 Bug ID: 104230 Summary: Non-type template arguments of reference and pointer type fail when initialized by pointer to member operator Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: anton at socialhacker dot com Target Milestone: --- I believe that GCC incorrectly rejects non-type template arguments of pointer and reference type that were generated by using the pointer to member operator. My reading of "P1907R1: Inconsistencies with non-type template parameters" [1] makes me think that these uses should be acceptable. In particular the change to "13.4.2 [temp.arg.nontype] paragraph 2" moves the restriction of passing a reference to a subobject so that it only applies to subobjects of already disallowed values (temporaries, string literals ...). And it looks like that's working when using direct member access operators, but not when using pointer to member operators. And nothing there seems to indicate how the reference or pointer is generated, so presumably any valid constant expression that generates a valid pointer or reference should be acceptable. Below is a simple test case that fails on both the trunk [2] and 11.2 [3] versions on compiler explorer. struct T { int a; int b; } t; template struct U {}; U<> u1; U<> u2; U<(&(t.*(::a)))> u3; // Interestingly doesn't fail, good? U<(&(t.*(::b)))> u4; // Fails, shouldn't fail in C++20 I believe template struct V {}; V v1; V v2; V<(t.*(::a))> v3; // Fails, shouldn't fail in C++20 I believe V<(t.*(::b))> v4; // Fails, shouldn't fail in C++20 I believe Both compiler version produce the same output when run with `--std=c++20 -Wall`: :8:18: error: '(((int*)(& t)) + 4)' is not a valid template argument for 'int*' because it is not the address of a variable 8 | U<(&(t.*(::b)))> u4; | ^ :14:15: error: '&(int&)(& t)' is not a valid template argument of type 'int&' because '(int&)(& t)' is not a variable 14 | V<(t.*(::a))> v3; | ^ :15:15: error: '&(((int&)(& t)) + 4)' is not a valid template argument of type 'int&' because '(((int&)(& t)) + 4)' is not a variable 15 | V<(t.*(::b))> v4; | ^ [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1907r1.html [2] gcc version 12.0.1 20220125 (experimental) (Compiler-Explorer-Build-gcc-bb99171b9b0f01a46bfca2d3cbd52fc6faf6cbaa-binutils-2.36.1) [3] gcc version 11.2.0 (Compiler-Explorer-Build-gcc--binutils-2.36.1)