64 lines · cpp
1// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s2// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s3// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s4// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify=cxx20 %s5// expected-no-diagnostics6 7struct Incomplete;8template <class T> struct Holder { T t; };9 10namespace DotFollowingFunctionName {11struct Good {12 struct Nested {13 int b;14 } a;15};16 17struct Bad {18 Holder<Incomplete> a();19};20 21template <class T>22constexpr auto f(T t) -> decltype((t.a.b, true)) { return true; }23constexpr bool f(...) { return false; }24 25static_assert(DotFollowingFunctionName::f(Good{}), "");26static_assert(!DotFollowingFunctionName::f(Bad{}), "");27 28#if __cplusplus >= 202002L29template <class T>30concept C = requires(T t) { t.a.b; };31 // cxx20-note@-1 {{because 't.a.b' would be invalid: reference to non-static member function must be called}}32 33static_assert(C<Good>);34static_assert(!C<Bad>);35static_assert(C<Bad>); // cxx20-error {{static assertion failed}}36 // cxx20-note@-1 {{because 'Bad' does not satisfy 'C'}}37#endif38} // namespace DotFollowingFunctionName39 40namespace DotFollowingPointer {41struct Good {42 int begin();43};44using Bad = Holder<Incomplete> *;45 46template <class T>47constexpr auto f(T t) -> decltype((t.begin(), true)) { return true; }48constexpr bool f(...) { return false; }49 50static_assert(DotFollowingPointer::f(Good{}), "");51static_assert(!DotFollowingPointer::f(Bad{}), "");52 53#if __cplusplus >= 202002L54template <class T>55concept C = requires(T t) { t.begin(); };56 // cxx20-note@-1 {{because 't.begin()' would be invalid: member reference type 'Bad' (aka 'Holder<Incomplete> *') is a pointer}}57 58static_assert(C<Good>);59static_assert(!C<Bad>);60static_assert(C<Bad>); // cxx20-error {{static assertion failed}}61 // cxx20-note@-1 {{because 'Bad' (aka 'Holder<Incomplete> *') does not satisfy 'C'}}62#endif63} // namespace DotFollowingPointer64