Make a somewhat more convincing test case for unqualified lookup through

using directives, and fix a bug thereby exposed:  since we're playing
tricks with pointers, we need to make certain we're always using the same 
pointers for things.
Also tweak an existing error message.

llvm-svn: 86679
This commit is contained in:
John McCall 2009-11-10 09:20:04 +00:00
parent dca0c28452
commit 9757d0363d
3 changed files with 131 additions and 2 deletions

View File

@ -230,7 +230,7 @@ def ext_ellipsis_exception_spec : Extension<
def err_expected_catch : Error<"expected catch">; def err_expected_catch : Error<"expected catch">;
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
def err_using_namespace_in_class : Error< 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< def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">; "identifier %0 in pseudo-destructor expression does not name a type">;

View File

@ -169,6 +169,7 @@ namespace {
DeclContext *Common = UD->getNominatedNamespace(); DeclContext *Common = UD->getNominatedNamespace();
while (!Common->Encloses(EffectiveDC)) while (!Common->Encloses(EffectiveDC))
Common = Common->getParent(); Common = Common->getParent();
Common = Common->getPrimaryContext();
list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common));
} }
@ -187,7 +188,7 @@ namespace {
std::pair<const_iterator,const_iterator> std::pair<const_iterator,const_iterator>
getNamespacesFor(DeclContext *DC) const { getNamespacesFor(DeclContext *DC) const {
return std::equal_range(begin(), end(), DC, return std::equal_range(begin(), end(), DC->getPrimaryContext(),
UnqualUsingEntry::Comparator()); UnqualUsingEntry::Comparator());
} }
}; };

View File

@ -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}}
}
}