Skip to content

Commit dd1c7b5

Browse files
committed
[Clang][Sema] Ensure that the selected candidate for a member function explicit specialization is more constrained than all others
1 parent bd576fe commit dd1c7b5

File tree

1 file changed

+56
-24
lines changed

1 file changed

+56
-24
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9062,51 +9062,83 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
90629062
if (Previous.empty()) {
90639063
// Nowhere to look anyway.
90649064
} else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) {
9065-
SmallVector<FunctionDecl *> Candidates;
9066-
bool Ambiguous = false;
9067-
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
9068-
I != E; ++I) {
9069-
CXXMethodDecl *Method =
9070-
dyn_cast<CXXMethodDecl>((*I)->getUnderlyingDecl());
9071-
if (!Method)
9065+
LookupResult::Filter Filter = Previous.makeFilter();
9066+
while (Filter.hasNext()) {
9067+
auto *Method =
9068+
dyn_cast<CXXMethodDecl>(Filter.next()->getUnderlyingDecl());
9069+
// Discard any candidates that aren't member functions.
9070+
if (!Method) {
9071+
Filter.erase();
90729072
continue;
9073+
}
9074+
90739075
QualType Adjusted = Function->getType();
90749076
if (!hasExplicitCallingConv(Adjusted))
90759077
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
9078+
// Discard any candidates with the wrong type.
90769079
// This doesn't handle deduced return types, but both function
90779080
// declarations should be undeduced at this point.
9078-
if (!Context.hasSameType(Adjusted, Method->getType()))
9081+
if (!Context.hasSameType(Adjusted, Method->getType())) {
9082+
Filter.erase();
90799083
continue;
9084+
}
9085+
9086+
// Discard any candidates with unsatisfied constraints.
90809087
if (ConstraintSatisfaction Satisfaction;
90819088
Method->getTrailingRequiresClause() &&
90829089
(CheckFunctionConstraints(Method, Satisfaction,
90839090
/*UsageLoc=*/Member->getLocation(),
90849091
/*ForOverloadResolution=*/true) ||
9085-
!Satisfaction.IsSatisfied))
9086-
continue;
9087-
Candidates.push_back(Method);
9088-
FunctionDecl *MoreConstrained =
9089-
Instantiation ? getMoreConstrainedFunction(
9090-
Method, cast<FunctionDecl>(Instantiation))
9091-
: Method;
9092-
if (!MoreConstrained) {
9093-
Ambiguous = true;
9092+
!Satisfaction.IsSatisfied)) {
9093+
Filter.erase();
90949094
continue;
90959095
}
9096-
if (MoreConstrained == Method) {
9097-
Ambiguous = false;
9098-
FoundInstantiation = *I;
9099-
Instantiation = Method;
9100-
InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
9101-
MSInfo = Method->getMemberSpecializationInfo();
9096+
}
9097+
Filter.done();
9098+
9099+
// If we have no candidates left after filtering, we are done.
9100+
if (Previous.empty())
9101+
return false;
9102+
9103+
// Find the function that is more constrained than every other function it
9104+
// has been compared to.
9105+
UnresolvedSetIterator Best = Previous.begin();
9106+
CXXMethodDecl *BestMethod = nullptr;
9107+
for (UnresolvedSetIterator I = Previous.begin(), E = Previous.end(); I != E;
9108+
++I) {
9109+
auto *Method = cast<CXXMethodDecl>(I->getUnderlyingDecl());
9110+
if (I == Best ||
9111+
getMoreConstrainedFunction(Method, BestMethod) == Method) {
9112+
Best = I;
9113+
BestMethod = Method;
9114+
}
9115+
}
9116+
9117+
FoundInstantiation = *Best;
9118+
Instantiation = BestMethod;
9119+
InstantiatedFrom = BestMethod->getInstantiatedFromMemberFunction();
9120+
MSInfo = BestMethod->getMemberSpecializationInfo();
9121+
9122+
// Make sure the best candidate is more specialized than all of the others.
9123+
bool Ambiguous = false;
9124+
for (UnresolvedSetIterator I = Previous.begin(), E = Previous.end(); I != E;
9125+
++I) {
9126+
auto *Method = cast<CXXMethodDecl>(I->getUnderlyingDecl());
9127+
if (I != Best &&
9128+
getMoreConstrainedFunction(Method, BestMethod) != BestMethod) {
9129+
Ambiguous = true;
9130+
break;
91029131
}
91039132
}
9133+
91049134
if (Ambiguous) {
91059135
Diag(Member->getLocation(), diag::err_function_member_spec_ambiguous)
91069136
<< Member << (InstantiatedFrom ? InstantiatedFrom : Instantiation);
9107-
for (FunctionDecl *Candidate : Candidates)
9137+
for (NamedDecl *Candidate : Previous) {
9138+
Candidate = Candidate->getUnderlyingDecl();
91089139
Diag(Candidate->getLocation(), diag::note_function_member_spec_matched)
91099140
<< Candidate;
9141+
}
91109142
return true;
91119143
}
91129144
} else if (isa<VarDecl>(Member)) {

0 commit comments

Comments
 (0)