aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--lib/Sema/SemaLookup.cpp3
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp128
3 files changed, 131 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e173cffdfd..2d5a502bfe 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f6ae4e147f..eb7c3fa80e 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/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<const_iterator,const_iterator>
getNamespacesFor(DeclContext *DC) const {
- return std::equal_range(begin(), end(), DC,
+ return std::equal_range(begin(), end(), DC->getPrimaryContext(),
UnqualUsingEntry::Comparator());
}
};
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p1.cpp
new file mode 100644
index 0000000000..5b8aadf391
--- /dev/null
+++ b/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}}
+ }
+}