mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-12 01:18:53 +00:00
Revert "[Sema] Fix handling of functions that hide classes"
This reverts commit d031ff3877
.
See https://reviews.llvm.org/D154503#4576393 for a reproducer and
details.
This commit is contained in:
parent
3dd58333d0
commit
7d259b36d2
@ -514,42 +514,21 @@ void LookupResult::resolveKind() {
|
||||
const NamedDecl *HasNonFunction = nullptr;
|
||||
|
||||
llvm::SmallVector<const NamedDecl *, 4> EquivalentNonFunctions;
|
||||
llvm::BitVector RemovedDecls(N);
|
||||
|
||||
for (unsigned I = 0; I < N; I++) {
|
||||
unsigned UniqueTagIndex = 0;
|
||||
|
||||
unsigned I = 0;
|
||||
while (I < N) {
|
||||
const NamedDecl *D = Decls[I]->getUnderlyingDecl();
|
||||
D = cast<NamedDecl>(D->getCanonicalDecl());
|
||||
|
||||
// Ignore an invalid declaration unless it's the only one left.
|
||||
// Also ignore HLSLBufferDecl which not have name conflict with other Decls.
|
||||
if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) &&
|
||||
N - RemovedDecls.count() > 1) {
|
||||
RemovedDecls.set(I);
|
||||
if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) {
|
||||
Decls[I] = Decls[--N];
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 && isa<TagDecl>(D)) {
|
||||
bool Hidden = false;
|
||||
for (auto *OtherDecl : Decls) {
|
||||
if (canHideTag(OtherDecl) &&
|
||||
getContextForScopeMatching(OtherDecl)->Equals(
|
||||
getContextForScopeMatching(Decls[I]))) {
|
||||
RemovedDecls.set(I);
|
||||
Hidden = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Hidden)
|
||||
continue;
|
||||
}
|
||||
|
||||
std::optional<unsigned> ExistingI;
|
||||
|
||||
// Redeclarations of types via typedef can occur both within a scope
|
||||
@ -582,7 +561,7 @@ void LookupResult::resolveKind() {
|
||||
if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I],
|
||||
Decls[*ExistingI]))
|
||||
Decls[*ExistingI] = Decls[I];
|
||||
RemovedDecls.set(I);
|
||||
Decls[I] = Decls[--N];
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -593,6 +572,7 @@ void LookupResult::resolveKind() {
|
||||
} else if (isa<TagDecl>(D)) {
|
||||
if (HasTag)
|
||||
Ambiguous = true;
|
||||
UniqueTagIndex = I;
|
||||
HasTag = true;
|
||||
} else if (isa<FunctionTemplateDecl>(D)) {
|
||||
HasFunction = true;
|
||||
@ -608,7 +588,7 @@ void LookupResult::resolveKind() {
|
||||
if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction,
|
||||
D)) {
|
||||
EquivalentNonFunctions.push_back(D);
|
||||
RemovedDecls.set(I);
|
||||
Decls[I] = Decls[--N];
|
||||
continue;
|
||||
}
|
||||
if (D->isPlaceholderVar(getSema().getLangOpts()) &&
|
||||
@ -620,6 +600,28 @@ void LookupResult::resolveKind() {
|
||||
}
|
||||
HasNonFunction = D;
|
||||
}
|
||||
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<TagDecl>(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
|
||||
@ -628,15 +630,9 @@ void LookupResult::resolveKind() {
|
||||
getSema().diagnoseEquivalentInternalLinkageDeclarations(
|
||||
getNameLoc(), HasNonFunction, EquivalentNonFunctions);
|
||||
|
||||
// Remove decls by replacing them with decls from the end (which
|
||||
// means that we need to iterate from the end) and then truncating
|
||||
// to the new size.
|
||||
for (int I = RemovedDecls.find_last(); I >= 0; I = RemovedDecls.find_prev(I))
|
||||
Decls[I] = Decls[--N];
|
||||
Decls.truncate(N);
|
||||
|
||||
if ((HasNonFunction && (HasFunction || HasUnresolved)) ||
|
||||
(HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved)))
|
||||
if (HasNonFunction && (HasFunction || HasUnresolved))
|
||||
Ambiguous = true;
|
||||
|
||||
if (Ambiguous && ReferenceToPlaceHolderVariable)
|
||||
|
@ -1,373 +0,0 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
namespace A {
|
||||
class X { }; // expected-note{{candidate found by name lookup is 'A::X'}}
|
||||
// expected-note@-1{{candidate found by name lookup is 'A::X'}}
|
||||
}
|
||||
namespace B {
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'B::X'}}
|
||||
// expected-note@-1{{candidate found by name lookup is 'B::X'}}
|
||||
}
|
||||
|
||||
// Using directive doesn't cause A::X to be hidden, so X is ambiguous.
|
||||
namespace Test1a {
|
||||
using namespace A;
|
||||
using namespace B;
|
||||
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test1b {
|
||||
using namespace B;
|
||||
using namespace A;
|
||||
|
||||
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 Test2a {
|
||||
namespace C {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test2a::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
using B::X; // expected-note{{candidate found by name lookup is 'Test2a::D::X'}}
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test2b {
|
||||
namespace C {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test2b::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
using B::X; // expected-note{{candidate found by name lookup is 'Test2b::D::X'}}
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
|
||||
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 Test3a {
|
||||
namespace C {
|
||||
using A::X;
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test3a::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test3a::D::X'}}
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test3b {
|
||||
namespace C {
|
||||
using A::X;
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test3b::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test3b::D::X'}}
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test3c {
|
||||
namespace C {
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test3c::C::X'}}
|
||||
using A::X;
|
||||
}
|
||||
namespace D {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test3c::D::X'}}
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test3d {
|
||||
namespace C {
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test3d::C::X'}}
|
||||
using A::X;
|
||||
}
|
||||
namespace D {
|
||||
using A::X; // expected-note{{candidate found by name lookup is 'Test3d::D::X'}}
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
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 Test4a {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test4b {
|
||||
namespace C {
|
||||
using A::X;
|
||||
void X(int);
|
||||
}
|
||||
namespace D {
|
||||
using A::X;
|
||||
void X(int, int);
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test4c {
|
||||
namespace C {
|
||||
void X(int);
|
||||
using A::X;
|
||||
}
|
||||
namespace D {
|
||||
void X(int, int);
|
||||
using A::X;
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test4d {
|
||||
namespace C {
|
||||
void X(int);
|
||||
using A::X;
|
||||
}
|
||||
namespace D {
|
||||
void X(int, int);
|
||||
using A::X;
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
// B::X hides class X in C, so the the result is not ambiguous
|
||||
namespace Test5a {
|
||||
namespace C {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test5b {
|
||||
namespace C {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test5c {
|
||||
namespace C {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test5d {
|
||||
namespace C {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
// B::X hides class X declared in both C and D, so the result is not ambiguous.
|
||||
namespace Test6a {
|
||||
namespace C {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
namespace D {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test6b {
|
||||
namespace C {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
namespace D {
|
||||
class X { };
|
||||
using B::X;
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test6c {
|
||||
namespace C {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test6d {
|
||||
namespace C {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
namespace D {
|
||||
using B::X;
|
||||
class X { };
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1);
|
||||
}
|
||||
}
|
||||
|
||||
// function X inside C should hide class X in C but not D.
|
||||
namespace Test7a {
|
||||
namespace C {
|
||||
class X;
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test7a::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
class X; // expected-note{{candidate found by name lookup is 'Test7a::D::X'}}
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test7b {
|
||||
namespace C {
|
||||
class X;
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test7b::C::X'}}
|
||||
}
|
||||
namespace D {
|
||||
class X; // expected-note{{candidate found by name lookup is 'Test7b::D::X'}}
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test7c {
|
||||
namespace C {
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test7c::C::X'}}
|
||||
class X;
|
||||
}
|
||||
namespace D {
|
||||
class X; // expected-note{{candidate found by name lookup is 'Test7c::D::X'}}
|
||||
}
|
||||
using namespace C;
|
||||
using namespace D;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test7d {
|
||||
namespace C {
|
||||
void X(int); // expected-note{{candidate found by name lookup is 'Test7d::C::X'}}
|
||||
class X;
|
||||
}
|
||||
namespace D {
|
||||
class X; // expected-note{{candidate found by name lookup is 'Test7d::D::X'}}
|
||||
}
|
||||
using namespace D;
|
||||
using namespace C;
|
||||
void f() {
|
||||
X(1); // expected-error{{reference to 'X' is ambiguous}}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user