[cfe-commits] r100753 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclFriend.h include/clang/AST/DeclTemplate.h lib/AST/Decl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp

John McCall rjmccall at apple.com
Thu Apr 8 02:05:18 PDT 2010


Author: rjmccall
Date: Thu Apr  8 04:05:18 2010
New Revision: 100753

URL: http://llvm.org/viewvc/llvm-project?rev=100753&view=rev
Log:
Implement dependent friend function template specializations.


Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclFriend.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Apr  8 04:05:18 2010
@@ -31,7 +31,9 @@
 class TemplateArgumentList;
 class MemberSpecializationInfo;
 class FunctionTemplateSpecializationInfo;
+class DependentFunctionTemplateSpecializationInfo;
 class TypeLoc;
+class UnresolvedSetImpl;
 
 /// \brief A container of type source information.
 ///
@@ -1037,9 +1039,10 @@
   /// FunctionTemplateSpecializationInfo, which contains information about
   /// the template being specialized and the template arguments involved in
   /// that specialization.
-  llvm::PointerUnion3<FunctionTemplateDecl *, 
+  llvm::PointerUnion4<FunctionTemplateDecl *, 
                       MemberSpecializationInfo *,
-                      FunctionTemplateSpecializationInfo *>
+                      FunctionTemplateSpecializationInfo *,
+                      DependentFunctionTemplateSpecializationInfo *>
     TemplateOrSpecialization;
 
 protected:
@@ -1365,6 +1368,18 @@
                                          void *InsertPos,
                     TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
 
+  /// \brief Specifies that this function declaration is actually a
+  /// dependent function template specialization.
+  void setDependentTemplateSpecialization(ASTContext &Context,
+                             const UnresolvedSetImpl &Templates,
+                      const TemplateArgumentListInfo &TemplateArgs);
+
+  DependentFunctionTemplateSpecializationInfo *
+  getDependentSpecializationInfo() const {
+    return TemplateOrSpecialization.
+             dyn_cast<DependentFunctionTemplateSpecializationInfo*>();
+  }
+
   /// \brief Determine what kind of template instantiation this function
   /// represents.
   TemplateSpecializationKind getTemplateSpecializationKind() const;

Modified: cfe/trunk/include/clang/AST/DeclFriend.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclFriend.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclFriend.h (original)
+++ cfe/trunk/include/clang/AST/DeclFriend.h Thu Apr  8 04:05:18 2010
@@ -48,10 +48,6 @@
   // Location of the 'friend' specifier.
   SourceLocation FriendLoc;
 
-  // FIXME: Hack to keep track of whether this was a friend function
-  // template specialization.
-  bool WasSpecialization;
-
   friend class CXXRecordDecl::friend_iterator;
   friend class CXXRecordDecl;
 
@@ -60,8 +56,7 @@
     : Decl(Decl::Friend, DC, L),
       Friend(Friend),
       NextFriend(0),
-      FriendLoc(FriendL),
-      WasSpecialization(false) {
+      FriendLoc(FriendL) {
   }
 
 public:
@@ -88,9 +83,6 @@
     return FriendLoc;
   }
 
-  bool wasSpecialization() const { return WasSpecialization; }
-  void setSpecialization(bool WS) { WasSpecialization = WS; }
-
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classof(const FriendDecl *D) { return true; }

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Apr  8 04:05:18 2010
@@ -376,6 +376,81 @@
     PointOfInstantiation = POI;
   }
 };
