]> granicus.if.org Git - clang/commitdiff
Unrevert r186040, reverted in r186185, with fix for PR16597.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 12 Jul 2013 20:38:49 +0000 (20:38 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 12 Jul 2013 20:38:49 +0000 (20:38 +0000)
Original commit log:
  If we friend a declaration twice, that should not make it visible to
  name lookup in the surrounding context. Slightly rework how we handle
  friend declarations to inherit the visibility of the prior
  declaration, rather than setting a friend declaration to be visible
  whenever there was a prior declaration.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186199 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/DeclBase.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.decls/temp.friend/p4.cpp
test/SemaCXX/friend.cpp

index e90f454db3016bf806eb4cab84ededab3fd58586..2b2bf1a1efc13411eb193ae44b81d40006cec689 100644 (file)
@@ -3402,6 +3402,12 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
   First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
   assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) ||
          cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid());
+
+  // If the declaration was previously visible, a redeclaration of it remains
+  // visible even if it wouldn't be visible by itself.
+  static_cast<decl_type*>(this)->IdentifierNamespace |=
+    First->getIdentifierNamespace() &
+    (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
 }
 
 // Inline function definitions.
index 4f289d315adb9f12064cfca21e944a03dd28b314..157506d2a607e3b6683ebe928e2f760fff4919f8 100644 (file)
@@ -295,6 +295,8 @@ protected:
   friend class ASTReader;
   friend class LinkageComputer;
 
+  template<typename decl_type> friend class Redeclarable;
+
 private:
   void CheckAccessDeclContext() const;
 
@@ -824,7 +826,7 @@ public:
   /// class, but in the semantic context of the actual entity.  This property
   /// applies only to a specific decl object;  other redeclarations of the
   /// same entity may not (and probably don't) share this property.
-  void setObjectOfFriendDecl(bool PreviouslyDeclared) {
+  void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
     unsigned OldNS = IdentifierNamespace;
     assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
                      IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
@@ -833,15 +835,20 @@ public:
                        IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
            "namespace includes other than ordinary or tag");
 
+    Decl *Prev = getPreviousDecl();
     IdentifierNamespace = 0;
     if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
       IdentifierNamespace |= IDNS_TagFriend;
-      if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
+      if (PerformFriendInjection || 
+          (Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
+        IdentifierNamespace |= IDNS_Tag | IDNS_Type;
     }
 
     if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
       IdentifierNamespace |= IDNS_OrdinaryFriend;
-      if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+      if (PerformFriendInjection ||
+          (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
+        IdentifierNamespace |= IDNS_Ordinary;
     }
   }
 
index 5e535da19a1464e01a4f68ee42bd4bad90a62983..fd4ddcf55e657ec10d822f9a9b2144f6575ee429 100644 (file)
@@ -6328,12 +6328,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     }
 
     if (isFriend) {
-      // For now, claim that the objects have no previous declaration.
       if (FunctionTemplate) {
-        FunctionTemplate->setObjectOfFriendDecl(false);
+        FunctionTemplate->setObjectOfFriendDecl();
         FunctionTemplate->setAccess(AS_public);
       }
-      NewFD->setObjectOfFriendDecl(false);
+      NewFD->setObjectOfFriendDecl();
       NewFD->setAccess(AS_public);
     }
 
@@ -6652,8 +6651,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
 
       NewFD->setAccess(Access);
       if (FunctionTemplate) FunctionTemplate->setAccess(Access);
-
-      PrincipalDecl->setObjectOfFriendDecl(true);
     }
 
     if (NewFD->isOverloadedOperator() && !DC->isRecord() &&
@@ -10384,9 +10381,8 @@ CreateNewDecl:
   // declaration so we always pass true to setObjectOfFriendDecl to make
   // the tag name visible.
   if (TUK == TUK_Friend)
-    New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
-                               (!FriendSawTagOutsideEnclosingNamespace &&
-                                getLangOpts().MicrosoftExt));
+    New->setObjectOfFriendDecl(!FriendSawTagOutsideEnclosingNamespace &&
+                               getLangOpts().MicrosoftExt);
 
   // Set the access specifier.
   if (!Invalid && SearchDC->isRecord())
index 8d954ca994cd918d886ac2648a6aa16c6a57c69c..be336277b4a5538827c507c798c7947fc48eb317 100644 (file)
@@ -2757,8 +2757,15 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
       // If the only declaration here is an ordinary friend, consider
       // it only if it was declared in an associated classes.
       if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
