diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-02 00:49:05 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-02 00:49:05 +0000 |
commit | 2d77937455e8f133a9e4df562d91f40a97c59c8c (patch) | |
tree | 883f2206314d3e0a89c277b34fbb624ce763f58b | |
parent | 7a72a8bc72710febe64ee092f919514f3de6cf88 (diff) |
Diagnose non-dependent qualified friend function template declarations
that don't match any existing declaration. Don't get confused and treat
such declarations as template *specializations*.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359746 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 1 | ||||
-rw-r--r-- | test/SemaCXX/friend-template-redecl.cpp | 10 | ||||
-rw-r--r-- | test/SemaCXX/lambda-expressions.cpp | 21 |
4 files changed, 23 insertions, 12 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 33ccdf0bba..a97e3573b9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9086,8 +9086,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // nothing will diagnose that error later. if (isFriend && (D.getCXXScopeSpec().getScopeRep()->isDependent() || - (!Previous.empty() && (TemplateParamLists.size() || - CurContext->isDependentContext())))) { + (!Previous.empty() && CurContext->isDependentContext()))) { // ignore these } else { // The user tried to provide an out-of-line definition for a diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 73f3e75c80..2b0467fa86 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1056,6 +1056,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, // third bullet. If the type of the friend is dependent, skip this lookup // until instantiation. if (New->getFriendObjectKind() && New->getQualifier() && + !New->getDescribedFunctionTemplate() && !New->getDependentSpecializationInfo() && !New->getType()->isDependentType()) { LookupResult TemplateSpecResult(LookupResult::Temporary, Old); diff --git a/test/SemaCXX/friend-template-redecl.cpp b/test/SemaCXX/friend-template-redecl.cpp index 3e05964fb2..4ee03c6f63 100644 --- a/test/SemaCXX/friend-template-redecl.cpp +++ b/test/SemaCXX/friend-template-redecl.cpp @@ -1,7 +1,5 @@ // RUN: %clang_cc1 -std=c++17 -verify -emit-llvm-only %s -// expected-no-diagnostics - template <class T> void bar(const T &t) { foo(t); } template <class> @@ -18,3 +16,11 @@ void f() { foo(x); bar(x); } + +template<typename T> void droid(); +struct X { + template<typename T> friend void ::droid(); + template<int N> friend void ::droid(); // expected-error {{does not match}} + // FIXME: We should produce a note for the above candidate explaining why + // it's not the droid we're looking for. +}; diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index 4565345fc6..1833400be3 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -586,25 +586,30 @@ namespace PR25627_dont_odr_use_local_consts { namespace ConversionOperatorDoesNotHaveDeducedReturnType { auto x = [](int){}; - auto y = [](auto) -> void {}; + auto y = [](auto &v) -> void { v.n = 0; }; using T = decltype(x); using U = decltype(y); using ExpectedTypeT = void (*)(int); template<typename T> - using ExpectedTypeU = void (*)(T); + using ExpectedTypeU = void (*)(T&); struct X { + friend auto T::operator()(int) const; friend T::operator ExpectedTypeT() const; - // Formally, this is invalid, because the return type of the conversion - // function for a generic lambda expression is an unspecified decltype - // type, which this should not match. However, this declaration is - // functionally equivalent to that one, so we're permitted to choose to - // accept this. + // FIXME: The first of these should match. The second should not. template<typename T> - friend U::operator ExpectedTypeU<T>() const; + friend void U::operator()(T&) const; // expected-error {{does not match}} + template<typename T> + friend U::operator ExpectedTypeU<T>() const; // expected-error {{does not match}} + + private: + int n; }; + // Should be OK: lambda's call operator is a friend. + void use(X &x) { y(x); } + // This used to crash in return type deduction for the conversion opreator. struct A { int n; void f() { +[](decltype(n)) {}; } }; } |