Skip to content

Commit d031ff3

Browse files
[Sema] Fix handling of functions that hide classes
When a function is declared in the same scope as a class with the same name then the function hides that class. Currently this is done by a single check after the main loop in LookupResult::resolveKind, but this can give the wrong result when we have a using declaration in multiple namespace scopes in two different ways: * When the using declaration is hidden in one namespace but not the other we can end up considering only the hidden one when deciding if the result is ambiguous, causing an incorrect "not ambiguous" result. * When two classes with the same name in different namespace scopes are both hidden by using declarations this can result in incorrectly deciding the result is ambiguous. There's currently a comment saying this is expected, but I don't think that's correct. Solve this by checking each Decl to see if it's hidden by some other Decl in the same scope. This means we have to delay removing anything from Decls until after the main loop, in case a Decl is hidden by another that is removed due to being non-unique. Differential Revision: https://reviews.llvm.org/D154503
1 parent e93ae28 commit d031ff3

File tree

2 files changed

+409
-32
lines changed

2 files changed

+409
-32
lines changed

clang/lib/Sema/SemaLookup.cpp

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -513,21 +513,42 @@ void LookupResult::resolveKind() {
513513
const NamedDecl *HasNonFunction = nullptr;
514514

515515
llvm::SmallVector<const NamedDecl *, 4> EquivalentNonFunctions;
516+
llvm::BitVector RemovedDecls(N);
516517

517-
unsigned UniqueTagIndex = 0;
518-
519-
unsigned I = 0;
520-
while (I < N) {
518+
for (unsigned I = 0; I < N; I++) {
521519
const NamedDecl *D = Decls[I]->getUnderlyingDecl();
522520
D = cast<NamedDecl>(D->getCanonicalDecl());
523521

524522
// Ignore an invalid declaration unless it's the only one left.
525523
// Also ignore HLSLBufferDecl which not have name conflict with other Decls.
526-
if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) {
527-
Decls[I] = Decls[--N];
524+
if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) &&
525+
N - RemovedDecls.count() > 1) {
526+
RemovedDecls.set(I);
528527
continue;
529528
}
530529

530+
// C++ [basic.scope.hiding]p2:
531+
// A class name or enumeration name can be hidden by the name of
532+
// an object, function, or enumerator declared in the same
533+
// scope. If a class or enumeration name and an object, function,
534+
// or enumerator are declared in the same scope (in any order)
535+
// with the same name, the class or enumeration name is hidden
536+
// wherever the object, function, or enumerator name is visible.
537+
if (HideTags && isa<TagDecl>(D)) {
538+
bool Hidden = false;
539+
for (auto *OtherDecl : Decls) {
540+
if (canHideTag(OtherDecl) &&
541+
getContextForScopeMatching(OtherDecl)->Equals(
542+
getContextForScopeMatching(Decls[I]))) {
543+
RemovedDecls.set(I);
544+
Hidden = true;
545+
break;
546+
}
547+
}
548+
if (Hidden)
549+
continue;
550+
}
551+
531552
std::optional<unsigned> ExistingI;
532553

533554
// Redeclarations of types via typedef can occur both within a scope
@@ -560,7 +581,7 @@ void LookupResult::resolveKind() {
560581
if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I],
561582
Decls[*ExistingI]))
562583
Decls[*ExistingI] = Decls[I];
563-
Decls[I] = Decls[--N];
584+
RemovedDecls.set(I);
564585
continue;
565586
}
566587

@@ -571,7 +592,6 @@ void LookupResult::resolveKind() {
571592
} else if (isa<TagDecl>(D)) {
572593
if (HasTag)
573594
Ambiguous = true;
574-
UniqueTagIndex = I;
575595
HasTag = true;
576596
} else if (isa<FunctionTemplateDecl>(D)) {
577597
HasFunction = true;
@@ -587,36 +607,14 @@ void LookupResult::resolveKind() {
587607
if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction,
588608
D)) {
589609
EquivalentNonFunctions.push_back(D);
590-
Decls[I] = Decls[--N];
610+
RemovedDecls.set(I);
591611
continue;
592612
}
593613

594614
Ambiguous = true;
595615
}
596616
HasNonFunction = D;
597617
}
598-
I++;
599-
}
600-
601-
// C++ [basic.scope.hiding]p2:
602-
// A class name or enumeration name can be hidden by the name of
603-
// an object, function, or enumerator declared in the same
604-
// scope. If a class or enumeration name and an object, function,
605-
// or enumerator are declared in the same scope (in any order)
606-
// with the same name, the class or enumeration name is hidden
607-
// wherever the object, function, or enumerator name is visible.
608-
// But it's still an error if there are distinct tag types found,
609-
// even if they're not visible. (ref?)
610-
if (N > 1 && HideTags && HasTag && !Ambiguous &&
611-
(HasFunction || HasNonFunction || HasUnresolved)) {
612-
const NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1];
613-
if (isa<TagDecl>(Decls[UniqueTagIndex]->getUnderlyingDecl()) &&
614-
getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
615-
getContextForScopeMatching(OtherDecl)) &&
616-
canHideTag(OtherDecl))
617-
Decls[UniqueTagIndex] = Decls[--N];
618-
else
619-
Ambiguous = true;
620618
}
621619

622620
// FIXME: This diagnostic should really be delayed until we're done with
@@ -625,9 +623,15 @@ void LookupResult::resolveKind() {
625623
getSema().diagnoseEquivalentInternalLinkageDeclarations(
626624
getNameLoc(), HasNonFunction, EquivalentNonFunctions);
627625

626+
// Remove decls by replacing them with decls from the end (which
627+
// means that we need to iterate from the end) and then truncating
628+
// to the new size.
629+
for (int I = RemovedDecls.find_last(); I >= 0; I = RemovedDecls.find_prev(I))
630+
Decls[I] = Decls[--N];
628631
Decls.truncate(N);
629632

630-
if (HasNonFunction && (HasFunction || HasUnresolved))
633+
if ((HasNonFunction && (HasFunction || HasUnresolved)) ||
634+
(HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved)))
631635
Ambiguous = true;
632636

633637
if (Ambiguous)

0 commit comments

Comments
 (0)