[cfe-commits] r116364 - in /cfe/trunk: lib/Sema/SemaAccess.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.friend/p5.cpp

John McCall rjmccall at apple.com
Tue Oct 12 16:13:28 PDT 2010


Author: rjmccall
Date: Tue Oct 12 18:13:28 2010
New Revision: 116364

URL: http://llvm.org/viewvc/llvm-project?rev=116364&view=rev
Log:
Handle dependent friends more explicitly and deal with the possibility
of templated-scope friends by marking them invalid and white-listing all
accesses until such time as we implement them.  Fixes a crash, this time
without a broken test case.


Modified:
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=116364&r1=116363&r2=116364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Tue Oct 12 18:13:28 2010
@@ -516,6 +516,10 @@
 static AccessResult MatchesFriend(Sema &S,
                                   const EffectiveContext &EC,
                                   FriendDecl *FriendD) {
+  // Whitelist accesses if there's an invalid friend declaration.
+  if (FriendD->isInvalidDecl())
+    return AR_accessible;
+
   if (TypeSourceInfo *T = FriendD->getFriendType())
     return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=116364&r1=116363&r2=116364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Oct 12 18:13:28 2010
@@ -3471,7 +3471,9 @@
 
   if (isFriend) {
     // DC is the namespace in which the function is being declared.
-    assert((DC->isFileContext() || !Previous.empty()) &&
+    assert((DC->isFileContext() || !Previous.empty() ||
+            (D.getCXXScopeSpec().isSet() &&
+             D.getCXXScopeSpec().getScopeRep()->isDependent())) &&
            "previously-undeclared friend function being created "
            "in a non-namespace context");
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=116364&r1=116363&r2=116364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Oct 12 18:13:28 2010
@@ -6285,10 +6285,8 @@
   return D;
 }
 
-Decl *Sema::ActOnFriendFunctionDecl(Scope *S,
-                                         Declarator &D,
-                                         bool IsDefinition,
-                              MultiTemplateParamsArg TemplateParams) {
+Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
+                                    MultiTemplateParamsArg TemplateParams) {
   const DeclSpec &DS = D.getDeclSpec();
 
   assert(DS.isFriendSpecified());
@@ -6331,7 +6329,7 @@
   //    declared as a friend, scopes outside the innermost enclosing
   //    namespace scope are not considered.
 
-  CXXScopeSpec &ScopeQual = D.getCXXScopeSpec();
+  CXXScopeSpec &SS = D.getCXXScopeSpec();
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
   assert(Name);
@@ -6339,47 +6337,18 @@
   // The context we found the declaration in, or in which we should
   // create the declaration.
   DeclContext *DC;
-
-  // FIXME: handle local classes
-
-  // Recover from invalid scope qualifiers as if they just weren't there.
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
                         ForRedeclaration);
-  if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
-    DC = computeDeclContext(ScopeQual);
-
-    // FIXME: handle dependent contexts
-    if (!DC) return 0;
-    if (RequireCompleteDeclContext(ScopeQual, DC)) return 0;
-
-    LookupQualifiedName(Previous, DC);
-
-    // Ignore things found implicitly in the wrong scope.
-    // TODO: better diagnostics for this case.  Suggesting the right
-    // qualified scope would be nice...
-    LookupResult::Filter F = Previous.makeFilter();
-    while (F.hasNext()) {
-      NamedDecl *D = F.next();
-      if (!DC->InEnclosingNamespaceSetOf(
-              D->getDeclContext()->getRedeclContext()))
-        F.erase();
-    }
-    F.done();
-
-    if (Previous.empty()) {
-      D.setInvalidType();
-      Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
-      return 0;
-    }
 
-    // C++ [class.friend]p1: A friend of a class is a function or
-    //   class that is not a member of the class . . .
-    if (DC->Equals(CurContext))
-      Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+  // FIXME: there are different rules in local classes
 
-  // Otherwise walk out to the nearest namespace scope looking for matches.
-  } else {
-    // TODO: handle local class contexts.
+  // There are four cases here.
+  //   - There's no scope specifier, in which case we just go to the
+  //     appropriate namespace and create a function or function template
+  //     there as appropriate.
+  // Recover from invalid scope qualifiers as if they just weren't there.
+  if (SS.isInvalid() || !SS.isSet()) {
+    // Walk out to the nearest namespace scope looking for matches.
 
     DC = CurContext;
     while (true) {
@@ -6411,6 +6380,49 @@
     if (!Previous.empty() && DC->Equals(CurContext)
         && !getLangOptions().CPlusPlus0x)
       Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+
+  //   - There's a non-dependent scope specifier, in which case we
+  //     compute it and do a previous lookup there for a function
+  //     or function template.
+  } else if (!SS.getScopeRep()->isDependent()) {
+    DC = computeDeclContext(SS);
+    if (!DC) return 0;
+
+    if (RequireCompleteDeclContext(SS, DC)) return 0;
+
+    LookupQualifiedName(Previous, DC);
+
+    // Ignore things found implicitly in the wrong scope.
+    // TODO: better diagnostics for this case.  Suggesting the right
+    // qualified scope would be nice...
+    LookupResult::Filter F = Previous.makeFilter();
+    while (F.hasNext()) {
+      NamedDecl *D = F.next();
+      if (!DC->InEnclosingNamespaceSetOf(
+              D->getDeclContext()->getRedeclContext()))
+        F.erase();
+    }
+    F.done();
+
+    if (Previous.empty()) {
+      D.setInvalidType();
+      Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
+      return 0;
+    }
+
+    // C++ [class.friend]p1: A friend of a class is a function or
+    //   class that is not a member of the class . . .
+    if (DC->Equals(CurContext))
+      Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+
+  //   - There's a scope specifier that does not match any template
+  //     parameter lists, in which case we use some arbitrary context,
+  //     create a method or method template, and wait for instantiation.
+  //   - There's a scope specifier that does match some template
+  //     parameter lists, which we don't handle right now.
+  } else {
+    DC = CurContext;
+    assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
   }
 
   if (DC->isFileContext()) {
@@ -6454,6 +6466,9 @@
   FrD->setAccess(AS_public);
   CurContext->addDecl(FrD);
 
+  if (ND->isInvalidDecl())
+    FrD->setInvalidDecl();
+
   return ND;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=116364&r1=116363&r2=116364&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct 12 18:13:28 2010
@@ -1374,8 +1374,13 @@
   // If there were at least as many template-ids as there were template
   // parameter lists, then there are no template parameter lists remaining for
   // the declaration itself.
-  if (Idx >= NumParamLists)
+  if (Idx >= NumParamLists) {
+    // Silently drop template member friend declarations.
+    // TODO: implement these
+    if (IsFriend && NumParamLists) Invalid = true;
+
     return 0;
+  }
 
   // If there were too many template parameter lists, complain about that now.
   if (Idx != NumParamLists - 1) {
@@ -1404,6 +1409,11 @@
     }
   }
 
+  // Silently drop template member template friend declarations.
+  // TODO: implement these
+  if (IsFriend && NumParamLists > 1)
+    Invalid = true;
+
   // Return the last template parameter list, which corresponds to the
   // entity being declared.
   return ParamLists[NumParamLists - 1];

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp?rev=116364&r1=116363&r2=116364&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p5.cpp Tue Oct 12 18:13:28 2010
@@ -1,13 +1,58 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-template <class T> class A {
-  class Member {
+namespace test0 {
+  template <class T> class A {
+    class Member {};
   };
-};
 
-class B {
-  template <class T> friend class A<T>::Member;
-};
+  class B {
+    template <class T> friend class A<T>::Member;
+  };
+
+  A<int> a;
+  B b;
+}
+
+// rdar://problem/8204127
+namespace test1 {
+  template <class T> struct A;
+
+  class C {
+    static void foo();
+    template <class T> friend void A<T>::f();
+  };
 
-A<int> a;
-B b;
+  template <class T> struct A {
+    void f() { C::foo(); }
+  };
+
+  template <class T> struct A<T*> {
+    void f() { C::foo(); }
+  };
+
+  template <> struct A<char> {
+    void f() { C::foo(); }
+  };
+}
+
+// FIXME: these should fail!
+namespace test2 {
+  template <class T> struct A;
+
+  class C {
+    static void foo();
+    template <class T> friend void A<T>::g();
+  };
+
+  template <class T> struct A {
+    void f() { C::foo(); }
+  };
+
+  template <class T> struct A<T*> {
+    void f() { C::foo(); }
+  };
+
+  template <> struct A<char> {
+    void f() { C::foo(); }
+  };
+}





More information about the cfe-commits mailing list