[PATCH] D20192: [Sema] Fix bug to do with lookup of template friend function in namespace
Erik Pilkington via cfe-commits
cfe-commits at lists.llvm.org
Wed May 11 17:58:30 PDT 2016
erik.pilkington created this revision.
erik.pilkington added a reviewer: rsmith.
erik.pilkington added a subscriber: cfe-commits.
Clang erroneously rejects the following code because it does not find the default argument for `makeType` :
```
namespace n {
template <class> struct Type {
template <class T> friend Type<T> makeType();
};
template <class T = void> Type<T> makeType();
void f() {
Type<void> t;
n::makeType<>(); // Error, lookup finds wrong version of makeType
}
} // end namespace n
```
The problem is that during instantiation of `Type<void>` on the previous line the default template argument version of `makeType` is incorrectly swapped out of `DeclContext::LookupPtr` for the friend version. This patch fixes that by disallowing the swap in `NamedDecl::declarationReplaces()`.
This patch looks like it's a fix for PR10856, PR18038, PR20877, and PR26962.
http://reviews.llvm.org/D20192
Files:
lib/AST/Decl.cpp
test/SemaTemplate/friend-template.cpp
Index: test/SemaTemplate/friend-template.cpp
===================================================================
--- test/SemaTemplate/friend-template.cpp
+++ test/SemaTemplate/friend-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
// PR5057
namespace test0 {
namespace std {
@@ -69,16 +69,13 @@
template<typename T, T Value> struct X2a;
- template<typename T, int Size> struct X2b;
+ template<typename T, int Size> struct X2b; // expected-note {{previous non-type template parameter with type 'int' is here}}
template<typename T>
class X3 {
template<typename U, U Value> friend struct X2a;
- // FIXME: the redeclaration note ends up here because redeclaration
- // lookup ends up finding the friend target from X3<int>.
- template<typename U, T Value> friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}} \
- // expected-note {{previous non-type template parameter with type 'int' is here}}
+ template<typename U, T Value> friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}}
};
X3<int> x3i; // okay
@@ -297,14 +294,10 @@
int n = C::D<void*>().f();
struct F {
- template<int> struct G;
+ template<int> struct G; // expected-note {{previous non-type template parameter with type 'int' is here}}
};
template<typename T> struct H {
- // FIXME: As with cases above, the note here is on an unhelpful declaration,
- // and should point to the declaration of G within F.
- template<T> friend struct F::G; // \
- // expected-error {{different type 'char' in template redeclaration}} \
- // expected-note {{previous}}
+ template<T> friend struct F::G; // expected-error {{different type 'char' in template redeclaration}}
};
H<int> h1; // ok
H<char> h2; // expected-note {{instantiation}}
@@ -329,3 +322,16 @@
foo(b); // expected-note {{in instantiation}}
}
}
+
+namespace PR26962 {
+template <class> struct Type {
+ template <class T> friend Type<T> makeType();
+};
+
+template <class T = void> Type<T> makeType();
+
+void f() {
+ Type<void> t;
+ PR26962::makeType<>();
+}
+} // end PR26962
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1520,6 +1520,10 @@
if (OldD->isFromASTFile() && isFromASTFile())
return false;
+ // Do not replace a declaration with a friend.
+ if (getFriendObjectKind() != FOK_None)
+ return false;
+
// A kind mismatch implies that the declaration is not replaced.
if (OldD->getKind() != getKind())
return false;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D20192.56988.patch
Type: text/x-patch
Size: 2787 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160512/64f4af36/attachment.bin>
More information about the cfe-commits
mailing list