aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-08-20 01:40:01 +0000
committerJohn McCall <rjmccall@apple.com>2010-08-20 01:40:01 +0000
commit29c695b86199ce917fd59b875683960a1858342a (patch)
tree5738de2342a8ffcdede6ec1c4c85b692b98ad02c
parent59b6dca7e5160d6f2aff42b1cf077d1cbd64e330 (diff)
Detect efforts to declare a template member friend and explicitly ignore them.
Avoids a crash. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111609 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaAccess.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--lib/Sema/SemaTemplate.cpp11
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp61
4 files changed, 68 insertions, 9 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 90d3177222..e2b7a7e061 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -514,6 +514,9 @@ static AccessResult MatchesFriend(Sema &S,
static AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
FriendDecl *FriendD) {
+ if (FriendD->isInvalidDecl())
+ return AR_accessible;
+
if (TypeSourceInfo *T = FriendD->getFriendType())
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1958095783..1d633a9048 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6538,6 +6538,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
+ if (ND->isInvalidDecl()) FrD->setInvalidDecl();
+
return DeclPtrTy::make(ND);
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5cfacf78b5..af852aa340 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1365,8 +1365,12 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (Idx >= NumParamLists)
+ if (Idx >= NumParamLists) {
+ // Silently drop template member friend declarations.
+ // TODO: implement these
+ if (IsFriend && NumParamLists) Invalid = true;
return 0;
+ }
// If there were too many template parameter lists, complain about that now.
if (Idx != NumParamLists - 1) {
@@ -1395,6 +1399,11 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
}
}
+ // Silently drop template member template friend declarations.
+ // TODO: implement these
+ if (IsFriend && NumParamLists > 1)
+ Invalid = true;
+
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists[NumParamLists - 1];
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index f23611bd50..82c2b3169d 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -1,13 +1,58 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template <class T> class A {
- class Member {
+namespace test0 {
+ template <class T> class A {
+ class Member {};
};
-};
-class B {
- template <class T> friend class A<T>::Member;
-};
+ class B {
+ template <class T> friend class A<T>::Member;
+ };
+
+ A<int> a;
+ B b;
+}
+
+// rdar://problem/8204127
+namespace test1 {
+ template <class T> struct A;
+
+ class C {
+ static void foo();
+ template <class T> friend void A<T>::f();
+ };
-A<int> a;
-B b;
+ template <class T> struct A {
+ void f() { C::foo(); }
+ };
+
+ template <class T> struct A<T*> {
+ void f() { C::foo(); }
+ };
+
+ template <> struct A<char> {
+ void f() { C::foo(); }
+ };
+}
+
+// FIXME: these should fail!
+namespace test2 {
+ template <class T> struct A;
+
+ class C {
+ static void foo();
+ template <class T> friend void A<T>::g();
+ };
+
+ template <class T> struct A {
+ void f() { C::foo(); }
+ };
+
+ template <class T> struct A<T*> {
+ void f() { C::foo(); }
+ };
+
+ template <> struct A<char> {
+ void f() { C::foo(); }
+ };
+}