Bug 69836 - compilation error with constexpr in template types with redeclared methods
Summary: compilation error with constexpr in template types with redeclared methods
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 14.0
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 69837 (view as bug list)
Depends on:
Blocks:
 
Reported: 2016-02-16 12:57 UTC by Olivier Goffart
Modified: 2023-05-03 04:37 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2023-02-01 00:00:00


Attachments
testcase (428 bytes, text/plain)
2016-02-16 12:57 UTC, Olivier Goffart
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Goffart 2016-02-16 12:57:22 UTC
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
Comment 1 Marek Polacek 2016-02-25 10:00:50 UTC
*** Bug 69837 has been marked as a duplicate of this bug. ***
Comment 2 Andrew Pinski 2021-12-07 19:01:08 UTC
I wonder if this is just invalid code but no diagnostic required as state changes inside the scope of TemplateObject.
Comment 3 Andrew Pinski 2021-12-07 19:14:21 UTC
(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;
      |             ^
Comment 4 Jason Merrill 2023-02-01 20:21:03 UTC
(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).
Comment 5 Jason Merrill 2023-02-01 20:38:09 UTC
(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.
Comment 6 GCC Commits 2023-04-26 21:16:32 UTC
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.
Comment 7 Jason Merrill 2023-05-03 04:37:43 UTC
Fixed for GCC 14.