[clang] Revert "[Clang] Bypass TAD during overload resolution if a perfect match exists" (PR #136113)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 17 02:01:23 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: cor3ntin (cor3ntin)
<details>
<summary>Changes</summary>
Reverts llvm/llvm-project#<!-- -->136018
Still some bots failing https://lab.llvm.org/buildbot/#/builders/52/builds/7643
---
Patch is 78.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/136113.diff
12 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (-6)
- (modified) clang/include/clang/Sema/Overload.h (+10-222)
- (modified) clang/lib/Sema/SemaCodeComplete.cpp (+2-4)
- (modified) clang/lib/Sema/SemaInit.cpp (+5-13)
- (modified) clang/lib/Sema/SemaOverload.cpp (+100-432)
- (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+2-2)
- (modified) clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp (+4-4)
- (modified) clang/test/SemaCUDA/function-overload.cu (+3)
- (modified) clang/test/SemaCXX/implicit-member-functions.cpp (+14-7)
- (removed) clang/test/SemaCXX/overload-resolution-deferred-templates.cpp (-200)
- (modified) clang/test/SemaTemplate/instantiate-function-params.cpp (+4-3)
- (modified) clang/test/Templight/templight-empty-entries-fix.cpp (+75-51)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc36962b317e8..4f640697e1817 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -96,12 +96,6 @@ C++ Language Changes
asm((std::string_view("nop")) ::: (std::string_view("memory")));
}
-- Clang now implements the changes to overload resolution proposed by section 1 and 2 of
- `P3606 <https://wg21.link/P3606R0>`_. If a non-template candidate exists in an overload set that is
- a perfect match (all conversion sequences are identity conversions) template candidates are not instantiated.
- Diagnostics that would have resulted from the instantiation of these template candidates are no longer
- produced. This aligns Clang closer to the behavior of GCC, and fixes (#GH62096), (#GH74581), and (#GH74581).
-
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index e667147bfac7e..6e08762dcc6d7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -407,26 +407,6 @@ class Sema;
Third == ICK_Identity;
}
- /// A conversion sequence is perfect if it is an identity conversion and
- /// the type of the source is the same as the type of the target.
- bool isPerfect(const ASTContext &C) const {
- if (!isIdentityConversion())
- return false;
- // If we are not performing a reference binding, we can skip comparing
- // the types, which has a noticeable performance impact.
- if (!ReferenceBinding) {
- // The types might differ if there is an array-to-pointer conversion
- // or lvalue-to-rvalue conversion.
- assert(First || C.hasSameUnqualifiedType(getFromType(), getToType(2)));
- return true;
- }
- if (!C.hasSameType(getFromType(), getToType(2)))
- return false;
- if (BindsToRvalue && IsLvalueReference)
- return false;
- return true;
- }
-
ImplicitConversionRank getRank() const;
NarrowingKind
getNarrowingKind(ASTContext &Context, const Expr *Converted,
@@ -763,12 +743,6 @@ class Sema;
Standard.setAllToTypes(T);
}
- /// A conversion sequence is perfect if it is an identity conversion and
- /// the type of the source is the same as the type of the target.
- bool isPerfect(const ASTContext &C) const {
- return isStandard() && Standard.isPerfect(C);
- }
-
// True iff this is a conversion sequence from an initializer list to an
// array or std::initializer.
bool hasInitializerListContainerType() const {
@@ -965,10 +939,6 @@ class Sema;
LLVM_PREFERRED_TYPE(CallExpr::ADLCallKind)
unsigned IsADLCandidate : 1;
- /// Whether FinalConversion has been set.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasFinalConversion : 1;
-
/// Whether this is a rewritten candidate, and if so, of what kind?
LLVM_PREFERRED_TYPE(OverloadCandidateRewriteKind)
unsigned RewriteKind : 2;
@@ -1009,20 +979,6 @@ class Sema;
return false;
}
- // An overload is a perfect match if the conversion
- // sequences for each argument are perfect.
- bool isPerfectMatch(const ASTContext &Ctx) const {
- if (!Viable)
- return false;
- for (const auto &C : Conversions) {
- if (!C.isInitialized() || !C.isPerfect(Ctx))
- return false;
- }
- if (HasFinalConversion)
- return FinalConversion.isPerfect(Ctx);
- return true;
- }
-
bool TryToFixBadConversion(unsigned Idx, Sema &S) {
bool CanFix = Fix.tryToFixConversion(
Conversions[Idx].Bad.FromExpr,
@@ -1056,67 +1012,8 @@ class Sema;
: IsSurrogate(false), IgnoreObjectArgument(false),
TookAddressOfOverload(false), StrictPackMatch(false),
IsADLCandidate(llvm::to_underlying(CallExpr::NotADL)),
- HasFinalConversion(false), RewriteKind(CRK_None) {}
- };
-
- struct DeferredTemplateOverloadCandidate {
-
- // intrusive linked list support for allocateDeferredCandidate
- DeferredTemplateOverloadCandidate *Next = nullptr;
-
- enum Kind { Function, Method, Conversion };
-
- LLVM_PREFERRED_TYPE(Kind)
- unsigned Kind : 2;
- LLVM_PREFERRED_TYPE(bool)
- unsigned AllowObjCConversionOnExplicit : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned AllowResultConversion : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned AllowExplicit : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned SuppressUserConversions : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned PartialOverloading : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned AggregateCandidateDeduction : 1;
- };
-
- struct DeferredFunctionTemplateOverloadCandidate
- : public DeferredTemplateOverloadCandidate {
- FunctionTemplateDecl *FunctionTemplate;
- DeclAccessPair FoundDecl;
- ArrayRef<Expr *> Args;
- CallExpr::ADLCallKind IsADLCandidate;
- OverloadCandidateParamOrder PO;
- };
- static_assert(std::is_trivially_destructible_v<
- DeferredFunctionTemplateOverloadCandidate>);
-
- struct DeferredMethodTemplateOverloadCandidate
- : public DeferredTemplateOverloadCandidate {
- FunctionTemplateDecl *FunctionTemplate;
- DeclAccessPair FoundDecl;
- ArrayRef<Expr *> Args;
- CXXRecordDecl *ActingContext;
- Expr::Classification ObjectClassification;
- QualType ObjectType;
- OverloadCandidateParamOrder PO;
+ RewriteKind(CRK_None) {}
};
- static_assert(std::is_trivially_destructible_v<
- DeferredMethodTemplateOverloadCandidate>);
-
- struct DeferredConversionTemplateOverloadCandidate
- : public DeferredTemplateOverloadCandidate {
- FunctionTemplateDecl *FunctionTemplate;
- DeclAccessPair FoundDecl;
- CXXRecordDecl *ActingContext;
- Expr *From;
- QualType ToType;
- };
-
- static_assert(std::is_trivially_destructible_v<
- DeferredConversionTemplateOverloadCandidate>);
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
@@ -1146,11 +1043,6 @@ class Sema;
/// C++ [over.match.call.general]
/// Resolve a call through the address of an overload set.
CSK_AddressOfOverloadSet,
-
- /// When doing overload resolution during code completion,
- /// we want to show all viable candidates, including otherwise
- /// deferred template candidates.
- CSK_CodeCompletion,
};
/// Information about operator rewrites to consider when adding operator
@@ -1225,15 +1117,7 @@ class Sema;
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<uintptr_t, 16> Functions;
- DeferredTemplateOverloadCandidate *FirstDeferredCandidate = nullptr;
- unsigned DeferredCandidatesCount : 8 * sizeof(unsigned) - 2;
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasDeferredTemplateConstructors : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned ResolutionByPerfectCandidateIsDisabled : 1;
-
- // Allocator for ConversionSequenceLists and deferred candidate args.
- // We store the first few of these
+ // Allocator for ConversionSequenceLists. We store the first few of these
// inline to avoid allocation for small sets.
llvm::BumpPtrAllocator SlabAllocator;
@@ -1241,11 +1125,8 @@ class Sema;
CandidateSetKind Kind;
OperatorRewriteInfo RewriteInfo;
- /// Small storage size for ImplicitConversionSequences
- /// and the persisted arguments of deferred candidates.
constexpr static unsigned NumInlineBytes =
- 32 * sizeof(ImplicitConversionSequence);
-
+ 24 * sizeof(ImplicitConversionSequence);
unsigned NumInlineBytesUsed = 0;
alignas(void *) char InlineSpace[NumInlineBytes];
@@ -1256,13 +1137,15 @@ class Sema;
/// from the slab allocator.
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
/// instead.
+ /// FIXME: Now that this only allocates ImplicitConversionSequences, do we
+ /// want to un-generalize this?
template <typename T>
T *slabAllocate(unsigned N) {
// It's simpler if this doesn't need to consider alignment.
static_assert(alignof(T) == alignof(void *),
"Only works for pointer-aligned types.");
- static_assert(std::is_trivially_destructible_v<T> ||
- (std::is_same_v<ImplicitConversionSequence, T>),
+ static_assert(std::is_trivial<T>::value ||
+ std::is_same<ImplicitConversionSequence, T>::value,
"Add destruction logic to OverloadCandidateSet::clear().");
unsigned NBytes = sizeof(T) * N;
@@ -1276,34 +1159,12 @@ class Sema;
return reinterpret_cast<T *>(FreeSpaceStart);
}
- // Because the size of OverloadCandidateSet has a noticeable impact on
- // performance, we store each deferred template candidate in the slab
- // allocator such that deferred candidates are ultimately a singly-linked
- // intrusive linked list. This ends up being much more efficient than a
- // SmallVector that is empty in the common case.
- template <typename T> T *allocateDeferredCandidate() {
- T *C = slabAllocate<T>(1);
- if (!FirstDeferredCandidate)
- FirstDeferredCandidate = C;
- else {
- auto *F = FirstDeferredCandidate;
- while (F->Next)
- F = F->Next;
- F->Next = C;
- }
- DeferredCandidatesCount++;
- return C;
- }
-
void destroyCandidates();
public:
OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,
OperatorRewriteInfo RewriteInfo = {})
- : FirstDeferredCandidate(nullptr), DeferredCandidatesCount(0),
- HasDeferredTemplateConstructors(false),
- ResolutionByPerfectCandidateIsDisabled(false), Loc(Loc), Kind(CSK),
- RewriteInfo(RewriteInfo) {}
+ : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;
~OverloadCandidateSet() { destroyCandidates(); }
@@ -1315,9 +1176,6 @@ class Sema;
/// Whether diagnostics should be deferred.
bool shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args, SourceLocation OpLoc);
- // Whether the resolution of template candidates should be deferred
- bool shouldDeferTemplateArgumentDeduction(const LangOptions &Opts) const;
-
/// Determine when this overload candidate will be new to the
/// overload set.
bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO =
@@ -1341,10 +1199,8 @@ class Sema;
iterator begin() { return Candidates.begin(); }
iterator end() { return Candidates.end(); }
- size_t size() const { return Candidates.size() + DeferredCandidatesCount; }
- bool empty() const {
- return Candidates.empty() && DeferredCandidatesCount == 0;
- }
+ size_t size() const { return Candidates.size(); }
+ bool empty() const { return Candidates.empty(); }
/// Allocate storage for conversion sequences for NumConversions
/// conversions.
@@ -1360,24 +1216,6 @@ class Sema;
return ConversionSequenceList(Conversions, NumConversions);
}
- /// Provide storage for any Expr* arg that must be preserved
- /// until deferred template candidates are deduced.
- /// Typically this should be used for reversed operator arguments
- /// and any time the argument array is transformed while adding
- /// a template candidate.
- llvm::MutableArrayRef<Expr *> getPersistentArgsArray(unsigned N) {
- Expr **Exprs = slabAllocate<Expr *>(N);
- return llvm::MutableArrayRef<Expr *>(Exprs, N);
- }
-
- template <typename... T>
- llvm::MutableArrayRef<Expr *> getPersistentArgsArray(T *...Exprs) {
- llvm::MutableArrayRef<Expr *> Arr =
- getPersistentArgsArray(sizeof...(Exprs));
- llvm::copy(std::initializer_list<Expr *>{Exprs...}, Arr.data());
- return Arr;
- }
-
/// Add a new candidate with NumConversions conversion sequence slots
/// to the overload set.
OverloadCandidate &addCandidate(unsigned NumConversions = 0,
@@ -1393,32 +1231,6 @@ class Sema;
return C;
}
- void AddDeferredTemplateCandidate(
- FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
- ArrayRef<Expr *> Args, bool SuppressUserConversions,
- bool PartialOverloading, bool AllowExplicit,
- CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO,
- bool AggregateCandidateDeduction);
-
- void AddDeferredMethodTemplateCandidate(
- FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext, QualType ObjectType,
- Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
- bool SuppressUserConversions, bool PartialOverloading,
- OverloadCandidateParamOrder PO);
-
- void AddDeferredConversionTemplateCandidate(
- FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
- bool AllowObjCConversionOnExplicit, bool AllowExplicit,
- bool AllowResultConversion);
-
- void InjectNonDeducedTemplateCandidates(Sema &S);
-
- void DisableResolutionByPerfectCandidate() {
- ResolutionByPerfectCandidateIsDisabled = true;
- }
-
/// Find the best viable function on this overload set, if it exists.
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
@@ -1451,15 +1263,6 @@ class Sema;
DestAS = AS;
}
- private:
- OverloadingResult ResultForBestCandidate(const iterator &Best);
- void CudaExcludeWrongSideCandidates(
- Sema &S, SmallVectorImpl<OverloadCandidate *> &Candidates);
- 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,
@@ -1508,21 +1311,6 @@ class Sema;
// parameter.
bool shouldEnforceArgLimit(bool PartialOverloading, FunctionDecl *Function);
- inline bool OverloadCandidateSet::shouldDeferTemplateArgumentDeduction(
- const LangOptions &Opts) const {
- return
- // For user defined conversion we need to check against different
- // combination of CV qualifiers and look at any explicit specifier, so
- // always deduce template candidates.
- Kind != CSK_InitByUserDefinedConversion
- // When doing code completion, we want to see all the
- // viable candidates.
- && Kind != CSK_CodeCompletion
- // CUDA may prefer template candidates even when a non-candidate
- // is a perfect match
- && !Opts.CUDA;
- }
-
} // namespace clang
#endif // LLVM_CLANG_SEMA_OVERLOAD_H
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 45405d4709e14..f6ec4cb0f069e 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -6354,8 +6354,7 @@ SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
Expr *NakedFn = Fn->IgnoreParenCasts();
// Build an overload candidate set based on the functions we find.
SourceLocation Loc = Fn->getExprLoc();
- OverloadCandidateSet CandidateSet(Loc,
- OverloadCandidateSet::CSK_CodeCompletion);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
if (auto ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) {
SemaRef.AddOverloadedCallCandidates(ULE, ArgsWithoutDependentTypes,
@@ -6558,8 +6557,7 @@ QualType SemaCodeCompletion::ProduceConstructorSignatureHelp(
// FIXME: Provide support for variadic template constructors.
if (CRD) {
- OverloadCandidateSet CandidateSet(Loc,
- OverloadCandidateSet::CSK_CodeCompletion);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
for (NamedDecl *C : SemaRef.LookupConstructors(CRD)) {
if (auto *FD = dyn_cast<FunctionDecl>(C)) {
// FIXME: we can't yet provide correct signature help for initializer
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 9e802a175bb05..77d7f821f2011 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5231,7 +5231,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
- assert(Best->HasFinalConversion && !isa<CXXConstructorDecl>(Function) &&
+ assert(!isa<CXXConstructorDecl>(Function) &&
"should not have conversion after constructor");
ImplicitConversionSequence ICS;
@@ -6200,7 +6200,6 @@ static void TryUserDefinedConversion(Sema &S,
// If the conversion following the call to the conversion function
// is interesting, add it as a separate step.
- assert(Best->HasFinalConversion);
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
@@ -10030,19 +10029,12 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// When [...] the constructor [...] is a candidate by
// - [over.match.copy] (in all cases)
if (TD) {
-
- // As template candidates are not deduced immediately,
- // persist the array in the overload set.
- MutableArrayRef<Expr *> TmpInits =
- Candidates.getPersistentArgsArray(Inits.size());
-
- for (auto [I, E] : llvm::enumerate(Inits)) {
+ SmallVector<Expr *, 8> TmpInits;
+ for (Expr *E : Inits)
if (auto *DI = dyn_cast<DesignatedInitExpr>(E))
- TmpInits[I] = DI->getInit();
+ TmpInits.push_back(DI->getInit());
else
- TmpInits[I] = E;
- }
-
+ TmpInits.push_back(E);
AddTemplateOverloadCandidate(
TD, FoundDecl, /*ExplicitArgs=*/nullptr, TmpInits, Candidates,
/*SuppressUserConversions=*/false,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index b7a981e08ead9..55634aa75ae25 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1123,10 +1123,6 @@ void OverloadCandidateSet::clear(CandidateSetKind CSK) {
Candidates.clear();
Functions.clear();
Kind = CSK;
- FirstDeferredCandidate = nullptr;
- DeferredCandidatesCount = 0;
- HasDeferredTemplateConstructors = false;
- ResolutionByPerfectCandidateIsDisabled = false;
}
namespace {
@@ -4079,9 +4075,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
-
- assert(Best->HasFinalConversion);
-
// C++ [over.ics.user]p1:
//
// [...] If the user-defined conversion is specified by a
@@ -5165,9 +5158,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
case OR_Success:
-
- assert(Best->HasFinalConversion);
-
// C++ [over.ics.ref]p1:
//
// [...] If the parameter binds directly to the result of
@@ -7805,14 +7795,15 @@ void Sema::AddMethodCandidate(
}
}
-static void AddMethodTemplateCandidateImmediately(
- Sema &S, OverloadCandidateSet &CandidateSet,
+void Sema::AddMethodTemplateCandidate(
FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType,
Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
- bool SuppressUserConversions, bool PartialOverloading,
- OverloadCandidateParamOrder PO) {
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+ bool PartialOverloading, OverloadCandidateParamOrder PO) {
+ if (!CandidateSet.isNewCandidate(MethodTmpl, PO))
+ return;
// C++ [over.match.fu...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/136113
More information about the cfe-commits
mailing list