summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-04-22 02:13:50 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-04-22 02:13:50 +0000
commite85e1766005ef4510d388f99e5084259b327c594 (patch)
treed6b2054462681d218d3e7f8c465e28e15753cefb /clang
parent4304101fb2991826b13cfd68a5d9798595906d04 (diff)
downloadbcm5719-llvm-e85e1766005ef4510d388f99e5084259b327c594.tar.gz
bcm5719-llvm-e85e1766005ef4510d388f99e5084259b327c594.zip
PR12585: When processing a friend template inside a class template, don't
pretend there was no previous declaration -- that can lead us to injecting a class template (with no access specifier) into a class scope. Instead, just avoid the problematic checks. llvm-svn: 155303
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp27
-rw-r--r--clang/test/PCH/cxx-friends.cpp8
-rw-r--r--clang/test/PCH/cxx-friends.h12
-rw-r--r--clang/test/SemaTemplate/friend-template.cpp35
5 files changed, 69 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 007869c4374..113a8fc3e54 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3658,6 +3658,8 @@ def err_member_def_undefined_record : Error<
"out-of-line definition of %0 from class %1 without definition">;
def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
+def err_friend_decl_does_not_match : Error<
+ "friend declaration of %0 does not match any declaration in %1">;
def err_member_def_does_not_match_suggest : Error<
"out-of-line definition of %0 does not match any declaration in %1; "
"did you mean %2?">;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f1581e0c349..d4b09753d30 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -969,20 +969,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
}
}
-
- if (CurContext->isDependentContext() && PrevClassTemplate) {
- // If this is a dependent context, we don't want to link the friend
- // class template to the template in scope, because that would perform
- // checking of the template parameter lists that can't be performed
- // until the outer context is instantiated.
- PrevDecl = PrevClassTemplate = 0;
- }
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = PrevClassTemplate = 0;
if (PrevClassTemplate) {
- // Ensure that the template parameter lists are compatible.
- if (!TemplateParameterListsAreEqual(TemplateParams,
+ // Ensure that the template parameter lists are compatible. Skip this check
+ // for a friend in a dependent context: the template parameter list itself
+ // could be dependent.
+ if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
+ !TemplateParameterListsAreEqual(TemplateParams,
PrevClassTemplate->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
@@ -1031,8 +1026,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Check the template parameter list of this declaration, possibly
// merging in the template parameter list from the previous class
- // template declaration.
- if (CheckTemplateParameterList(TemplateParams,
+ // template declaration. Skip this check for a friend in a dependent
+ // context, because the template parameter list might be dependent.
+ if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
+ CheckTemplateParameterList(TemplateParams,
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0,
(SS.isSet() && SemanticContext &&
SemanticContext->isRecord() &&
@@ -1044,9 +1041,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SS.isSet()) {
// If the name of the template was qualified, we must be defining the
// template out-of-line.
- if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
- !(TUK == TUK_Friend && CurContext->isDependentContext())) {
- Diag(NameLoc, diag::err_member_def_does_not_match)
+ if (!SS.isInvalid() && !Invalid && !PrevClassTemplate) {
+ Diag(NameLoc, TUK == TUK_Friend ? diag::err_friend_decl_does_not_match
+ : diag::err_member_def_does_not_match)
<< Name << SemanticContext << SS.getRange();
Invalid = true;
}
diff --git a/clang/test/PCH/cxx-friends.cpp b/clang/test/PCH/cxx-friends.cpp
index a8d75586e43..bdba42bbcb5 100644
--- a/clang/test/PCH/cxx-friends.cpp
+++ b/clang/test/PCH/cxx-friends.cpp
@@ -11,3 +11,11 @@ class F {
a->x = 0;
}
};
+
+template<typename T> class PR12585::future_base::setter {
+public:
+ int f() {
+ return promise<T*>().k;
+ }
+};
+int k = PR12585::future_base::setter<int>().f();
diff --git a/clang/test/PCH/cxx-friends.h b/clang/test/PCH/cxx-friends.h
index 2a33f15a532..05dcc960663 100644
--- a/clang/test/PCH/cxx-friends.h
+++ b/clang/test/PCH/cxx-friends.h
@@ -4,3 +4,15 @@ class A {
int x;
friend class F;
};
+
+namespace PR12585 {
+ struct future_base {
+ template<typename> class setter;
+ };
+ template<typename> class promise {
+ // We used to inject this into future_base with no access specifier,
+ // then crash during AST writing.
+ template<typename> friend class future_base::setter;
+ int k;
+ };
+}
diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 2b05527cf17..9acbfdcea29 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -267,3 +267,38 @@ namespace PR12557 {
Bar<int> b;
}
+
+namespace PR12585 {
+ struct A { };
+ template<typename> struct B {
+ template<typename> friend class A::does_not_exist; // \
+ // expected-error {{friend declaration of 'does_not_exist' does not match any declaration in 'PR12585::A'}}
+ };
+
+ struct C {
+ template<typename> struct D;
+ };
+ template<typename> class E {
+ int n;
+ template<typename> friend struct C::D;
+ };
+ template<typename T> struct C::D {
+ int f() {
+ return E<int>().n;
+ }
+ };
+ int n = C::D<void*>().f();
+
+ struct F {
+ template<int> struct G;
+ };
+ 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}}
+ };
+ H<int> h1; // ok
+ H<char> h2; // expected-note {{instantiation}}
+}
OpenPOWER on IntegriCloud