https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/222296
>From d5c04428be4b47526390e4bbcbb49e92bd9005dd Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Wed, 9 Sep 2026 15:19:40 +0800 Subject: [PATCH 1/3] [Clang] Avoid unnecessary overload resolution when building RecoveryExpr --- clang/lib/Sema/SemaOverload.cpp | 64 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 106ddb90ed9dc..6cec8f9892c2c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14612,18 +14612,31 @@ static bool canBeDeclaredInNamespace(const DeclarationName &Name) { /// Attempt to recover from an ill-formed use of a non-dependent name in a /// template, where the non-dependent name was declared after the template -/// was defined. This is common in code written for a compilers which do not +/// was defined. This is common in code written for compilers which do not /// correctly implement two-stage name lookup. /// /// Returns true if a viable candidate was found and a diagnostic was issued. static bool DiagnoseTwoPhaseLookup( Sema &SemaRef, SourceLocation FnLoc, const CXXScopeSpec &SS, LookupResult &R, OverloadCandidateSet::CandidateSetKind CSK, + OverloadCandidateSet &KnownInvalidCandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, CXXRecordDecl **FoundInClass = nullptr) { if (!SemaRef.inTemplateInstantiation() || !SS.isEmpty()) return false; + llvm::SmallPtrSet<FunctionDecl *, 4> InvalidCandidates( + llvm::from_range, + llvm::make_filter_range( + llvm::map_range( + KnownInvalidCandidateSet, + [](const OverloadCandidate &Candidate) -> FunctionDecl * { + if (!Candidate.Viable) + return Candidate.Function; + return nullptr; + }), + [](const FunctionDecl *FD) { return FD != nullptr; })); + for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) { if (DC->isTransparentContext()) continue; @@ -14634,8 +14647,13 @@ static bool DiagnoseTwoPhaseLookup( R.suppressDiagnostics(); OverloadCandidateSet Candidates(FnLoc, CSK); - SemaRef.AddOverloadedCallCandidates(R, ExplicitTemplateArgs, Args, - Candidates); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (InvalidCandidates.contains(I->getAsFunction())) + continue; + AddOverloadedCallCandidate(SemaRef, I.getPair(), ExplicitTemplateArgs, + Args, Candidates, false, + /*KnownValid=*/false); + } OverloadCandidateSet::iterator Best; OverloadingResult OR = @@ -14726,14 +14744,15 @@ static bool DiagnoseTwoPhaseLookup( /// Returns true if a viable candidate was found and a diagnostic was issued. static bool DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op, - SourceLocation OpLoc, - ArrayRef<Expr *> Args) { + SourceLocation OpLoc, ArrayRef<Expr *> Args, + OverloadCandidateSet &KnownInvalidCandidateSet) { DeclarationName OpName = - SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); + SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName); - return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R, - OverloadCandidateSet::CSK_Operator, - /*ExplicitTemplateArgs=*/nullptr, Args); + return DiagnoseTwoPhaseLookup( + SemaRef, OpLoc, CXXScopeSpec(), R, OverloadCandidateSet::CSK_Operator, + KnownInvalidCandidateSet, + /*ExplicitTemplateArgs=*/nullptr, Args, /*FoundInClass=*/nullptr); } namespace { @@ -14760,11 +14779,10 @@ class BuildRecoveryCallExprRAII { /// expected to diagnose as appropriate. static ExprResult BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, - UnresolvedLookupExpr *ULE, - SourceLocation LParenLoc, - MutableArrayRef<Expr *> Args, - SourceLocation RParenLoc, - bool EmptyLookup, bool AllowTypoCorrection) { + UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, + MutableArrayRef<Expr *> Args, SourceLocation RParenLoc, + OverloadCandidateSet &KnownInvalidCandidateSet, + bool AllowTypoCorrection) { // Do not try to recover if it is already building a recovery call. // This stops infinite loops for template instantiations like // @@ -14790,9 +14808,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, CXXRecordDecl *FoundInClass = nullptr; if (DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal, - ExplicitTemplateArgs, Args, &FoundInClass)) { + KnownInvalidCandidateSet, ExplicitTemplateArgs, + Args, &FoundInClass)) { // OK, diagnosed a two-phase lookup issue. - } else if (EmptyLookup) { + } else if (KnownInvalidCandidateSet.empty()) { // Try to recover from an empty lookup with typo correction. R.clear(); NoTypoCorrectionCCC NoTypoValidator{}; @@ -15005,10 +15024,9 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, // Try to recover by looking for viable functions which the user might // have meant to call. - ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, - Args, RParenLoc, - CandidateSet->empty(), - AllowTypoCorrection); + ExprResult Recovery = + BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, Args, RParenLoc, + *CandidateSet, AllowTypoCorrection); if (Recovery.isInvalid() || Recovery.isUsable()) return Recovery; @@ -15410,7 +15428,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, // This is an erroneous use of an operator which can be overloaded by // a non-member function. Check for non-member operators which were // defined too late to be candidates. - if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, ArgsArray)) + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, ArgsArray, + CandidateSet)) // FIXME: Recover by calling the found function. return ExprError(); @@ -15932,7 +15951,8 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // This is an erroneous use of an operator which can be overloaded by // a non-member function. Check for non-member operators which were // defined too late to be candidates. - if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args)) + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, + CandidateSet)) // FIXME: Recover by calling the found function. return ExprError(); >From de09a923261728b389a84136429b25bb64f8bf9f Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Wed, 9 Sep 2026 22:29:50 +0800 Subject: [PATCH 2/3] Address Erich's feedback --- clang/lib/Sema/SemaOverload.cpp | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6cec8f9892c2c..429ed5718cd87 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14625,18 +14625,6 @@ static bool DiagnoseTwoPhaseLookup( if (!SemaRef.inTemplateInstantiation() || !SS.isEmpty()) return false; - llvm::SmallPtrSet<FunctionDecl *, 4> InvalidCandidates( - llvm::from_range, - llvm::make_filter_range( - llvm::map_range( - KnownInvalidCandidateSet, - [](const OverloadCandidate &Candidate) -> FunctionDecl * { - if (!Candidate.Viable) - return Candidate.Function; - return nullptr; - }), - [](const FunctionDecl *FD) { return FD != nullptr; })); - for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) { if (DC->isTransparentContext()) continue; @@ -14647,13 +14635,14 @@ static bool DiagnoseTwoPhaseLookup( R.suppressDiagnostics(); OverloadCandidateSet Candidates(FnLoc, CSK); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - if (InvalidCandidates.contains(I->getAsFunction())) - continue; - AddOverloadedCallCandidate(SemaRef, I.getPair(), ExplicitTemplateArgs, - Args, Candidates, false, - /*KnownValid=*/false); + for (auto &Cand : KnownInvalidCandidateSet) { + if (Cand.Function) + Candidates.exclude(Cand.Function); + else if (Cand.IsSurrogate) + Candidates.exclude(Cand.Surrogate); } + SemaRef.AddOverloadedCallCandidates(R, ExplicitTemplateArgs, Args, + Candidates); OverloadCandidateSet::iterator Best; OverloadingResult OR = >From 3068ea46e3298ad53cccfb8d5a1a106f5521ea95 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Wed, 9 Sep 2026 22:51:07 +0800 Subject: [PATCH 3/3] fixup --- clang/include/clang/Sema/Overload.h | 4 ++++ clang/lib/Sema/SemaOverload.cpp | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index a3ec9ef3f3e6d..3abc0013d8f69 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -1375,10 +1375,14 @@ class Sema; void clear(CandidateSetKind CSK); using iterator = SmallVectorImpl<OverloadCandidate>::iterator; + using const_iterator = SmallVectorImpl<OverloadCandidate>::const_iterator; iterator begin() { return Candidates.begin(); } iterator end() { return Candidates.end(); } + const_iterator begin() const { return Candidates.begin(); } + const_iterator end() const { return Candidates.end(); } + size_t size() const { return Candidates.size() + DeferredCandidatesCount; } size_t nonDeferredCandidatesCount() const { return Candidates.size(); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 429ed5718cd87..fb7f1c483c529 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14619,7 +14619,7 @@ static bool canBeDeclaredInNamespace(const DeclarationName &Name) { static bool DiagnoseTwoPhaseLookup( Sema &SemaRef, SourceLocation FnLoc, const CXXScopeSpec &SS, LookupResult &R, OverloadCandidateSet::CandidateSetKind CSK, - OverloadCandidateSet &KnownInvalidCandidateSet, + const OverloadCandidateSet &ResolvedCandidates, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, CXXRecordDecl **FoundInClass = nullptr) { if (!SemaRef.inTemplateInstantiation() || !SS.isEmpty()) @@ -14635,7 +14635,9 @@ static bool DiagnoseTwoPhaseLookup( R.suppressDiagnostics(); OverloadCandidateSet Candidates(FnLoc, CSK); - for (auto &Cand : KnownInvalidCandidateSet) { + // We have performed a BestViableFunction over these candidates, so + // exclude them. + for (auto &Cand : ResolvedCandidates) { if (Cand.Function) Candidates.exclude(Cand.Function); else if (Cand.IsSurrogate) @@ -14731,16 +14733,15 @@ static bool DiagnoseTwoPhaseLookup( /// was defined. /// /// Returns true if a viable candidate was found and a diagnostic was issued. -static bool -DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op, - SourceLocation OpLoc, ArrayRef<Expr *> Args, - OverloadCandidateSet &KnownInvalidCandidateSet) { +static bool DiagnoseTwoPhaseOperatorLookup( + Sema &SemaRef, OverloadedOperatorKind Op, SourceLocation OpLoc, + ArrayRef<Expr *> Args, const OverloadCandidateSet &ResolvedCandidateSet) { DeclarationName OpName = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName); return DiagnoseTwoPhaseLookup( SemaRef, OpLoc, CXXScopeSpec(), R, OverloadCandidateSet::CSK_Operator, - KnownInvalidCandidateSet, + ResolvedCandidateSet, /*ExplicitTemplateArgs=*/nullptr, Args, /*FoundInClass=*/nullptr); } @@ -14770,7 +14771,7 @@ static ExprResult BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, MutableArrayRef<Expr *> Args, SourceLocation RParenLoc, - OverloadCandidateSet &KnownInvalidCandidateSet, + const OverloadCandidateSet &ResolvedCandidateSet, bool AllowTypoCorrection) { // Do not try to recover if it is already building a recovery call. // This stops infinite loops for template instantiations like @@ -14797,10 +14798,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, CXXRecordDecl *FoundInClass = nullptr; if (DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal, - KnownInvalidCandidateSet, ExplicitTemplateArgs, + ResolvedCandidateSet, ExplicitTemplateArgs, Args, &FoundInClass)) { // OK, diagnosed a two-phase lookup issue. - } else if (KnownInvalidCandidateSet.empty()) { + } else if (ResolvedCandidateSet.empty()) { // Try to recover from an empty lookup with typo correction. R.clear(); NoTypoCorrectionCCC NoTypoValidator{}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
