Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -504,6 +504,48 @@ // Don't do any extra resolution if we've already resolved as ambiguous. if (ResultKind == Ambiguous) return; + // C++ [basic.scope.hiding]p2: + // A class name or enumeration name can be hidden by the name of + // an object, function, or enumerator declared in the same + // scope. If a class or enumeration name and an object, function, + // or enumerator are declared in the same scope (in any order) + // with the same name, the class or enumeration name is hidden + // wherever the object, function, or enumerator name is visible. + if (HideTags) { + // First collect all decls that can hide others and those that can be hidden + llvm::BitVector CanHideOther(N), CanBeHidden(N); + for (unsigned I = 0; I < N; ++I) { + const NamedDecl *D = Decls[I]->getUnderlyingDecl(); + D = cast(D->getCanonicalDecl()); + if (isa(D)) + CanBeHidden.set(I); + else if (canHideTag(D)) + CanHideOther.set(I); + } + + if (!CanBeHidden.empty() && !CanHideOther.empty()) { + // Collect those decls that will be hidden + llvm::BitVector HiddenDecls(N); + for (unsigned HiddenI : CanBeHidden.set_bits()) { + for (unsigned HiderI : CanHideOther.set_bits()) { + if (getContextForScopeMatching(Decls[HiderI]) + ->Equals(getContextForScopeMatching(Decls[HiddenI]))) { + HiddenDecls.set(HiddenI); + break; + } + } + } + + // Erase hidden decls by replacing them with decls from the end (which + // means that we need to iterate from the end). N is adjusted so we don't + // see the extra copies at the end, and they're removed when we call + // truncate at the end. + for (int I = HiddenDecls.find_last(); I >= 0; + I = HiddenDecls.find_prev(I)) + Decls[I] = Decls[--N]; + } + } + llvm::SmallDenseMap Unique; llvm::SmallDenseMap UniqueTypes; @@ -514,8 +556,6 @@ llvm::SmallVector EquivalentNonFunctions; - unsigned UniqueTagIndex = 0; - unsigned I = 0; while (I < N) { const NamedDecl *D = Decls[I]->getUnderlyingDecl(); @@ -571,7 +611,6 @@ } else if (isa(D)) { if (HasTag) Ambiguous = true; - UniqueTagIndex = I; HasTag = true; } else if (isa(D)) { HasFunction = true; @@ -598,27 +637,6 @@ I++; } - // C++ [basic.scope.hiding]p2: - // A class name or enumeration name can be hidden by the name of - // an object, function, or enumerator declared in the same - // scope. If a class or enumeration name and an object, function, - // or enumerator are declared in the same scope (in any order) - // with the same name, the class or enumeration name is hidden - // wherever the object, function, or enumerator name is visible. - // But it's still an error if there are distinct tag types found, - // even if they're not visible. (ref?) - if (N > 1 && HideTags && HasTag && !Ambiguous && - (HasFunction || HasNonFunction || HasUnresolved)) { - const NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1]; - if (isa(Decls[UniqueTagIndex]->getUnderlyingDecl()) && - getContextForScopeMatching(Decls[UniqueTagIndex])->Equals( - getContextForScopeMatching(OtherDecl)) && - canHideTag(OtherDecl)) - Decls[UniqueTagIndex] = Decls[--N]; - else - Ambiguous = true; - } - // FIXME: This diagnostic should really be delayed until we're done with // the lookup result, in case the ambiguity is resolved by the caller. if (!EquivalentNonFunctions.empty() && !Ambiguous) @@ -627,7 +645,8 @@ Decls.truncate(N); - if (HasNonFunction && (HasFunction || HasUnresolved)) + if ((HasNonFunction && (HasFunction || HasUnresolved)) || + (HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved))) Ambiguous = true; if (Ambiguous) Index: clang/test/SemaCXX/using-hiding.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/using-hiding.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace A { + class X { }; // expected-note{{candidate found by name lookup is 'A::X'}} +} +namespace B { + void X(int); // expected-note{{candidate found by name lookup is 'B::X'}} +} + +// Using directive doesn't cause A::X to be hidden, so X is ambiguous. +namespace Test1 { + using namespace A; + using namespace B; + + void f() { + X(1); // expected-error{{reference to 'X' is ambiguous}} + } +} + +// The behaviour here should be the same as using namespaces A and B directly +namespace Test2 { + namespace C { + using A::X; // expected-note{{candidate found by name lookup is 'Test2::C::X'}} + } + namespace D { + using B::X; // expected-note{{candidate found by name lookup is 'Test2::D::X'}} + } + using namespace C; + using namespace D; + + void f() { + X(1); // expected-error{{reference to 'X' is ambiguous}} + } +} + +// Defining a function X inside C should hide using A::X in C but not D, so the result is ambiguous. +namespace Test3 { + namespace C { + using A::X; + void X(int); // expected-note{{candidate found by name lookup is 'Test3::C::X'}} + } + namespace D { + using A::X; // expected-note{{candidate found by name lookup is 'Test3::D::X'}} + } + using namespace C; + using namespace D; + void f() { + X(1); // expected-error{{reference to 'X' is ambiguous}} + } +} + +// A::X hidden in both C and D by overloaded function, so the result is not ambiguous. +namespace Test4 { + namespace C { + using A::X; + void X(int); + } + namespace D { + using A::X; + void X(int, int); + } + using namespace C; + using namespace D; + void f() { + X(1); + } +} + +// C and D declare a class X, but it's hidden so the result is not ambiguous. +namespace Test5 { + namespace C { + class X { }; + using B::X; + } + namespace D { + class X { }; + using B::X; + } + using namespace C; + using namespace D; + void f() { + X(1); + } +} + +// function X inside C should hide class X in C but not D. +namespace Test6 { + namespace C { + class X; + void X(int); // expected-note{{candidate found by name lookup is 'Test6::C::X'}} + } + namespace D { + class X; // expected-note{{candidate found by name lookup is 'Test6::D::X'}} + } + using namespace C; + using namespace D; + void f() { + X(1); // expected-error{{reference to 'X' is ambiguous}} + } +}