[cfe-commits] r155303 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplate.cpp test/PCH/cxx-friends.cpp test/PCH/cxx-friends.h test/SemaTemplate/friend-template.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sat Apr 21 19:13:50 PDT 2012


Author: rsmith
Date: Sat Apr 21 21:13:50 2012
New Revision: 155303

URL: http://llvm.org/viewvc/llvm-project?rev=155303&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/PCH/cxx-friends.cpp
    cfe/trunk/test/PCH/cxx-friends.h
    cfe/trunk/test/SemaTemplate/friend-template.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=155303&r1=155302&r2=155303&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Apr 21 21:13:50 2012
@@ -3658,6 +3658,8 @@
   "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?">;

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=155303&r1=155302&r2=155303&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Apr 21 21:13:50 2012
@@ -969,20 +969,15 @@
           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 @@
 
   // 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 @@
   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;
     }

Modified: cfe/trunk/test/PCH/cxx-friends.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-friends.cpp?rev=155303&r1=155302&r2=155303&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-friends.cpp (original)
+++ cfe/trunk/test/PCH/cxx-friends.cpp Sat Apr 21 21:13:50 2012
@@ -11,3 +11,11 @@
     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();

Modified: cfe/trunk/test/PCH/cxx-friends.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-friends.h?rev=155303&r1=155302&r2=155303&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-friends.h (original)
+++ cfe/trunk/test/PCH/cxx-friends.h Sat Apr 21 21:13:50 2012
@@ -4,3 +4,15 @@
   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;
+  };
+}

Modified: cfe/trunk/test/SemaTemplate/friend-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/friend-template.cpp?rev=155303&r1=155302&r2=155303&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/friend-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/friend-template.cpp Sat Apr 21 21:13:50 2012
@@ -267,3 +267,38 @@
 
   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}}
+}





More information about the cfe-commits mailing list