]> granicus.if.org Git - clang/commitdiff
When parsing a template friend declaration we dropped the template
authorChandler Carruth <chandlerc@gmail.com>
Tue, 3 May 2011 18:35:10 +0000 (18:35 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Tue, 3 May 2011 18:35:10 +0000 (18:35 +0000)
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

include/clang/Sema/Sema.h
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
test/CXX/temp/temp.decls/temp.friend/p3.cpp
test/SemaTemplate/friend-template.cpp

index 1129adda49da9f0068a69994c7cc0997963a9160..7d970a8695f8ee32004a5912dab3d4ca784f7e78 100644 (file)
@@ -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);
 
index 8c0aa1ba694ce60f4fa25f40fa9e932e24e687db..596778dbd3209b12a72a36c52213cdf985d22db5 100644 (file)
@@ -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;
   }
index 7214988bdafc9e027bdfd6fc0904982872713e0a..975a96357481a72e433187e55a288c0392442309 100644 (file)
@@ -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
index d116e016f1d2ac1cbd4a4c89ba1ef53195b44b40..0b2a25e9876be66d83d7267413269f779bca92e4 100644 (file)
@@ -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}}
 };
index 703daea3e63005d363e4a6a9d9f1d5fe96d0d4ef..d1284de35f188b45e6fc502eeeeffcef6a93aa7e 100644 (file)
@@ -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>;
+}