r358882 - [Sema] ADL: Associated namespaces for class types and enumeration types (CWG 1691)

Bruno Ricci via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 22 05:19:00 PDT 2019


Author: brunoricci
Date: Mon Apr 22 05:19:00 2019
New Revision: 358882

URL: http://llvm.org/viewvc/llvm-project?rev=358882&view=rev
Log:
[Sema] ADL: Associated namespaces for class types and enumeration types (CWG 1691)

CWG 1691 changed the definition of the namespaces associated with a class
type or enumeration type.

For a class type, the associated namespaces are the innermost enclosing
namespaces of the associated classes. For an enumeration type, the associated
namespace is the innermost enclosing namespace of its declaration.

This also fixes CWG 1690 and CWG 1692.

Differential Revision: https://reviews.llvm.org/D60573

Reviewed By: rjmccall, rsmith


Modified:
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
    cfe/trunk/test/CXX/drs/dr16xx.cpp

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=358882&r1=358881&r2=358882&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Apr 22 05:19:00 2019
@@ -2471,30 +2471,38 @@ namespace {
 static void
 addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T);
 
+// Given the declaration context \param Ctx of a class, class template or
+// enumeration, add the associated namespaces to \param Namespaces as described
+// in [basic.lookup.argdep]p2.
 static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces,
                                       DeclContext *Ctx) {
-  // Add the associated namespace for this class.
-
-  // We don't use DeclContext::getEnclosingNamespaceContext() as this may
-  // be a locally scoped record.
+  // The exact wording has been changed in C++14 as a result of
+  // CWG 1691 (see also CWG 1690 and CWG 1692). We apply it unconditionally
+  // to all language versions since it is possible to return a local type
+  // from a lambda in C++11.
+  //
+  // C++14 [basic.lookup.argdep]p2:
+  //   If T is a class type [...]. Its associated namespaces are the innermost
+  //   enclosing namespaces of its associated classes. [...]
+  //
+  //   If T is an enumeration type, its associated namespace is the innermost
+  //   enclosing namespace of its declaration. [...]
 
-  // We skip out of inline namespaces. The innermost non-inline namespace
+  // We additionally skip inline namespaces. The innermost non-inline namespace
   // contains all names of all its nested inline namespaces anyway, so we can
   // replace the entire inline namespace tree with its root.
-  while (Ctx->isRecord() || Ctx->isTransparentContext() ||
-         Ctx->isInlineNamespace())
+  while (!Ctx->isFileContext() || Ctx->isInlineNamespace())
     Ctx = Ctx->getParent();
 
-  if (Ctx->isFileContext())
-    Namespaces.insert(Ctx->getPrimaryContext());
+  Namespaces.insert(Ctx->getPrimaryContext());
 }
 
 // Add the associated classes and namespaces for argument-dependent
