[cfe-commits] r78653 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def include/clang/Parse/Action.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp

John McCall rjmccall at apple.com
Mon Aug 10 23:59:38 PDT 2009


Author: rjmccall
Date: Tue Aug 11 01:59:38 2009
New Revision: 78653

URL: http://llvm.org/viewvc/llvm-project?rev=78653&view=rev
Log:
Argument-dependent lookup for friend declarations.  Add a new decl type,
FriendFunctionDecl, and create instances as appropriate.

The design of FriendFunctionDecl is still somewhat up in the air;  you can
befriend arbitrary types of functions --- methods, constructors, etc. ---
and it's not clear that this representation captures that very well.
We'll have a better picture when we start consuming this data in access
control.


Added:
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/DeclNodes.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Tue Aug 11 01:59:38 2009
@@ -827,6 +827,14 @@
   /// semantic context via makeDeclVisibleInContext.
   void addDecl(Decl *D);
 
+  /// @brief Add the declaration D to this context without modifying
+  /// any lookup tables.
+  ///
+  /// This is useful for some operations in dependent contexts where
+  /// the semantic context might not be dependent;  this basically
+  /// only happens with friends.
+  void addHiddenDecl(Decl *D);
+
   /// lookup_iterator - An iterator that provides access to the results
   /// of looking up a name within this context.
   typedef NamedDecl **lookup_iterator;

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 11 01:59:38 2009
@@ -1213,6 +1213,36 @@
   static bool classof(const CXXConversionDecl *D) { return true; }
 };
 
+/// FriendFunctionDecl - Represents the declaration (and possibly
+/// the definition) of a friend function.
+class FriendFunctionDecl : public FunctionDecl {
+  // Location of the 'friend' specifier.
+  const SourceLocation FriendLoc;
+
+  FriendFunctionDecl(DeclContext *DC, SourceLocation L,
+                     DeclarationName N, QualType T,
+                     bool isInline, SourceLocation FriendL)
+    : FunctionDecl(FriendFunction, DC, L, N, T, None, isInline),
+      FriendLoc(FriendL)
+  {}
+
+public:
+  static FriendFunctionDecl *Create(ASTContext &C, DeclContext *DC,
+                                    SourceLocation L, DeclarationName N,
+                                    QualType T, bool isInline,
+                                    SourceLocation FriendL);
+
+  SourceLocation getFriendLoc() const {
+    return FriendLoc;
+  }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { 
+    return D->getKind() == FriendFunction;
+  }
+  static bool classof(const FriendFunctionDecl *D) { return true; }
+};
+  
 /// LinkageSpecDecl - This represents a linkage specification.  For example:
 ///   extern "C" void foo();
 ///

Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Tue Aug 11 01:59:38 2009
@@ -92,6 +92,7 @@
   ABSTRACT_DECL(Value, NamedDecl)
     DECL(EnumConstant, ValueDecl)
     DECL(Function, ValueDecl)
+      DECL(FriendFunction, FunctionDecl)
       DECL(CXXMethod, FunctionDecl)
         DECL(CXXConstructor, CXXMethodDecl)
         DECL(CXXDestructor, CXXMethodDecl)

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Aug 11 01:59:38 2009
@@ -1143,7 +1143,8 @@
   /// ActOnFriendDecl - This action is called when a friend declaration is
   /// encountered.
   virtual DeclPtrTy ActOnFriendDecl(Scope *S,
-                        llvm::PointerUnion<const DeclSpec*,Declarator*> D) {
+                        llvm::PointerUnion<const DeclSpec*,Declarator*> D,
+                                    bool IsDefinition) {
     return DeclPtrTy();
   }
 

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Aug 11 01:59:38 2009
@@ -198,6 +198,9 @@
     case ObjCProperty:
     case ObjCCompatibleAlias:
       return IDNS_Ordinary;
+
+    case FriendFunction:
+      return IDNS_Friend;
       
     case ObjCProtocol:
       return IDNS_ObjCProtocol;
@@ -583,7 +586,7 @@
   return !FirstDecl;
 }
 
