aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaDecl.cpp9
-rw-r--r--lib/Sema/SemaOverload.cpp3
-rw-r--r--test/SemaCXX/friend.cpp16
4 files changed, 29 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 858df1754b..c4815cd7ea 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -867,6 +867,8 @@ def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
+def err_using_decl_friend : Error<
+ "cannot befriend target of using declaration">;
def err_invalid_member_in_interface : Error<
"%select{data member |non-public member function |static member function |"
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a6ba68060d..1288568401 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2277,6 +2277,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) {
+ if (New->getFriendObjectKind()) {
+ Diag(New->getLocation(), diag::err_using_decl_friend);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(),
+ diag::note_using_decl) << 0;
+ return true;
+ }
+
Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
Diag(Shadow->getTargetDecl()->getLocation(),
diag::note_using_decl_target);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 5d931cfcaf..89d495ddc1 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -920,7 +920,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
// function templates hide function templates with different
// return types or template parameter lists.
bool UseMemberUsingDeclRules =
- (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord();
+ (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() &&
+ !New->getFriendObjectKind();
if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) {
if (!IsOverload(New, OldT->getTemplatedDecl(), UseMemberUsingDeclRules)) {
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index c5b11eb5a3..b401a06a7e 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -138,3 +138,19 @@ namespace test7 {
};
}
}
+
+// PR15485
+namespace test8 {
+ namespace ns1 {
+ namespace ns2 {
+ template<class T> void f(T t); // expected-note {{target of using declaration}}
+ }
+ using ns2::f; // expected-note {{using declaration}}
+ }
+ struct A { void f(); }; // expected-note {{target of using declaration}}
+ struct B : public A { using A::f; }; // expected-note {{using declaration}}
+ struct X {
+ template<class T> friend void ns1::f(T t); // expected-error {{cannot befriend target of using declaration}}
+ friend void B::f(); // expected-error {{cannot befriend target of using declaration}}
+ };
+}