https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108884

            Bug ID: 108884
           Summary: [temp.friends]/9: Should constraint friends declared
                    in class scope differ with definition out of scope?
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: zyn7109 at gmail dot com
  Target Milestone: ---

Clang implements deferred concept instantiation in
[D126907](https://reviews.llvm.org/D126907). As that patch suggests, according
to [temp.friend]/9, 

> A friend function template with a constraint that depends on a
> template parameter from an enclosing template shall be a definition.
> Such a constrained friend function or function template declaration
> does not declare the same function or function template as a
> declaration in any other scope.

That being said, such code should not compile as constrained friend declaration
(#1) doesn't declare the function defined out of class scope (#2).

(Example comes from https://github.com/clangd/clangd/issues/1511)

```cpp
// https://gcc.godbolt.org/z/sP9xdTqhe
template <typename>
concept C = true;

template <C... Ts>
class Foo
{
private:
  Foo(const Ts&...) {};

public:
  friend auto factory(const C auto&...);  // #1
};

auto factory(const C auto&... ts)  // #2
{
  return Foo{ts...};
}

int main()
{
  factory(5);
}
```

Such code is rejected in Clang 16 onwards, showing that function defined at #2
is trying to access private constructor of `Foo`, but GCC still accepts this,
which implies GCC considers #1 and #2 are the same function. Is this a GCC
regression or I have missed something from the wording?

Note that if we swap #1 and #2, i.e.,
```cpp
// https://gcc.godbolt.org/z/WfG7vnxx8

template <typename>
concept C = true;

template <C... Ts>
class Foo
{
private:
  Foo(const Ts&...) {}

public:
  friend auto factory(const C auto&... ts)
  {
    return Foo{ts...};
  }
};

template <C... Ts>
auto factory(const C auto&... ts) -> Foo<Ts...>;

int main()
{
  factory(5);
}
```

then both GCC and Clang would accept it.

Reply via email to