Created attachment 37701 [details] testcase The attached code [live: http://melpon.org/wandbox/permlink/wUtHZsr0ZAuiMtK1 ] Produce a compilation error with GCC while it is accepted by clang. file.cc:20:57: error: could not convert 'increment<2>((state((number<N>::prev<3>(), number<2>()), w_this), S<2>()))' from 'S<3>' to 'S<2>' RETURN(increment(state(w_counter.prev(), w_this))) ^ file.cc:11:43: note: in definition of macro 'RETURN' #define RETURN(R) -> decltype(R) { return R; } ^ Since decltype and the return value are both the same, this should not be a problem. It seems that gcc misunderstand the type of w_counter. Also in the error message there is "(number<N>::prev<3>(), number<2>())" why is there a commas there, and where does this <3> comes from? When the class (TemplateObject) is not a template, then the compilaiton passes
*** Bug 69837 has been marked as a duplicate of this bug. ***
I wonder if this is just invalid code but no diagnostic required as state changes inside the scope of TemplateObject.
(In reply to Andrew Pinski from comment #2) > I wonder if this is just invalid code but no diagnostic required as state > changes inside the scope of TemplateObject. That is it needs to be reinterpret it after the parsing and needs to same inside the scope itself. Like types of the same name should stay the same if used inside the class. Like: typedef int t; class y { typedef t u; typedef float t; }; Which GCC only handles currently: <source>:5:17: error: declaration of 'typedef float y::t' changes meaning of 't' [-fpermissive] 5 | typedef float t; | ^ <source>:1:13: note: 't' declared here as 'typedef int t' 1 | typedef int t; | ^
(In reply to Andrew Pinski from comment #3) > (In reply to Andrew Pinski from comment #2) > > I wonder if this is just invalid code but no diagnostic required as state > > changes inside the scope of TemplateObject. > > That is it needs to be reinterpret it after the parsing and needs to same > inside the scope itself. Like types of the same name should stay the same if > used inside the class. I have not considered that rule to apply to additional overloads. Here, the problem looks to be that we're re-calculating the type of w_counter inside the function definition (where the current function is in the overload set) rather than using the actual parameter type (which is calculated before the current function is in the overload set).
(In reply to Jason Merrill from comment #4) > Here, the > problem looks to be that we're re-calculating the type of w_counter inside > the function definition (where the current function is in the overload set) > rather than using the actual parameter type (which is calculated before the > current function is in the overload set). Ah, the actual problem is regenerate_decl_from_template changing the type of w_counter.
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:1e27e7e0985e055b3d4ec92e93976b709fdbe425 commit r14-277-g1e27e7e0985e055b3d4ec92e93976b709fdbe425 Author: Jason Merrill <jason@redhat.com> Date: Wed Feb 1 17:00:48 2023 -0500 c++: unique friend shenanigans [PR69836] Normally we re-instantiate a function declaration when we start to instantiate the body in case of multiple declarations. In this wacky testcase, this causes a problem because the type of the w_counter parameter depends on its declaration not being in scope yet, so the name lookup only finds the previous declaration. This isn't a problem for member functions, since they aren't subject to argument-dependent lookup. So let's just skip the regeneration for hidden friends. PR c++/69836 gcc/cp/ChangeLog: * pt.cc (regenerate_decl_from_template): Skip unique friends. gcc/testsuite/ChangeLog: * g++.dg/template/friend76.C: New test.
Fixed for GCC 14.