]> granicus.if.org Git - clang/commitdiff
Reinstate r186040, with additional fixes and more test coverage (reverted in
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 17 Jul 2013 23:53:16 +0000 (23:53 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 17 Jul 2013 23:53:16 +0000 (23:53 +0000)
r186331).

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@186546 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 6dbdc1307be66fe7753aa9cd7281b82592954911..c0422e336af2d3cfab6d6b75096a9a77c0e154e4 100644 (file)
@@ -3406,6 +3406,12 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
     assert(First->RedeclLink.NextIsLatest() && "Expected first");
     decl_type *MostRecent = First->RedeclLink.getNext();
     RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
+
+    // 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 |=
+      PrevDecl->getIdentifierNamespace() &
+      (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
   } else {
     // Make this first.
     First = static_cast<decl_type*>(this);
index b46fdf319fc78de7fed0b2edaa927b17c566453e..c19d3cf841834a9b751b42e7af7127d684f36b9e 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 b860823ff62434eb8a646ae966a259ed51e92c61..2291fc208fb91f573aefbad30c1ccffd4baeff36 100644 (file)
@@ -6330,12 +6330,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);
     }
 
@@ -6654,8 +6653,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() &&
@@ -10392,9 +10389,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 8dedee8926288ea8ce8f487ea6280f4b0f82982d..e10a96a5cbdeaf04abd7b14d7de4b257de83c406 100644 (file)
@@ -2757,8 +2757,16 @@ 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 (isa<CXXRecordDecl>(LexDC) &&
+              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 37591a373434e4880b7bb199bd6527d4b21d1d1f..420ccb167fbcfabc1b6580cb470e1d4435700aaf 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 86fb2a78bc19c5577899417011a3462c2bcf3252..aed2ab2c7d0c0e34eb70db544b332ad07ba7af04 100644 (file)
@@ -165,14 +165,126 @@ namespace test9 {
 }
 
 namespace test10 {
+  struct X {};
+  extern void f10_a();
+  extern void f10_a(X);
   struct A {
-    friend void f();
+    friend void f10_a();
+    friend void f10_b();
+    friend void f10_c();
+    friend void f10_d();
+    friend void f10_a(X);
+    friend void f10_b(X);
+    friend void f10_c(X);
+    friend void f10_d(X);
   };
-  extern void f();
+  extern void f10_b();
+  extern void f10_b(X);
   struct B {
-    friend void f();
+    friend void f10_a();
+    friend void f10_b();
+    friend void f10_c();
+    friend void f10_d();
+    friend void f10_a(X);
+    friend void f10_b(X);
+    friend void f10_c(X);
+    friend void f10_d(X);
   };
-  void g() {
-    ::test10::f();
+  extern void f10_c();
+  extern void f10_c(X);
+
+  // FIXME: Give a better diagnostic for the case where a function exists but is
+  // not visible.
+  void g(X x) {
+    f10_a();
+    f10_b();
+    f10_c();
+    f10_d(); // expected-error {{undeclared identifier}}
+
+    ::test10::f10_a();
+    ::test10::f10_b();
+    ::test10::f10_c();
+    ::test10::f10_d(); // expected-error {{no member named 'f10_d'}}
+
+    f10_a(x);
+    f10_b(x);
+    f10_c(x);
+    f10_d(x); // PR16597: expected-error {{undeclared identifier}}
+
+    ::test10::f10_a(x);
+    ::test10::f10_b(x);
+    ::test10::f10_c(x);
+    ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}}
+  }
+
+  struct Y : X {
+    friend void f10_d();
+    friend void f10_d(X);
+  };
+
+  struct Z {
+    operator X();
+    friend void f10_d();
+    friend void f10_d(X);
+  };
+
+  void g(X x, Y y, Z z) {
+    f10_d(); // expected-error {{undeclared identifier}}
+    ::test10::f10_d(); // expected-error {{no member named 'f10_d'}}
+
+    // f10_d is visible to ADL in the second and third cases.
+    f10_d(x); // expected-error {{undeclared identifier}}
+    f10_d(y);
+    f10_d(z);
+
+    // No ADL here.
+    ::test10::f10_d(x); // expected-error {{no type named 'f10_d'}}
+    ::test10::f10_d(y); // expected-error {{no type named 'f10_d'}}
+    ::test10::f10_d(z); // expected-error {{no type named 'f10_d'}}
+  }
+
+  void local_externs(X x, Y y) {
+    extern void f10_d();
+    extern void f10_d(X);
+    f10_d();
+    f10_d(x);
+    // FIXME: This lookup should fail, because the local extern declaration
+    // should suppress ADL.
+    f10_d(y);
+    {
+      int f10_d;
+      f10_d(); // expected-error {{not a function}}
+      f10_d(x); // expected-error {{not a function}}
+      f10_d(y); // expected-error {{not a function}}
+    }
+  }
+
+  void i(X x, Y y) {
+    f10_d(); // expected-error {{undeclared identifier}}
+    f10_d(x); // expected-error {{undeclared identifier}}
+    f10_d(y);
+  }
+
+  struct C {
+    friend void f10_d();
+    friend void f10_d(X);
+  };
+
+  void j(X x, Y y) {
+    f10_d(); // expected-error {{undeclared identifier}}
+    f10_d(x); // expected-error {{undeclared identifier}}
+    f10_d(y);
+  }
+
+  extern void f10_d();
+  extern void f10_d(X);
+  void k(X x, Y y, Z z) {
+    // All OK now.
+    f10_d();
+    f10_d(x);
+    ::test10::f10_d();
+    ::test10::f10_d(x);
+    ::test10::f10_d(y);
+    ::test10::f10_d(z);
   }
 }