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(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(cast(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(T)->getDecl(); @@ -2704,7 +2712,7 @@ if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); - // Add the associated namespace for this class. + // Add the associated namespace for this enumeration. CollectEnclosingNamespace(Result.Namespaces, Ctx); break; 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