Bug 93467

Summary: [concepts] getting "type constraint differs in template redeclaration" error after friend declaration in template
Product: gcc Reporter: Robert Zavalczki <robert.zavalczki>
Component: c++Assignee: Patrick Palka <ppalka>
Status: RESOLVED FIXED    
Severity: normal CC: gcc-bugs, ppalka, webrown.cpp
Priority: P3    
Version: 9.2.1   
Target Milestone: 10.2   
Host: Target:
Build: Known to work:
Known to fail: 10.0, 11.0 Last reconfirmed: 2020-05-26 00:00:00

Description Robert Zavalczki 2020-01-27 19:19:27 UTC
I know the C++ standard says:

> "A constrained declaration may only be redeclared using the same syntactic form. No diagnostic is required."

However, that specification causes this supposedly correct program to fail:

///////////////////////////////////////
// compile with: g++-9 -fconcepts -std=c++2a
template<typename T> concept True = true;

template<typename U>
struct S1 {
    template<True T> friend struct S2; // friend declaration for S2
};

S1<int> s; // instantiate S1

template<True T> struct S2; // another declaration for S2
///////////////////////////////////////

You can test the above snippet on godbolt.org: https://godbolt.org/z/V6uJPe
Comment 1 Patrick Palka 2020-05-26 18:41:38 UTC
Reconfirmed on trunk.  I ran into this when writing a fix for PR libstdc++/95322..

Here is another valid testcase which we reject:

template<bool B> requires B
  class C;

template<typename>
class S
{
  template<bool B> requires B
    friend class ::C;
};


testcase.C:8:20: error: ‘C<B>’ does not match original declaration
    8 |     friend class ::C;
      |                    ^
testcase.C:2:9: note: original template declaration here
    2 |   class C;
      |         ^
Comment 2 GCC Commits 2020-06-11 21:05:48 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:11c7261128ad3ee136508703b20e45cbe04f8dd0

commit r11-1243-g11c7261128ad3ee136508703b20e45cbe04f8dd0
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Jun 11 16:33:41 2020 -0400

    c++: constrained class template friend [PR93467]
    
    This fixes two issues in our handling of constrained class template
    friend declarations.
    
    The first issue is that we fail to set the constraints on the injected
    class template declaration during tsubst_friend_class.
    
    The second issue is that the template parameter levels within the parsed
    constraints of a class template friend declaration are shifted if the
    enclosing class is a template, and this shift leads to spurious
    constraint mismatch errors in associate_classtype_constraints if the
    friend declaration refers to an already declared class template.
    
    gcc/cp/ChangeLog:
    
            PR c++/93467
            * constraint.cc (associate_classtype_constraints): If there is a
            discrepancy between the current template depth and the template
            depth of the original declaration, then adjust the template
            parameter depth within the current constraints appropriately.
            * pt.c (tsubst_friend_class): Substitute into and set the
            constraints on the injected declaration.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/93467
            * g++.dg/cpp2a/concepts-friend6.C: New test.
            * g++.dg/cpp2a/concepts-friend7.C: New test.
Comment 3 GCC Commits 2020-06-13 15:32:07 UTC
The releases/gcc-10 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:652ec7e8c046b239c42dedd295acf1815ed2b93a

commit r10-8288-g652ec7e8c046b239c42dedd295acf1815ed2b93a
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Jun 11 16:33:41 2020 -0400

    c++: constrained class template friend [PR93467]
    
    This fixes two issues in our handling of constrained class template
    friend declarations.
    
    The first issue is that we fail to set the constraints on the injected
    class template declaration during tsubst_friend_class.
    
    The second issue is that the template parameter levels within the parsed
    constraints of a class template friend declaration are shifted if the
    enclosing class is a template, and this shift leads to spurious
    constraint mismatch errors in associate_classtype_constraints if the
    friend declaration refers to an already declared class template.
    
    gcc/cp/ChangeLog:
    
            PR c++/93467
            * constraint.cc (associate_classtype_constraints): If there is a
            discrepancy between the current template depth and the template
            depth of the original declaration, then adjust the template
            parameter depth within the current constraints appropriately.
            * pt.c (tsubst_friend_class): Substitute into and set the
            constraints on the injected declaration.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/93467
            * g++.dg/cpp2a/concepts-friend6.C: New test.
            * g++.dg/cpp2a/concepts-friend7.C: New test.
    
    (cherry picked from commit 11c7261128ad3ee136508703b20e45cbe04f8dd0)
Comment 4 Patrick Palka 2020-06-13 15:32:33 UTC
Fixed for GCC 10.2+.