-void DeclContext::addDecl(Decl *D) {
+void DeclContext::addHiddenDecl(Decl *D) {
   assert(D->getLexicalDeclContext() == this &&
          "Decl inserted into wrong lexical context");
   assert(!D->getNextDeclInContext() && D != LastDecl && 
@@ -595,6 +598,10 @@
   } else {
     FirstDecl = LastDecl = D;
   }
+}
+
+void DeclContext::addDecl(Decl *D) {
+  addHiddenDecl(D);
 
   if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
     ND->getDeclContext()->makeDeclVisibleInContext(ND);
@@ -608,9 +615,12 @@
     for (decl_iterator D = DCtx->decls_begin(), 
                     DEnd = DCtx->decls_end(); 
          D != DEnd; ++D) {
-      // Insert this declaration into the lookup structure
+      // Insert this declaration into the lookup structure, but only
+      // if it's semantically in its decl context.  During non-lazy
+      // lookup building, this is implicitly enforced by addDecl.
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
-        makeDeclVisibleInContextImpl(ND);
+        if (D->getDeclContext() == DCtx)
+          makeDeclVisibleInContextImpl(ND);
 
       // If this declaration is itself a transparent declaration context,
       // add its members (recursively).

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -738,6 +738,15 @@
   return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
 }
 
+FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,DeclContext *DC,
+                                               SourceLocation L,
+                                               DeclarationName N, QualType T,
+                                               bool isInline,
+                                               SourceLocation FriendL) {
+  return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
+}
+                                               
+
 LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
                                          DeclContext *DC, 
                                          SourceLocation L,

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Aug 11 01:59:38 2009
@@ -29,7 +29,7 @@
 
   DeclPtrTy FnD;
   if (D.getDeclSpec().isFriendSpecified())
-    FnD = Actions.ActOnFriendDecl(CurScope, &D);
+    FnD = Actions.ActOnFriendDecl(CurScope, &D, /*IsDefinition*/ true);
   else
     FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -954,7 +954,7 @@
     ConsumeToken();
 
     if (DS.isFriendSpecified())
-      Actions.ActOnFriendDecl(CurScope, &DS);
+      Actions.ActOnFriendDecl(CurScope, &DS, /*IsDefinition*/ false);
     else
       Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
 
@@ -1060,7 +1060,8 @@
     DeclPtrTy ThisDecl;
     if (DS.isFriendSpecified()) {
       // TODO: handle initializers, bitfields, 'delete'
-      ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo);
+      ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo,
+                                         /*IsDefinition*/ false);
     } else
       ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
                                                   DeclaratorInfo,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Aug 11 01:59:38 2009
@@ -2036,7 +2036,8 @@
                                                  ExprArg AssertMessageExpr);
   
   virtual DeclPtrTy ActOnFriendDecl(Scope *S,
-                    llvm::PointerUnion<const DeclSpec*,Declarator*> D);
+                          llvm::PointerUnion<const DeclSpec*,Declarator*> D,
+                                    bool IsDefinition);
 
   QualType CheckConstructorDeclarator(Declarator &D, QualType R,
                                       FunctionDecl::StorageClass& SC);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 11 01:59:38 2009
@@ -2353,6 +2353,7 @@
   if (D.getDeclSpec().isThreadSpecified())
     Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
 
+  bool isFriend = D.getDeclSpec().isFriendSpecified();
   bool isInline = D.getDeclSpec().isInlineSpecified();
   bool isVirtual = D.getDeclSpec().isVirtualSpecified();
   bool isExplicit = D.getDeclSpec().isExplicitSpecified();
@@ -2382,7 +2383,20 @@
   
   bool isVirtualOkay = false;
   FunctionDecl *NewFD;
-  if (D.getKind() == Declarator::DK_Constructor) {
+  if (isFriend) {
+    // DC is the namespace in which the function is being declared.
+    assert(DC->isFileContext() || PrevDecl);
+
+    // C++ [class.friend]p5
+    //   A function can be defined in a friend declaration of a
+    //   class . . . . Such a function is implicitly inline.
+    isInline |= IsFunctionDefinition;
+
+    NewFD = FriendFunctionDecl::Create(Context, DC,
+                                       D.getIdentifierLoc(), Name, R,
+                                       isInline,
+                                       D.getDeclSpec().getFriendSpecLoc());
+  } else if (D.getKind() == Declarator::DK_Constructor) {
     // This is a C++ constructor declaration.
     assert(DC->isRecord() &&
            "Constructors can only be declared in a member context");
@@ -2643,7 +2657,7 @@
   if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
     // An out-of-line member function declaration must also be a
     // definition (C++ [dcl.meaning]p1).
-    if (!IsFunctionDefinition) {
+    if (!IsFunctionDefinition && !isFriend) {
       Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
         << D.getCXXScopeSpec().getRange();
       NewFD->setInvalidDecl();
@@ -4142,7 +4156,7 @@
     //   If a friend declaration in a non-local class first declares a
     //   class or function, the friend class or function is a member of
     //   the innermost enclosing namespace.
-    while (!SearchDC->isNamespace() && !SearchDC->isTranslationUnit())
+    while (!SearchDC->isFileContext())
       SearchDC = SearchDC->getParent();
 
     // The entity of a decl scope is a DeclContext; see PushDeclContext.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -3305,7 +3305,8 @@
 }
 
 Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
-                       llvm::PointerUnion<const DeclSpec*,Declarator*> DU) {
+                       llvm::PointerUnion<const DeclSpec*,Declarator*> DU,
+                                      bool IsDefinition) {
   Declarator *D = DU.dyn_cast<Declarator*>();
   const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
 
@@ -3483,10 +3484,18 @@
       Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
   }
 
+  bool Redeclaration = (FD != 0);
+
+  // If we found a match, create a friend function declaration with
+  // that function as the previous declaration.
+  if (Redeclaration) {
+    // Create it in the semantic context of the original declaration.
+    DC = FD->getDeclContext();
+
   // If we didn't find something matching the type exactly, create
   // a declaration.  This declaration should only be findable via
   // argument-dependent lookup.
-  if (!FD) {
+  } else {
     assert(DC->isFileContext());
 
     // This implies that it has to be an operator or function.
@@ -3498,23 +3507,25 @@
          D->getKind() == Declarator::DK_Destructor ? 1 : 2);
       return DeclPtrTy();
     }
-
-    bool Redeclaration = false;
-    NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
-                                            /* PrevDecl = */ NULL,
-                                            MultiTemplateParamsArg(*this),
-                                            /* isFunctionDef */ false,
-                                            Redeclaration);
-
-    FD = cast_or_null<FunctionDecl>(ND);
-
-    // Note that we're creating a declaration but *not* pushing
-    // it onto the scope chains.
-
-    // TODO: make accessible via argument-dependent lookup.
   }
 
