[clang] 724cfce - [Clang] Do not assume a perfect match is a better match than a non-template non-perfect match (#149504)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 18 08:05:22 PDT 2025
Author: Corentin Jabot
Date: 2025-07-18T17:05:18+02:00
New Revision: 724cfce5801829340b240ba62e82a7e7199e971d
URL: https://github.com/llvm/llvm-project/commit/724cfce5801829340b240ba62e82a7e7199e971d
DIFF: https://github.com/llvm/llvm-project/commit/724cfce5801829340b240ba62e82a7e7199e971d.diff
LOG: [Clang] Do not assume a perfect match is a better match than a non-template non-perfect match (#149504)
This fixes a regression introduced by the "perfect match" overload
resolution mechanism introduced in 8c5a307.
[This does regress the performance noticeably (-0.7% for a stage 2
build)](https://llvm-compile-time-tracker.com/compare.php?from=42d2ae1034b287eb60563c370dbf52c59b66db20&to=82303bbc3e003c937ded498ac9f94f49a3fc3d90&stat=instructions:u),
however, the original patch had a +4% performance impact, so we are only
losing some of the gain, and this has
the benefit of being correct and more robust.
Fixes #147374
Added:
Modified:
clang/include/clang/Sema/Overload.h
clang/lib/Sema/SemaOverload.cpp
clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index a70335bef9dd4..d34a4146ddbd6 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -1491,8 +1491,6 @@ class Sema;
OverloadingResult
BestViableFunctionImpl(Sema &S, SourceLocation Loc,
OverloadCandidateSet::iterator &Best);
- void PerfectViableFunction(Sema &S, SourceLocation Loc,
- OverloadCandidateSet::iterator &Best);
};
bool isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 1b54628c5e564..5dd5b495480d9 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -11354,55 +11354,18 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S,
DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled;
if (TwoPhaseResolution) {
-
- PerfectViableFunction(S, Loc, Best);
- if (Best != end())
- return ResultForBestCandidate(Best);
+ OverloadingResult Res = BestViableFunctionImpl(S, Loc, Best);
+ if (Best != end() && Best->isPerfectMatch(S.Context)) {
+ if (!(HasDeferredTemplateConstructors &&
+ isa_and_nonnull<CXXConversionDecl>(Best->Function)))
+ return Res;
+ }
}
InjectNonDeducedTemplateCandidates(S);
return BestViableFunctionImpl(S, Loc, Best);
}
-void OverloadCandidateSet::PerfectViableFunction(
- Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best) {
-
- Best = end();
- for (auto It = Candidates.begin(); It != Candidates.end(); ++It) {
-
- if (!It->isPerfectMatch(S.getASTContext()))
- continue;
-
- // We found a suitable conversion function
- // but if there is a template constructor in the target class
- // we might prefer that instead.
- if (HasDeferredTemplateConstructors &&
- isa_and_nonnull<CXXConversionDecl>(It->Function)) {
- Best = end();
- break;
- }
-
- if (Best == end()) {
- Best = It;
- continue;
- }
- if (Best->Function && It->Function) {
- FunctionDecl *D =
- S.getMoreConstrainedFunction(Best->Function, It->Function);
- if (D == nullptr) {
- Best = end();
- break;
- }
- if (D == It->Function)
- Best = It;
- continue;
- }
- // ambiguous
- Best = end();
- break;
- }
-}
-
OverloadingResult OverloadCandidateSet::BestViableFunctionImpl(
Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best) {
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 46c3670848529..135865c8450f5 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -283,3 +283,31 @@ void f() {
}
#endif
+
+namespace GH147374 {
+
+struct String {};
+template <typename T> void operator+(T, String &&) = delete;
+
+struct Bar {
+ void operator+(String) const; // expected-note {{candidate function}}
+ friend void operator+(Bar, String) {}; // expected-note {{candidate function}}
+};
+
+struct Baz {
+ void operator+(String); // expected-note {{candidate function}}
+ friend void operator+(Baz, String) {}; // expected-note {{candidate function}}
+};
+
+void test() {
+ Bar a;
+ String b;
+ a + b;
+ //expected-error at -1 {{use of overloaded operator '+' is ambiguous (with operand types 'Bar' and 'String')}}
+
+ Baz z;
+ z + b;
+ //expected-error at -1 {{use of overloaded operator '+' is ambiguous (with operand types 'Baz' and 'String')}}
+}
+
+}
More information about the cfe-commits
mailing list