+
+/// \brief Provides information about a dependent function-template
+/// specialization declaration.  Since explicit function template
+/// specialization and instantiation declarations can only appear in
+/// namespace scope, and you can only specialize a member of a
+/// fully-specialized class, the only way to get one of these is in
+/// a friend declaration like the following:
+///
+///   template <class T> void foo(T);
+///   template <class T> class A {
+///     friend void foo<>(T);
+///   };
+class DependentFunctionTemplateSpecializationInfo {
+  union {
+    // Force sizeof to be a multiple of sizeof(void*) so that the
+    // trailing data is aligned.
+    void *Aligner; 
+
+    struct {
+      /// The number of potential template candidates.
+      unsigned NumTemplates;
+
+      /// The number of template arguments.
+      unsigned NumArgs;      
+    } d;
+  };
+
+  /// The locations of the left and right angle brackets.
+  SourceRange AngleLocs;
+
+  FunctionTemplateDecl * const *getTemplates() const {
+    return reinterpret_cast<FunctionTemplateDecl*const*>(this+1);
+  }
+
+  const TemplateArgumentLoc *getTemplateArgs() const {
+    return reinterpret_cast<const TemplateArgumentLoc*>(
+             getTemplates()[getNumTemplates()]);
+  }
+
+public:
+  DependentFunctionTemplateSpecializationInfo(
+                                 const UnresolvedSetImpl &Templates,
+                                 const TemplateArgumentListInfo &TemplateArgs);
+
+  /// \brief Returns the number of function templates that this might
+  /// be a specialization of.
+  unsigned getNumTemplates() const {
+    return d.NumTemplates;
+  }
+
+  /// \brief Returns the i'th template candidate.
+  FunctionTemplateDecl *getTemplate(unsigned I) const {
+    assert(I < getNumTemplates() && "template index out of range");
+    return getTemplates()[I];
+  }
+
+  /// \brief Returns the number of explicit template arguments that were given.
+  unsigned getNumTemplateArgs() const {
+    return d.NumArgs;
+  }
+
+  /// \brief Returns the nth template argument.
+  const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
+    assert(I < getNumTemplateArgs() && "template arg index out of range");
+    return getTemplateArgs()[I];
+  }
+
+  SourceLocation getLAngleLoc() const {
+    return AngleLocs.getBegin();
+  }
+
+  SourceLocation getRAngleLoc() const {
+    return AngleLocs.getEnd();
+  }
+};
   
 /// Declaration of a template function.
 class FunctionTemplateDecl : public TemplateDecl {

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Apr  8 04:05:18 2010
@@ -1309,6 +1309,40 @@
   }
 }
 
+void
+FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context,
+                                    const UnresolvedSetImpl &Templates,
+                             const TemplateArgumentListInfo &TemplateArgs) {
+  assert(TemplateOrSpecialization.isNull());
+  size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo);
+  Size += Templates.size() * sizeof(FunctionTemplateDecl*);
+  Size += TemplateArgs.size();
+  void *Buffer = Context.Allocate(Size);
+  DependentFunctionTemplateSpecializationInfo *Info =
+    new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates,
+                                                             TemplateArgs);
+  TemplateOrSpecialization = Info;
+}
+
+DependentFunctionTemplateSpecializationInfo::
+DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
+                                      const TemplateArgumentListInfo &TArgs)
+  : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) {
+
+  d.NumTemplates = Ts.size();
+  d.NumArgs = TArgs.size();
+
+  FunctionTemplateDecl **TsArray =
+    const_cast<FunctionTemplateDecl**>(getTemplates());
+  for (unsigned I = 0, E = Ts.size(); I != E; ++I)
+    TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl());
+
+  TemplateArgumentLoc *ArgsArray =
+    const_cast<TemplateArgumentLoc*>(getTemplateArgs());
+  for (unsigned I = 0, E = TArgs.size(); I != E; ++I)
+    new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]);
+}
+
 TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
   // For a function template specialization, query the specialization
   // information object.

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Apr  8 04:05:18 2010
@@ -2839,6 +2839,10 @@
                                          SourceLocation PrevPointOfInstantiation,
                                          bool &SuppressNew);
     
+  bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+                    const TemplateArgumentListInfo &ExplicitTemplateArgs,
+                                                    LookupResult &Previous);
+                                                    
   bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
                         const TemplateArgumentListInfo *ExplicitTemplateArgs,
                                            LookupResult &Previous);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr  8 04:05:18 2010
