diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e173cffdfd2b..2d5a502bfeab 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -230,7 +230,7 @@ def ext_ellipsis_exception_spec : Extension< def err_expected_catch : Error<"expected catch">; def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; def err_using_namespace_in_class : Error< - "'using namespace' in class not allowed">; + "'using namespace' is not allowed in classes">; def err_ident_in_pseudo_dtor_not_a_type : Error< "identifier %0 in pseudo-destructor expression does not name a type">; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index f6ae4e147f79..eb7c3fa80e28 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -169,6 +169,7 @@ namespace { DeclContext *Common = UD->getNominatedNamespace(); while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); + Common = Common->getPrimaryContext(); list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } @@ -187,7 +188,7 @@ namespace { std::pair getNamespacesFor(DeclContext *DC) const { - return std::equal_range(begin(), end(), DC, + return std::equal_range(begin(), end(), DC->getPrimaryContext(), UnqualUsingEntry::Comparator()); } }; diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp new file mode 100644 index 000000000000..5b8aadf3913d --- /dev/null +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp @@ -0,0 +1,128 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// (this actually occurs before paragraph 1) +namespace test0 { + namespace A {} + class B { + using namespace A; // expected-error {{'using namespace' is not allowed in classes}} + }; +} + + +struct opaque0 {}; +struct opaque1 {}; + +// Test that names appear as if in deepest common ancestor. +namespace test1 { + namespace A { + namespace B { + opaque0 foo(); // expected-note {{candidate}} + } + } + + namespace C { + opaque1 foo(); // expected-note {{candidate}} + + opaque1 test() { + using namespace A::B; + return foo(); // C::foo + } + } + + opaque1 test() { + using namespace A::B; + using namespace C; + return foo(); // expected-error {{call to 'foo' is ambiguous}} + } +} + +// Same thing, but with the directives in namespaces. +namespace test2 { + namespace A { + namespace B { + opaque0 foo(); // expected-note {{candidate}} + } + } + + namespace C { + opaque1 foo(); // expected-note {{candidate}} + + namespace test { + using namespace A::B; + + opaque1 test() { + return foo(); // C::foo + } + } + } + + namespace test { + using namespace A::B; + using namespace C; + + opaque1 test() { + return foo(); // expected-error {{call to 'foo' is ambiguous}} + } + } +} + +// Transitivity. +namespace test3 { + namespace A { + namespace B { + opaque0 foo(); + } + } + namespace C { + using namespace A; + } + + opaque0 test0() { + using namespace C; + using namespace B; + return foo(); + } + + namespace D { + using namespace C; + } + namespace A { + opaque1 foo(); + } + + opaque1 test1() { + using namespace D; + return foo(); + } +} + +// Transitivity acts like synthetic using directives. +namespace test4 { + namespace A { + namespace B { + opaque0 foo(); // expected-note {{candidate}} + } + } + + namespace C { + using namespace A::B; + } + + opaque1 foo(); // expected-note {{candidate}} + + namespace A { + namespace D { + using namespace C; + } + + opaque0 test() { + using namespace D; + return foo(); + } + } + + opaque0 test() { + using namespace A::D; + return foo(); // expected-error {{call to 'foo' is ambiguous}} + } +}