summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-02 00:49:05 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-02 00:49:05 +0000
commit2d77937455e8f133a9e4df562d91f40a97c59c8c (patch)
tree883f2206314d3e0a89c277b34fbb624ce763f58b
parent7a72a8bc72710febe64ee092f919514f3de6cf88 (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.cpp3
-rw-r--r--lib/Sema/SemaOverload.cpp1
-rw-r--r--test/SemaCXX/friend-template-redecl.cpp10
-rw-r--r--test/SemaCXX/lambda-expressions.cpp21
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)) {}; } };
}