@@ -2935,7 +2935,7 @@
       // This is a function template specialization.
       isFunctionTemplateSpecialization = true;
 
-      // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+      // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
       if (isFriend && isFunctionTemplateSpecialization) {
         // We want to remove the "template<>", found here.
         SourceRange RemoveRange = TemplateParams->getSourceRange();
@@ -3139,23 +3139,38 @@
       // "friend void foo<>(int);" is an implicit specialization decl.
       isFunctionTemplateSpecialization = true;
     }
+  } else if (isFriend && isFunctionTemplateSpecialization) {
+    // This combination is only possible in a recovery case;  the user
+    // wrote something like:
+    //   template <> friend void foo(int);
+    // which we're recovering from as if the user had written:
+    //   friend void foo<>(int);
+    // Go ahead and fake up a template id.
+    HasExplicitTemplateArgs = true;
+    TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
+    TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
   }
 
-  if (isFunctionTemplateSpecialization) {
-    if (isFriend && NewFD->getType()->isDependentType()) {
-      // FIXME: When we see a friend of a function template
-      // specialization with a dependent type, we can't match it now;
-      // for now, we just drop it, until we have a reasonable way to
-      // represent the parsed-but-not-matched friend function template
-      // specialization in the AST.
-      return 0;
-    } else if (CheckFunctionTemplateSpecialization(NewFD,
-                                   (HasExplicitTemplateArgs ? &TemplateArgs : 0),
-                                                 Previous))
+  // If it's a friend (and only if it's a friend), it's possible
+  // that either the specialized function type or the specialized
+  // template is dependent, and therefore matching will fail.  In
+  // this case, don't check the specialization yet.
+  if (isFunctionTemplateSpecialization && isFriend &&
+      (NewFD->getType()->isDependentType() || DC->isDependentContext())) {
+    assert(HasExplicitTemplateArgs &&
+           "friend function specialization without template args");
+    if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,
+                                                     Previous))
       NewFD->setInvalidDecl();
-  } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
-             CheckMemberSpecialization(NewFD, Previous))
-    NewFD->setInvalidDecl();
+  } else if (isFunctionTemplateSpecialization) {
+    if (CheckFunctionTemplateSpecialization(NewFD,
+                               (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+                                            Previous))
+      NewFD->setInvalidDecl();
+  } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
+    if (CheckMemberSpecialization(NewFD, Previous))
+      NewFD->setInvalidDecl();
+  }
     
   // Perform semantic checking on the function declaration.
   bool OverloadableAttrRequired = false; // FIXME: HACK!

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Apr  8 04:05:18 2010
@@ -5638,9 +5638,6 @@
   FrD->setAccess(AS_public);
   CurContext->addDecl(FrD);
 
-  if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
-    FrD->setSpecialization(true);
-
   return DeclPtrTy::make(ND);
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr  8 04:05:18 2010
@@ -4083,6 +4083,42 @@
   return false;
 }
 
+/// \brief Perform semantic analysis for the given dependent function
+/// template specialization.  The only possible way to get a dependent
+/// function template specialization is with a friend declaration,
+/// like so:
+///
+///   template <class T> void foo(T);
+///   template <class T> class A {
+///     friend void foo<>(T);
+///   };
+///
+/// There really isn't any useful analysis we can do here, so we
+/// just store the information.
+bool
+Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+                   const TemplateArgumentListInfo &ExplicitTemplateArgs,
+                                                   LookupResult &Previous) {
+  // Remove anything from Previous that isn't a function template in
+  // the correct context.
+  DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
+  LookupResult::Filter F = Previous.makeFilter();
+  while (F.hasNext()) {
+    NamedDecl *D = F.next()->getUnderlyingDecl();
+    if (!isa<FunctionTemplateDecl>(D) ||
+        !FDLookupContext->Equals(D->getDeclContext()->getLookupContext()))
+      F.erase();
+  }
+  F.done();
+
+  // Should this be diagnosed here?
+  if (Previous.empty()) return true;
+
+  FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
+                                         ExplicitTemplateArgs);
+  return false;
+}
+
 /// \brief Perform semantic analysis for the given function template 
 /// specialization.
 ///

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Apr  8 04:05:18 2010
@@ -497,18 +497,11 @@
   NamedDecl *ND = D->getFriendDecl();
   assert(ND && "friend decl must be a decl or a type!");
 
