blob: 91b797034ed6cf040b2fdbba066a36112d4a4ab8 [file] [log] [blame]
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
template <typename T>
concept constraint = false;
namespace temp_friend_9 {
// A non-template friend declaration with a requires-clause shall be a
// definition. ...Such a constrained friend function ... does not declare the
// same function or function template as a declaration in any other scope.
template <typename T>
struct NonTemplateFriend {
friend void foo()
requires true
{}
friend void baz() // expected-error {{non-template friend declaration with a requires clause must be a definition}}
requires true;
};
struct TempP9NotShownIfFunctionWouldBeInvalidAnyway {
friend void foo()
requires true; // expected-error {{non-templated function cannot have a requires clause}}
};
// A friend function template with a constraint that depends on a template
// parameter from an enclosing template shall be a definition. Such a ...
// function template declaration does not declare the same function or
// function template as a declaration in any other scope.
template <typename T>
struct TemplateFromEnclosing {
template <typename U>
friend void bar2() // expected-error {{friend declaration with a constraint that depends on an enclosing template parameter must be a definition}}
requires constraint<T>;
template <typename U>
friend void foo()
requires constraint<T>
{}
T variable;
template <typename U>
friend void foo2()
requires constraint<decltype(variable)>
{}
template <typename U>
friend void foo3(T parmvar)
requires constraint<decltype(parmvar)>
{}
template <typename U>
friend void foo4()
requires requires(T &req) { (void)req; }
{}
using Alias = T;
template <typename U>
friend void foo5()
requires constraint<Alias>
{}
// All of these refer to a parent, so these are not duplicate definitions.
struct ChildOfEnclosing {
template <typename U>
friend void foo6()
requires constraint<T>
{}
template <typename U>
friend void foo7()
requires constraint<decltype(variable)>
{}
template <typename U>
friend void foo8(T parmvar)
requires constraint<decltype(parmvar)>
{}
// This is NOT a duplicate since it itself is not a template.
friend void foo9()
requires true
{}
};
template <typename T2>
struct TemplChildOfEnclosing {
template <typename U>
friend void foo10()
requires constraint<T>
{}
};
};
// Doesn't meet either of the requirements in the above as they don't refer to
// an enclosing scope.
template <typename T>
struct Redefinition {
template <typename U>
friend void foo() // #REDEF
requires constraint<U>
{}
struct ChildOfRedef {
template <typename U>
friend void foo2() // #REDEF2
requires constraint<U>
{}
};
template <typename T2>
struct ChildOfRedef2 {
template <typename U>
friend void foo3() // #REDEF3
requires constraint<U>
{}
};
};
void bar() {
NonTemplateFriend<int> S1;
NonTemplateFriend<float> S2;
TemplateFromEnclosing<int> S3;
TemplateFromEnclosing<int>::ChildOfEnclosing S3b;
TemplateFromEnclosing<float> S4;
TemplateFromEnclosing<float>::ChildOfEnclosing S4b;
Redefinition<int> S5;
Redefinition<float> S6;
// expected-error@#REDEF {{redefinition of 'foo'}}
// expected-note@-2{{in instantiation of template class }}
// expected-note@#REDEF {{previous definition is here}}
Redefinition<int>::ChildOfRedef S7;
Redefinition<float>::ChildOfRedef S8;
// expected-error@#REDEF2 {{redefinition of 'foo2'}}
// expected-note@-2{{in instantiation of member class }}
// expected-note@#REDEF2 {{previous definition is here}}
Redefinition<int>::ChildOfRedef2<int> S9;
Redefinition<float>::ChildOfRedef2<float> S10;
// expected-error@#REDEF3 {{redefinition of 'foo3'}}
// expected-note@-2{{in instantiation of template class }}
// expected-note@#REDEF3 {{previous definition is here}}
}
} // namespace temp_friend_9
namespace SameScopeRedefs {
template <typename T>
struct NonTemplateFriend {
friend void foo() // #NTF1
requires true
{}
friend void foo() // #NTF2
requires true
{}
};
template <typename T>
struct TemplateFromEnclosing {
template <typename U>
friend void foo() // #TFE1
requires constraint<T>
{}
template <typename U>
friend void foo() // #TFE2
requires constraint<T>
{}
};
// Same as above, but doesn't require an instantiation pair to cause.
template <typename T>
struct Redefinition {
template <typename U>
friend void foo() // #RD1
requires constraint<U>
{}
template <typename U>
friend void foo() // #RD2
requires constraint<U>
{}
};
void bar() {
NonTemplateFriend<int> S1;
// expected-error@#NTF2 {{redefinition of 'foo'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#NTF1 {{previous definition is here}}
TemplateFromEnclosing<int> S2;
// expected-error@#TFE2 {{redefinition of 'foo'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#TFE1 {{previous definition is here}}
Redefinition<int> S3;
// expected-error@#RD2 {{redefinition of 'foo'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#RD1 {{previous definition is here}}
}
} // namespace SameScopeRedefs
namespace LibCXXOperatorRedef {
template <typename T, typename U> struct is_same {
static constexpr bool value = false;
};
template <typename T> struct is_same<T, T> {
static constexpr bool value = false;
};
template <typename T, typename U>
concept same_as = is_same<T, U>::value;
// An issue found from libcxx when trying to commit the deferred concepts patch.
// This caused an error of 'redefinition of funcN'.
template <class _Tp> struct __range_adaptor_closure {
template <typename _View, typename _Closure>
requires same_as<_Tp, _Closure>
friend constexpr decltype(auto) R1func1(_View &&__view,
_Closure &&__closure){};
template <typename _View, typename _Closure>
friend constexpr decltype(auto) R1func2(_View &&__view,
_Closure &&__closure)
requires same_as<_Tp, _Closure>
{};
template <same_as<_Tp> _View, typename _Closure>
friend constexpr decltype(auto) R1func3(_View &&__view,
_Closure &&__closure){};
};
struct A : __range_adaptor_closure<A> {};
struct B : __range_adaptor_closure<B> {};
// These three fail because after the 1st pass of instantiation, they are still
// identical.
template <class _Tp> struct __range_adaptor_closure2 {
template <typename _View, typename _Closure>
requires same_as<_View, _Closure>
friend constexpr decltype(auto) R2func1(_View &&__view, // #FUNC1
_Closure &&__closure){};
template <typename _View, typename _Closure>
friend constexpr decltype(auto) R2func2(_View &&__view, // #FUNC2
_Closure &&__closure)
requires same_as<_View, _Closure>
{};
template <typename _View, same_as<_View> _Closure>
friend constexpr decltype(auto) R2func3(_View &&__view, // #FUNC3
_Closure &&__closure){};
};
struct A2 : __range_adaptor_closure2<A2> {};
struct B2 : __range_adaptor_closure2<B2> {};
// expected-error@#FUNC1{{redefinition of 'R2func1'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#FUNC1{{previous definition is here}}
// expected-error@#FUNC2{{redefinition of 'R2func2'}}
// expected-note@#FUNC2{{previous definition is here}}
// expected-error@#FUNC3{{redefinition of 'R2func3'}}
// expected-note@#FUNC3{{previous definition is here}}
// These three are fine, they all depend on the parent template parameter, so
// are different despite ::type not being valid.
template <class _Tp> struct __range_adaptor_closure3 {
template <typename _View, typename _Closure>
requires same_as<typename _Tp::type, _Closure>
friend constexpr decltype(auto) R3func1(_View &&__view,
_Closure &&__closure){};
template <typename _View, typename _Closure>
friend constexpr decltype(auto) R3func2(_View &&__view,
_Closure &&__closure)
requires same_as<typename _Tp::type, _Closure>
{};
template <same_as<typename _Tp::type> _View, typename _Closure>
friend constexpr decltype(auto) R3func3(_View &&__view,
_Closure &&__closure){};
};
struct A3 : __range_adaptor_closure3<A3> {};
struct B3 : __range_adaptor_closure3<B3> {};
template <class _Tp> struct __range_adaptor_closure4 {
template <typename _View, typename _Closure>
requires same_as<_Tp, _View>
// expected-note@+1{{previous definition is here}}
void foo1(_View &&, _Closure &&) {}
template <typename _View, typename _Closure>
requires same_as<_Tp, _View>
// expected-error@+1{{class member cannot be redeclared}}
void foo1(_View &&, _Closure &&) {}
template <typename _View, typename _Closure>
// expected-note@+1{{previous definition is here}}
void foo2(_View &&, _Closure &&)
requires same_as<_Tp, _View>
{}
template <typename _View, typename _Closure>
// expected-error@+1{{class member cannot be redeclared}}
void foo2(_View &&, _Closure &&)
requires same_as<_Tp, _View>
{}
template <same_as<_Tp> _View, typename _Closure>
// expected-note@+1{{previous definition is here}}
void foo3(_View &&, _Closure &&) {}
template <same_as<_Tp> _View, typename _Closure>
// expected-error@+1{{class member cannot be redeclared}}
void foo3(_View &&, _Closure &&) {}
};
// Requires instantiation to fail, so no errors here.
template <class _Tp> struct __range_adaptor_closure5 {
template <same_as<_Tp> U>
friend void foo() {}
template <same_as<_Tp> U>
friend void foo() {}
};
template <class _Tp> struct __range_adaptor_closure6 {
template <same_as<_Tp> U>
friend void foo() {} // #RAC6FOO1
template <same_as<_Tp> U>
friend void foo() {} // #RAC6FOO2
};
struct A6 : __range_adaptor_closure6<A6> {};
// expected-error@#RAC6FOO2{{redefinition of 'foo'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#RAC6FOO1{{previous definition is here}}
template <class T> struct S1 {
template <typename U>
friend void dupe() {} // #S1DUPE
template <typename U>
requires same_as<U, U>
friend void dupe2() {} // #S1DUPE2
};
template <class T> struct S2 {
template <typename U>
friend void dupe() {} // #S2DUPE
template <typename U>
requires same_as<U, U>
friend void dupe2() {} // #S2DUPE2
};
template <class T> struct S3 {
template <typename U>
requires same_as<T, U>
friend void dupe() {}
};
template <class T> struct S4 {
template <typename U>
requires same_as<T, U>
friend void dupe() {}
};
// Same as S3 and S4, but aren't instantiated with the same T.
template <class T> struct S5 {
template <typename U>
requires same_as<T, U>
friend void not_dupe() {}
};
template <class T> struct S6 {
template <typename U>
requires same_as<T, U>
friend void not_dupe() {}
};
template <class T> struct S7 {
void not_dupe()
requires same_as<T, T>
{}
};
void useS() {
S1<int> s1;
S2<double> s2;
// expected-error@#S2DUPE{{redefinition}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#S1DUPE{{previous definition is here}}
// expected-error@#S2DUPE2{{redefinition}}
// expected-note@#S1DUPE2{{previous definition is here}}
// OK, they have different 'scopes'.
S3<int> s3;
S4<int> s4;
// OK, because only instantiated with different T.
S5<int> s5;
S6<double> s6;
S7<int> s7;
}
} // namespace LibCXXOperatorRedef
namespace NamedDeclRefs {
namespace my_std {
template<typename T, typename U>
concept Outer = true;
template<typename T>
using Inner = T;
}
template<typename T>
struct Proxy {
template<class U>
friend constexpr void RefOuter()
requires my_std::Outer<my_std::Inner<T>, my_std::Inner<U>>{}
template<class U>
friend constexpr void NoRefOuter() // #NOREFOUTER
requires my_std::Outer<my_std::Inner<U>, my_std::Inner<U>>{}
};
void use() {
Proxy<int> p;
Proxy<float> p2;
// expected-error@#NOREFOUTER {{redefinition of 'NoRefOuter'}}
// expected-note@-2{{in instantiation of template class}}
// expected-note@#NOREFOUTER{{previous definition is here}}
}
} // namespace NamedDeclRefs
namespace RefersToParentInConstraint {
// No diagnostic, these aren't duplicates.
template<typename T, typename U>
concept similar = true;
template <typename X>
struct S{
friend void f(similar<S> auto && self){}
friend void f2(similar<S<X>> auto && self){}
};
void use() {
S<int> x;
S<long> y;
}
} // namespace RefersToParentInConstraint
namespace NTTP {
struct Base{};
template<int N>
struct S : Base {
// N is from the parent template.
template<typename T>
friend int templ_func(Base&) requires(N > 0)
{ return 10; }
};
template<typename T>
struct U : Base {
template<T N>
friend int templ_func(Base&) requires(N>0)
{ return 10; }
};
void use() {
S<1> s1;
templ_func<float>(s1);
S<2> s2;
templ_func<float>(s2);
U<int> u1;
templ_func<1>(u1);
U<short> u2;
templ_func<1>(u2);
}
}
namespace FriendOfFriend {
template <typename>
concept Concept = true;
template <Concept> class FriendOfBar;
template <Concept> class Bar {
template <Concept> friend class FriendOfBar;
};
Bar<void> BarInstance;
namespace internal {
void FriendOfFoo(FriendOfBar<void>);
}
template <Concept> class Foo {
friend void internal::FriendOfFoo(FriendOfBar<void>);
};
} // namespace FriendOfFriend
namespace GH86769 {
template <typename T>
concept X = true;
template <X T> struct Y {
Y(T) {}
template <X U> friend struct Y;
template <X U> friend struct Y;
template <X U> friend struct Y;
};
template <class T>
struct Z {
// FIXME: This is ill-formed per C++11 N3337 [temp.param]p12:
// A default template argument shall not be specified in a friend class
// template declaration.
template <X U = void> friend struct Y;
};
template struct Y<int>;
template struct Z<int>;
Y y(1);
}