-        DeclContext *LexDC = D->getLexicalDeclContext();
-        if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+        bool DeclaredInAssociatedClass = false;
+        for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) {
+          DeclContext *LexDC = DI->getLexicalDeclContext();
+          if (AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) {
+            DeclaredInAssociatedClass = true;
+            break;
+          }
+        }
+        if (!DeclaredInAssociatedClass)
           continue;
       }
 
index e6006b6bf973d87ba1214d739b154fede2bdfcf3..6f1ab19f10e061d2a61cf36973cad960b2c2d4a2 100644 (file)
@@ -1120,8 +1120,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
       NewClass->setAccess(PrevClassTemplate->getAccess());
     }
 
-    NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
-                                       PrevClassTemplate != NULL);
+    NewTemplate->setObjectOfFriendDecl();
 
     // Friend templates are visible in fairly strange ways.
     if (!CurContext->isDependentContext()) {
index b5a80d3f6a064d821b59ff0d9283330adb2abe84..14185c37ad177074ba3049564e51333c9055599f 100644 (file)
@@ -960,7 +960,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
     else
       Inst->setAccess(D->getAccess());
 
-    Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
+    Inst->setObjectOfFriendDecl();
     // TODO: do we want to track the instantiation progeny of this
     // friend target decl?
   } else {
@@ -1110,8 +1110,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
 
   // If the original function was part of a friend declaration,
   // inherit its namespace state.
-  if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
-    Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+  if (D->getFriendObjectKind())
+    Record->setObjectOfFriendDecl();
 
   // Make sure that anonymous structs and unions are recorded.
   if (D->isAnonymousStructOrUnion()) {
@@ -1315,7 +1315,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
     assert(isFriend && "non-friend has dependent specialization info?");
 
     // This needs to be set now for future sanity.
-    Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+    Function->setObjectOfFriendDecl();
 
     // Instantiate the explicit template arguments.
     TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
@@ -1365,13 +1365,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-    NamedDecl *PrevDecl;
-    if (TemplateParams)
-      PrevDecl = FunctionTemplate->getPreviousDecl();
-    else
-      PrevDecl = Function->getPreviousDecl();
-
-    PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
+    PrincipalDecl->setObjectOfFriendDecl();
     DC->makeDeclVisibleInContext(PrincipalDecl);
 
     bool queuedInstantiation = false;
@@ -1639,7 +1633,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
                                                     TemplateParams, Method);
     if (isFriend) {
       FunctionTemplate->setLexicalDeclContext(Owner);
-      FunctionTemplate->setObjectOfFriendDecl(true);
+      FunctionTemplate->setObjectOfFriendDecl();
     } else if (D->isOutOfLine())
       FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
     Method->setDescribedFunctionTemplate(FunctionTemplate);
@@ -1666,7 +1660,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
                                             TempParamLists.data());
 
     Method->setLexicalDeclContext(Owner);
-    Method->setObjectOfFriendDecl(true);
+    Method->setObjectOfFriendDecl();
   } else if (D->isOutOfLine())
     Method->setLexicalDeclContext(D->getLexicalDeclContext());
 
index e036cef32b283e5a712ea3d374ecf9148077f2a2..8571a141201bdb2d4b13c1ddc33db4033f4d8bc4 100644 (file)
@@ -26,3 +26,20 @@ void g() {
   X2<float> xf; 
   f(xf);
 }
+
+template<typename T>
+struct X3 {
+  operator int();
+
+  friend void h(int x);
+};
+
+int array2[sizeof(X3<int>)]; 
+int array3[sizeof(X3<float>)];
+
+void i() {
+  X3<int> xi;
+  h(xi);
+  X3<float> xf; 
+  h(xf);
+}
index ce2f34ff6b983f481c8c76b1d124d1d54e11d2c2..4d7ead2a5733135f73404ccca94f5fc56dc72753 100644 (file)
@@ -163,3 +163,27 @@ namespace test9 {
     friend void C::f(int, int, int) {}  // expected-error {{no function named 'f' with type 'void (int, int, int)' was found in the specified scope}}
   };
 }
+
+namespace test10 {
+  struct A {
+    friend void f10();
+  };
+  struct B {
+    friend void f10();
+  };
+  void g() {
+    f10(); // expected-error {{undeclared identifier}}
+  }
+}
+
+namespace PR16597 {
+  struct A {
+    friend void f_16597();
+  };
+  struct B {
+    friend void f_16597();
+  };
+  struct C {
+  };
+  void g(C a) { f_16597(a); } // expected-error {{undeclared identifier}}
+}