-  // FIXME: We have a problem here, because the nested call to Visit(ND)
-  // will inject the thing that the friend references into the current
-  // owner, which is wrong.
-  Decl *NewND;
-
-  // Hack to make this work almost well pending a rewrite.
-  if (D->wasSpecialization()) {
-    // Totally egregious hack to work around PR5866
-    return 0;
-  } else {
-    NewND = Visit(ND);
-  }
+  // All of the Visit implementations for the various potential friend
+  // declarations have to be carefully written to work for friend
+  // objects, with the most important detail being that the target
+  // decl should almost certainly not be placed in Owner.
+  Decl *NewND = Visit(ND);
   if (!NewND) return 0;
 
   FriendDecl *FD =
@@ -1024,11 +1017,47 @@
 
   bool Redeclaration = false;
   bool OverloadableAttrRequired = false;
+  bool isExplicitSpecialization = false;
     
   LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
                         Sema::LookupOrdinaryName, Sema::ForRedeclaration);
 
-  if (TemplateParams || !FunctionTemplate) {
+  if (DependentFunctionTemplateSpecializationInfo *Info
+        = D->getDependentSpecializationInfo()) {
+    assert(isFriend && "non-friend has dependent specialization info?");
+
+    // This needs to be set now for future sanity.
+    Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+
+    // Instantiate the explicit template arguments.
+    TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+                                          Info->getRAngleLoc());
+    for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) {
+      TemplateArgumentLoc Loc;
+      if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs))
+        return 0;
+
+      ExplicitArgs.addArgument(Loc);
+    }
+
+    // Map the candidate templates to their instantiations.
+    for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
+      Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
+                                                Info->getTemplate(I),
+                                                TemplateArgs);
+      if (!Temp) return 0;
+
+      Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+    }
+
+    if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+                                                    &ExplicitArgs,
+                                                    Previous))
+      Function->setInvalidDecl();
+                                          
+    isExplicitSpecialization = true;
+
+  } else if (TemplateParams || !FunctionTemplate) {
     // Look only into the namespace where the friend would be declared to 
     // find a previous declaration. This is the innermost enclosing namespace, 
     // as described in ActOnFriendFunctionDecl.
@@ -1043,7 +1072,7 @@
   }
   
   SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
-                                   false, Redeclaration,
+                                   isExplicitSpecialization, Redeclaration,
                                    /*FIXME:*/OverloadableAttrRequired);
 
   // If the original function was part of a friend declaration,

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Thu Apr  8 04:05:18 2010
@@ -216,3 +216,25 @@
 
   template class A<int>; // expected-note {{in instantiation}}
 }
+
+namespace test10 {
+  template <class T> class A;
+  template <class T> A<T> bar(const T*, const A<T>&);
+  template <class T> class A {
+  private:
+    void foo(); // expected-note {{declared private here}}
+    friend A bar<>(const T*, const A<T>&);
+  };
+
+  template <class T> A<T> bar(const T *l, const A<T> &r) {
+    A<T> l1;
+    l1.foo();
+
+    A<char> l2;
+    l2.foo(); // expected-error {{'foo' is a private member of 'test10::A<char>'}}
+
+    return l1;
+  }
+
+  template A<int> bar<int>(const int *, const A<int> &); // expected-note {{in instantiation}}
+}





More information about the cfe-commits mailing list