-  // TODO: actually register the function as a friend.
+  NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
+                                          /* PrevDecl = */ FD,
+                                          MultiTemplateParamsArg(*this),
+                                          IsDefinition,
+                                          Redeclaration);
+  FD = cast_or_null<FriendFunctionDecl>(ND);
+
+  // If this is a dependent context, just add the decl to the
+  // class's decl list and don't both with the lookup tables.  This
+  // doesn't affect lookup because any call that might find this
+  // function via ADL necessarily has to involve dependently-typed
+  // arguments and hence can't be resolved until
+  // template-instantiation anyway.
+  if (CurContext->isDependentContext())
+    CurContext->addHiddenDecl(FD);
+  else
+    CurContext->addDecl(FD);
 
   return DeclPtrTy::make(FD);
 }

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=78653&r1=78652&r2=78653&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Aug 11 01:59:38 2009
@@ -1756,28 +1756,17 @@
     //        associated classes are visible within their respective
     //        namespaces even if they are not visible during an ordinary
     //        lookup (11.4).
-    //
-    // We implement the second clause in the loop below.
     DeclContext::lookup_iterator I, E;
-    for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I)
-      CollectFunctionDecl(Functions, *I);
-  }
-
-  // Look for friend function declarations in associated classes
-  // which name functions in associated namespaces.
-  for (AssociatedClassSet::iterator AC = AssociatedClasses.begin(),
-                                 ACEnd = AssociatedClasses.end();
-       AC != ACEnd; ++AC) {
-    DeclContext::lookup_iterator I, E;
-    for (llvm::tie(I, E) = (*AC)->lookup(Name); I != E; ++I) {
+    for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
       Decl *D = *I;
-      if (!D->isInIdentifierNamespace(Decl::IDNS_Friend))
-        continue;
-
-      DeclContext *DC = D->getDeclContext();
-      if (!AssociatedNamespaces.count(DC))
-        continue;
-
+      // Only count friend declarations which were declared in
+      // associated classes.
+      if (D->isInIdentifierNamespace(Decl::IDNS_Friend)) {
+        DeclContext *LexDC = D->getLexicalDeclContext();
+        if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+          continue;
+      }
+      
       CollectFunctionDecl(Functions, D);
     }
   }

Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp?rev=78653&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp Tue Aug 11 01:59:38 2009
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+  class A {
+    friend void func(A);
+    friend A operator+(A,A);
+  };
+}
+
+namespace B {
+  class B {
+    static void func(B);
+  };
+  B operator+(B,B);
+}
+
+namespace D {
+  class D {};
+}
+
+namespace C {
+  class C {};
+  void func(C);
+  C operator+(C,C);
+  D::D operator+(D::D,D::D);
+}
+
+namespace D {
+  using namespace C;
+}
+
+namespace Test {
+  void test() {
+    func(A::A());
+    func(B::B()); // expected-error {{ no matching function for call to 'func' }}
+    func(C::C());
+    A::A() + A::A();
+    B::B() + B::B();
+    C::C() + C::C();
+    D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }}
+  }
+}





More information about the cfe-commits mailing list