aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Parse/ParseDeclCXX.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp12
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p3.cpp2
-rw-r--r--test/SemaTemplate/friend-template.cpp8
5 files changed, 24 insertions, 5 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 1129adda49..7d970a8695 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1026,10 +1026,11 @@ public:
void ActOnPopScope(SourceLocation Loc, Scope *S);
void ActOnTranslationUnitScope(Scope *S);
- /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
- /// no declarator (e.g. "struct foo;") is parsed.
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS);
+ Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams);
StmtResult ActOnVlaStmt(const DeclSpec &DS);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 8c0aa1ba69..596778dbd3 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1547,7 +1547,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
Decl *TheDecl =
- Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
DS.complete(TheDecl);
return;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7214988bda..975a963574 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2132,6 +2132,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS) {
+ return ParsedFreeStandingDeclSpec(S, AS, DS,
+ MultiTemplateParamsArg(*this, 0, 0));
+}
+
+/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// parameters to cope with template friend declarations.
+Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -2163,7 +2173,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// whatever routines created it handled the friendship aspect.
if (TagD && !Tag)
return 0;
- return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
// Track whether we warned about the fact that there aren't any
diff --git a/test/CXX/temp/temp.decls/temp.friend/p3.cpp b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
index d116e016f1..0b2a25e987 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
@@ -8,5 +8,5 @@ class B {
template <class T> friend class A;
template <class T> friend class Undeclared;
- template <class T> friend typename A<T>::Member; // expected-warning {{non-class type 'typename A<T>::Member' cannot be a friend}}
+ template <class T> friend typename A<T>::Member; // expected-error {{friend type templates must use an elaborated type}}
};
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 703daea3e6..d1284de35f 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -216,3 +216,11 @@ namespace PR8649 {
X<int, float, 7> x;
}
+
+// Don't crash, and error on invalid friend type template.
+namespace friend_type_template_no_tag {
+ template <typename T> struct S {
+ template <typename U> friend S<U>; // expected-error{{friend type templates must use an elaborated type}}
+ };
+ template struct S<int>;
+}