This revision was automatically updated to reflect the committed changes.
Closed by commit rC358882: [Sema] ADL: Associated namespaces for class types
and enumeration types (CWG… (authored by brunoricci, committed by ).
Changed prior to commit:
https://reviews.llvm.org/D60573?vs=194765&id=196058#toc
Repository:
rC Clang
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D60573/new/
https://reviews.llvm.org/D60573
Files:
lib/Sema/SemaLookup.cpp
test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
test/CXX/drs/dr16xx.cpp
Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
===================================================================
--- test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
+++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
@@ -38,12 +38,11 @@
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@-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 @@
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 @@
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 @@
f(e); // ok
N::S::F f;
g(f); // ok
+ N::G g;
+ h(g); // ok
+
}
}
Index: test/CXX/drs/dr16xx.cpp
===================================================================
--- test/CXX/drs/dr16xx.cpp
+++ test/CXX/drs/dr16xx.cpp
@@ -284,6 +284,54 @@
#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
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -2471,30 +2471,38 @@
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 @@
}
}
-// 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 @@
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 @@
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 @@
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 @@
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;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits