aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2011-05-03 18:35:10 +0000
committerChandler Carruth <chandlerc@gmail.com>2011-05-03 18:35:10 +0000
commit0f4be74ff0273e505d383f89174ef539828424ed (patch)
tree24263da428c02f4ba6efe5a6ff2ac4aa526a9f67
parente452c78072156c14cd9998733e3b4b28b6fc7fd7 (diff)
When parsing a template friend declaration we dropped the template
parameters on the floor in certain cases: class X { template <typename T> friend typename A<T>::Foo; }; This was parsed as a *non* template friend declaration some how, and received an ExtWarn. Fixing the parser to actually provide the template parameters to the freestanding declaration parse triggers the code which specifically looks for such constructs and hard errors on them. Along the way, this prevents us from trying to instantiate constructs like the above inside of a outer template. This is important as loosing the template parameters means we don't have a well formed declaration and template instantiation will be unable to rebuild the AST. That fixes a crash in the GCC test suite. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130772 91177308-0d34-0410-b5e6-96231b3b80d8
-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>;
+}