Skip to content

Commit 9e11a6d

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 30f0cd5 commit 9e11a6d

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
@@ -514,21 +514,42 @@ void LookupResult::resolveKind() {
514514
const NamedDecl *HasNonFunction = nullptr;
515515

516516
llvm::SmallVector<const NamedDecl *, 4> EquivalentNonFunctions;
517+
llvm::BitVector RemovedDecls(N);
517518

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

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

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

534555
// Redeclarations of types via typedef can occur both within a scope
@@ -561,7 +582,7 @@ void LookupResult::resolveKind() {
561582
if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I],
562583
Decls[*ExistingI]))
563584
Decls[*ExistingI] = Decls[I];
564-
Decls[I] = Decls[--N];
585+
RemovedDecls.set(I);
565586
continue;
566587
}
567588

@@ -572,7 +593,6 @@ void LookupResult::resolveKind() {
572593
} else if (isa<TagDecl>(D)) {
573594
if (HasTag)
574595
Ambiguous = true;
575-
UniqueTagIndex = I;
576596
HasTag = true;
577597
} else if (isa<FunctionTemplateDecl>(D)) {
578598
HasFunction = true;
@@ -588,7 +608,7 @@ void LookupResult::resolveKind() {
588608
if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction,
589609
D)) {
590610
EquivalentNonFunctions.push_back(D);
591-
Decls[I] = Decls[--N];
611+
RemovedDecls.set(I);
592612
continue;
593613
}
594614
if (D->isPlaceholderVar(getSema().getLangOpts()) &&
@@ -600,28 +620,6 @@ void LookupResult::resolveKind() {
600620
}
601621
HasNonFunction = D;
602622
}
603-
I++;
604-
}
605-
606-
// C++ [basic.scope.hiding]p2:
607-
// A class name or enumeration name can be hidden by the name of
608-
// an object, function, or enumerator declared in the same
609-
// scope. If a class or enumeration name and an object, function,
610-
// or enumerator are declared in the same scope (in any order)
611-
// with the same name, the class or enumeration name is hidden
612-
// wherever the object, function, or enumerator name is visible.
613-
// But it's still an error if there are distinct tag types found,
614-
// even if they're not visible. (ref?)
615-
if (N > 1 && HideTags && HasTag && !Ambiguous &&
616-
(HasFunction || HasNonFunction || HasUnresolved)) {
617-
const NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1];
618-
if (isa<TagDecl>(Decls[UniqueTagIndex]->getUnderlyingDecl()) &&
619-
getContextForScopeMatching(Decls[UniqueTagIndex])->Equals(
620-
getContextForScopeMatching(OtherDecl)) &&
621-
canHideTag(OtherDecl))
622-
Decls[UniqueTagIndex] = Decls[--N];
623-
else
624-
Ambiguous = true;
625623
}
626624

627625
// FIXME: This diagnostic should really be delayed until we're done with
@@ -630,9 +628,15 @@ void LookupResult::resolveKind() {
630628
getSema().diagnoseEquivalentInternalLinkageDeclarations(
631629
getNameLoc(), HasNonFunction, EquivalentNonFunctions);
632630

631+
// Remove decls by replacing them with decls from the end (which
632+
// means that we need to iterate from the end) and then truncating
633+
// to the new size.
634+
for (int I = RemovedDecls.find_last(); I >= 0; I = RemovedDecls.find_prev(I))
635+
Decls[I] = Decls[--N];
633636
Decls.truncate(N);
634637

635-
if (HasNonFunction && (HasFunction || HasUnresolved))
638+
if ((HasNonFunction && (HasFunction || HasUnresolved)) ||
639+
(HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved)))
636640
Ambiguous = true;
637641

638642
if (Ambiguous && ReferenceToPlaceHolderVariable)

0 commit comments

Comments
 (0)