]> granicus.if.org Git - clang/commitdiff
Improve argument-dependent lookup to find associated classes and
authorDouglas Gregor <dgregor@apple.com>
Wed, 8 Jul 2009 07:51:57 +0000 (07:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 8 Jul 2009 07:51:57 +0000 (07:51 +0000)
namespaces based on the template arguments of a class template
specialization type.

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

lib/Sema/SemaLookup.cpp
test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp [new file with mode: 0644]
test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp [moved from test/SemaCXX/basic_lookup_argdep.cpp with 100% similarity]
www/cxx_status.html

index 6f2fc5e0c434b15dd4d1689566f850d4e38ce0e0..343cbae673a036df9f2543f6fe9ca8a2ebb2ae77 100644 (file)
@@ -1241,6 +1241,74 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
   return true;
 }
 
+static void 
+addAssociatedClassesAndNamespaces(QualType T, 
+                                  ASTContext &Context,
+                          Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+                                  Sema::AssociatedClassSet &AssociatedClasses,
+                                  bool &GlobalScope);
+
+// \brief Add the associated classes and namespaces for argument-dependent 
+// lookup that involves a template argument (C++ [basic.lookup.koenig]p2).
+static void 
+addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, 
+                                  ASTContext &Context,
+                           Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+                                  Sema::AssociatedClassSet &AssociatedClasses,
+                                  bool &GlobalScope) {
+  // C++ [basic.lookup.koenig]p2, last bullet:
+  //   -- [...] ;  
+  switch (Arg.getKind()) {
+    case TemplateArgument::Null:
+      break;
+    
+    case TemplateArgument::Type:
+      // [...] the namespaces and classes associated with the types of the
+      // template arguments provided for template type parameters (excluding
+      // template template parameters)
+      addAssociatedClassesAndNamespaces(Arg.getAsType(), Context,
+                                        AssociatedNamespaces,
+                                        AssociatedClasses,
+                                        GlobalScope);
+      break;
+      
+    case TemplateArgument::Declaration:
+      // [...] the namespaces in which any template template arguments are 
+      // defined; and the classes in which any member templates used as 
+      // template template arguments are defined.
+      if (ClassTemplateDecl *ClassTemplate 
+            = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) {
+        DeclContext *Ctx = ClassTemplate->getDeclContext();
+        if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+          AssociatedClasses.insert(EnclosingClass);
+        // Add the associated namespace for this class.
+        while (Ctx->isRecord())
+          Ctx = Ctx->getParent();
+        if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+          AssociatedNamespaces.insert(EnclosingNamespace);
+        else if (Ctx->isTranslationUnit())
+          GlobalScope = true;
+      }
+      break;
+      
+    case TemplateArgument::Integral:
+    case TemplateArgument::Expression:
+      // [Note: non-type template arguments do not contribute to the set of 
+      //  associated namespaces. ]
+      break;
+      
+    case TemplateArgument::Pack:
+      for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
+                                        PEnd = Arg.pack_end();
+           P != PEnd; ++P)
+        addAssociatedClassesAndNamespaces(*P, Context,
+                                          AssociatedNamespaces,
+                                          AssociatedClasses,
+                                          GlobalScope);
+      break;
+  }
+}
+
 // \brief Add the associated classes and namespaces for
 // argument-dependent lookup with an argument of class type 
 // (C++ [basic.lookup.koenig]p2). 
@@ -1275,8 +1343,36 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
   if (!AssociatedClasses.insert(Class))
     return;
 
-  // FIXME: Handle class template specializations
-
+  // -- If T is a template-id, its associated namespaces and classes are 
+  //    the namespace in which the template is defined; for member 
+  //    templates, the member template’s class; the namespaces and classes
+  //    associated with the types of the template arguments provided for 
+  //    template type parameters (excluding template template parameters); the
+  //    namespaces in which any template template arguments are defined; and 
+  //    the classes in which any member templates used as template template 
+  //    arguments are defined. [Note: non-type template arguments do not 
+  //    contribute to the set of associated namespaces. ]
+  if (ClassTemplateSpecializationDecl *Spec 
+        = dyn_cast<ClassTemplateSpecializationDecl>(Class)) {
+    DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext();
+    if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+      AssociatedClasses.insert(EnclosingClass);
+    // Add the associated namespace for this class.
+    while (Ctx->isRecord())
+      Ctx = Ctx->getParent();
+    if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+      AssociatedNamespaces.insert(EnclosingNamespace);
+    else if (Ctx->isTranslationUnit())
+      GlobalScope = true;
+    
+    const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+    for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+      addAssociatedClassesAndNamespaces(TemplateArgs[I], Context,
+                                        AssociatedNamespaces,
+                                        AssociatedClasses,
+                                        GlobalScope);
+  }
+  
   // Add direct and indirect base classes along with their associated
   // namespaces.
   llvm::SmallVector<CXXRecordDecl *, 32> Bases;
@@ -1297,7 +1393,8 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
         DeclContext *BaseCtx = BaseDecl->getDeclContext();
         while (BaseCtx->isRecord())
           BaseCtx = BaseCtx->getParent();
-        if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
+        if (NamespaceDecl *EnclosingNamespace 
+              = dyn_cast<NamespaceDecl>(BaseCtx))
           AssociatedNamespaces.insert(EnclosingNamespace);
         else if (BaseCtx->isTranslationUnit())
           GlobalScope = true;
@@ -1490,6 +1587,8 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
     if (!DRE)
       continue;
 
+    // FIXME: The declaration might be a FunctionTemplateDecl (by itself)
+    // or might be buried in a TemplateIdRefExpr.
     OverloadedFunctionDecl *Ovl 
       = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
     if (!Ovl)
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
new file mode 100644 (file)
index 0000000..525afd8
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N1 {
+  struct X { };
+  int& f(void*);
+}
+
+namespace N2 {
+  template<typename T> struct Y { };
+}
+
+namespace N3 {
+  void test() {
+    int &ir = f((N2::Y<N1::X>*)0);
+  }
+}
index 389427e0aae7bd11b8af8c1025c26ca9bb37d9aa..9156370286019201638fddb67f1617ba63fee02b 100644 (file)
@@ -353,7 +353,7 @@ welcome!</p>
   <td class="advanced" align="center"></td>
   <td class="advanced" align="center"></td>
   <td class="na">N/A</td>
-  <td>Missing support for templates, friend functions.</td>
+  <td>Missing support for friend functions.</td>
 </tr>
 <tr>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;3.4.3 [basic.lookup.qual]</td>