-// lookup that involves a template argument (C++ [basic.lookup.koenig]p2).
+// lookup that involves a template argument (C++ [basic.lookup.argdep]p2).
 static void
 addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
                                   const TemplateArgument &Arg) {
-  // C++ [basic.lookup.koenig]p2, last bullet:
+  // C++ [basic.lookup.argdep]p2, last bullet:
   //   -- [...] ;
   switch (Arg.getKind()) {
     case TemplateArgument::Null:
@@ -2539,9 +2547,8 @@ addAssociatedClassesAndNamespaces(Associ
   }
 }
 
-// Add the associated classes and namespaces for
-// argument-dependent lookup with an argument of class type
-// (C++ [basic.lookup.koenig]p2).
+// Add the associated classes and namespaces for argument-dependent lookup
+// with an argument of class type (C++ [basic.lookup.argdep]p2).
 static void
 addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
                                   CXXRecordDecl *Class) {
@@ -2550,18 +2557,19 @@ addAssociatedClassesAndNamespaces(Associ
   if (Class->getDeclName() == Result.S.VAListTagName)
     return;
 
-  // C++ [basic.lookup.koenig]p2:
+  // C++ [basic.lookup.argdep]p2:
   //   [...]
   //     -- If T is a class type (including unions), its associated
   //        classes are: the class itself; the class of which it is a
-  //        member, if any; and its direct and indirect base
-  //        classes. Its associated namespaces are the namespaces in
-  //        which its associated classes are defined.
+  //        member, if any; and its direct and indirect base classes.
+  //        Its associated namespaces are the innermost enclosing
+  //        namespaces of its associated classes.
 
   // Add the class of which it is a member, if any.
   DeclContext *Ctx = Class->getDeclContext();
   if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
     Result.Classes.insert(EnclosingClass);
+
   // Add the associated namespace for this class.
   CollectEnclosingNamespace(Result.Namespaces, Ctx);
 
@@ -2682,10 +2690,10 @@ addAssociatedClassesAndNamespaces(Associ
       break;
 
     //     -- If T is a class type (including unions), its associated
-    //        classes are: the class itself; the class of which it is a
-    //        member, if any; and its direct and indirect base
-    //        classes. Its associated namespaces are the namespaces in
-    //        which its associated classes are defined.
+    //        classes are: the class itself; the class of which it is
+    //        a member, if any; and its direct and indirect base classes.
+    //        Its associated namespaces are the innermost enclosing
+    //        namespaces of its associated classes.
     case Type::Record: {
       CXXRecordDecl *Class =
           cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
@@ -2693,10 +2701,10 @@ addAssociatedClassesAndNamespaces(Associ
       break;
     }
 
-    //     -- If T is an enumeration type, its associated namespace is
-    //        the namespace in which it is defined. If it is class
-    //        member, its associated class is the member's class; else
-    //        it has no associated class.
+    //     -- If T is an enumeration type, its associated namespace
+    //        is the innermost enclosing namespace of its declaration.
+    //        If it is a class member, its associated class is the
+    //        member’s class; else it has no associated class.
     case Type::Enum: {
       EnumDecl *Enum = cast<EnumType>(T)->getDecl();
 
@@ -2704,7 +2712,7 @@ addAssociatedClassesAndNamespaces(Associ
       if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
         Result.Classes.insert(EnclosingClass);
 
-      // Add the associated namespace for this class.
+      // Add the associated namespace for this enumeration.
       CollectEnclosingNamespace(Result.Namespaces, Ctx);
 
       break;

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp?rev=358882&r1=358881&r2=358882&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp Mon Apr 22 05:19:00 2019
@@ -38,12 +38,11 @@ namespace adl_class_type {
       return s;
     }
     using S = decltype(foo());
-    void f(S); // expected-note {{'X2::f' declared here}}
+    void f(S); // #1
   }
   void test2() {
-    f(X2::S{}); // FIXME: This is well-formed; X2 is the innermost enclosing namespace
-                // of the local struct S.
-                // expected-error at -2 {{use of undeclared identifier 'f'}}
+    f(X2::S{}); // This is well-formed; X2 is the innermost enclosing namespace
+                // of the local struct S. Calls #1.
   }
 
   // associated class: the parent class
@@ -83,7 +82,7 @@ namespace adl_class_type {
 
     void test5() {
       auto lambda = N::get_lambda();
-      f(lambda); // FIXME: This is well-formed. expected-error {{use of undeclared}}
+      f(lambda); // ok
     }
   }
 
@@ -193,6 +192,12 @@ namespace adl_enumeration_type {
       enum F : int;
       friend void g(F);
     };
+    auto foo() {
+      enum G {} g;
+      return g;
+    }
+    using G = decltype(foo());
+    void h(G);
   }
 
   void test() {
@@ -200,6 +205,9 @@ namespace adl_enumeration_type {
     f(e); // ok
     N::S::F f;
     g(f); // ok
+    N::G g;
+    h(g); // ok
+
   }
 }
 

Modified: cfe/trunk/test/CXX/drs/dr16xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr16xx.cpp?rev=358882&r1=358881&r2=358882&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr16xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr16xx.cpp Mon Apr 22 05:19:00 2019
@@ -284,6 +284,54 @@ namespace dr1687 { // dr1687: 7
 #endif
 }
 
+namespace dr1690 { // dr1690: 9
+  // See also the various tests in "CXX/basic/basic.lookup/basic.lookup.argdep".
+#if __cplusplus >= 201103L
+  namespace N {
+    static auto lambda = []() { struct S {} s; return s; };
+    void f(decltype(lambda()));
+  }
+
+  void test() {
+    auto s = N::lambda();
+    f(s); // ok
+  }
+#endif
+}
+
+namespace dr1691 { // dr1691: 9
+#if __cplusplus >= 201103L
+  namespace N {
+    namespace M {
+      enum E : int;
+      void f(E);
+    }
+    enum M::E : int {};
+    void g(M::E); // expected-note {{declared here}}
+  }
+  void test() {
+    N::M::E e;
+    f(e); // ok
+    g(e); // expected-error {{use of undeclared}}
+  }
+#endif
+}
+
+namespace dr1692 { // dr1692: 9
+  namespace N {
+    struct A {
+      struct B {
+        struct C {};
+      };
+    };
+    void f(A::B::C);
+  }
+  void test() {
+    N::A::B::C c;
+    f(c); // ok
+  }
+}
+
 namespace dr1696 { // dr1696: 7
   namespace std_examples {
 #if __cplusplus >= 201402L




More information about the cfe-commits mailing list