summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-01-07 06:00:46 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-01-07 06:00:46 +0000
commit02db2fa1a919655cb54a160131c3ca6a3fa215b5 (patch)
tree739cca0952f0b9344e93b1bc928cf57f2b900d39 /lib/Sema/SemaOverload.cpp
parent1a1eb1e55e1bccc461ae696bc445541f6fef3cd0 (diff)
downloadclang-02db2fa1a919655cb54a160131c3ca6a3fa215b5.tar.gz
DR674, PR38883, PR40238: Qualified friend lookup should look for a
template specialization if there is no matching non-template function. This exposed a couple of related bugs: - we would sometimes substitute into a friend template instead of a suitable non-friend declaration; this would now crash because we'd decide the specialization of the friend is a redeclaration of itself - ADL failed to properly handle the case where an invisible local extern declaration redeclares an invisible friend Both are fixed herein: in particular, we now never make invisible friends or local extern declarations visible to name lookup unless they are the only declaration of the entity. (We already mostly did this for local extern declarations.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@350505 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp29
1 files changed, 29 insertions, 0 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 257eef435f..172116e30c 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1041,6 +1041,35 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
}
}
+ // C++ [temp.friend]p1:
+ // For a friend function declaration that is not a template declaration:
+ // -- if the name of the friend is a qualified or unqualified template-id,
+ // [...], otherwise
+ // -- if the name of the friend is a qualified-id and a matching
+ // non-template function is found in the specified class or namespace,
+ // the friend declaration refers to that function, otherwise,
+ // -- if the name of the friend is a qualified-id and a matching function
+ // template is found in the specified class or namespace, the friend
+ // declaration refers to the deduced specialization of that function
+ // template, otherwise
+ // -- the name shall be an unqualified-id [...]
+ // If we get here for a qualified friend declaration, we've just reached the
+ // third bullet. If the type of the friend is dependent, skip this lookup
+ // until instantiation.
+ if (New->getFriendObjectKind() && New->getQualifier() &&
+ !New->getType()->isDependentType()) {
+ LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
+ TemplateSpecResult.addAllDecls(Old);
+ if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
+ /*QualifiedFriend*/true)) {
+ New->setInvalidDecl();
+ return Ovl_Overload;
+ }
+
+ Match = TemplateSpecResult.getAsSingle<FunctionDecl>();
+ return Ovl_Match;
+ }
+
return Ovl_Overload;
}