-
Notifications
You must be signed in to change notification settings - Fork 45
Add full member function support in BestOverloadFunctionMatch #802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5a4808f
404c728
e22330b
891f754
679f928
2067136
68d0d98
d019807
daeb42b
56572f8
9f9a10e
5952e9b
504babf
5f96f50
fecfeca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1274,7 +1274,8 @@ | |||||
| TCppFunction_t | ||||||
| BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates, | ||||||
| const std::vector<TemplateArgInfo>& explicit_types, | ||||||
| const std::vector<TemplateArgInfo>& arg_types) { | ||||||
| const std::vector<TemplateArgInfo>& arg_types, | ||||||
| TCppType_t invoking_object_type) { | ||||||
| auto& S = getSema(); | ||||||
| auto& C = S.getASTContext(); | ||||||
|
|
||||||
|
|
@@ -1288,10 +1289,33 @@ | |||||
| struct WrapperExpr : public OpaqueValueExpr { | ||||||
| WrapperExpr() : OpaqueValueExpr(clang::Stmt::EmptyShell()) {} | ||||||
| }; | ||||||
| auto* Exprs = new WrapperExpr[arg_types.size()]; | ||||||
| // Check if we need to prepend the invoking object (for member functions) | ||||||
| size_t num_exprs = arg_types.size(); | ||||||
| bool has_invoking_object = (invoking_object_type != nullptr); | ||||||
| if (has_invoking_object) | ||||||
| num_exprs++; | ||||||
| auto* Exprs = new WrapperExpr[num_exprs]; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: initializing non-owner 'WrapperExpr *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory] auto* Exprs = new WrapperExpr[num_exprs];
^ |
||||||
| llvm::SmallVector<Expr*> Args; | ||||||
| Args.reserve(arg_types.size()); | ||||||
| Args.reserve(num_exprs); | ||||||
| size_t idx = 0; | ||||||
| // If we have an invoking object, create a synthetic expression for it first | ||||||
| // This represents the object on which the member function is called | ||||||
| if (has_invoking_object) { | ||||||
| QualType ObjType = QualType::getFromOpaquePtr(invoking_object_type); | ||||||
|
|
||||||
| // Determine the expression kind based on the type | ||||||
| ExprValueKind ExprKind = | ||||||
| ExprValueKind::VK_LValue; // Default for T& and const T& | ||||||
| if (ObjType->isRValueReferenceType()) | ||||||
| ExprKind = ExprValueKind::VK_XValue; // For T&& | ||||||
|
|
||||||
| // Create the synthetic expression for the invoking object | ||||||
| new (&Exprs[idx]) OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), | ||||||
| ObjType.getNonReferenceType(), ExprKind); | ||||||
| Args.push_back(&Exprs[idx]); | ||||||
| ++idx; | ||||||
| } | ||||||
| // Now add the regular function arguments | ||||||
| for (auto i : arg_types) { | ||||||
| QualType Type = QualType::getFromOpaquePtr(i.m_Type); | ||||||
| // XValue is an object that can be "moved" whereas PRValue is temporary | ||||||
|
|
@@ -1330,27 +1354,103 @@ | |||||
| OverloadCandidateSet Overloads( | ||||||
| SourceLocation(), OverloadCandidateSet::CandidateSetKind::CSK_Normal); | ||||||
|
|
||||||
| // Separate object expression from regular arguments for member functions | ||||||
| llvm::ArrayRef<Expr*> CallArgs = Args; | ||||||
| Expr* ObjectArg = nullptr; | ||||||
| if (has_invoking_object && !Args.empty()) { | ||||||
| ObjectArg = Args[0]; | ||||||
| CallArgs = llvm::ArrayRef<Expr*>(Args).drop_front(); | ||||||
| } | ||||||
|
|
||||||
| for (void* i : candidates) { | ||||||
| Decl* D = static_cast<Decl*>(i); | ||||||
| llvm::errs() << "Candidate decl kind: " << D->getDeclKindName(); | ||||||
| if (auto* ND = dyn_cast<NamedDecl>(D)) | ||||||
| llvm::errs() << " name: " << ND->getNameAsString(); | ||||||
| llvm::errs() << " | isa<FunctionDecl>: " << isa<FunctionDecl>(D) | ||||||
| << " | isa<CXXMethodDecl>: " << isa<CXXMethodDecl>(D) | ||||||
| << " | isa<FunctionTemplateDecl>: " | ||||||
| << isa<FunctionTemplateDecl>(D) << "\n"; | ||||||
|
|
||||||
| // Special handling for member functions when object type is provided | ||||||
| if (has_invoking_object && ObjectArg) { | ||||||
| if (auto* MD = dyn_cast<CXXMethodDecl>(D)) { | ||||||
| S.AddMethodCandidate(MD, DeclAccessPair::make(MD, MD->getAccess()), | ||||||
| MD->getParent(), ObjectArg->getType(), | ||||||
| ObjectArg->Classify(C), CallArgs, Overloads); | ||||||
| continue; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Default behavior: regular function handling (backward compatible) | ||||||
| if (auto* FD = dyn_cast<FunctionDecl>(D)) { | ||||||
| if (auto* MD = dyn_cast<CXXMethodDecl>(FD)) { | ||||||
| if (!has_invoking_object && !MD->isStatic()) { | ||||||
| llvm::errs() << "Skipping non-static method as non-member candidate: " | ||||||
| << MD->getQualifiedNameAsString() << "\n"; | ||||||
| continue; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| llvm::errs() << "Adding overload candidate: " | ||||||
| << FD->getQualifiedNameAsString() << "\n"; | ||||||
| S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()), | ||||||
| Args, Overloads); | ||||||
| } else if (auto* FTD = dyn_cast<FunctionTemplateDecl>(D)) { | ||||||
| // AddTemplateOverloadCandidate is causing a memory leak | ||||||
| // It is a known bug at clang | ||||||
| // call stack: AddTemplateOverloadCandidate -> MakeDeductionFailureInfo | ||||||
| // source: | ||||||
| // https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L731-L756 | ||||||
| S.AddTemplateOverloadCandidate( | ||||||
| FTD, DeclAccessPair::make(FTD, FTD->getAccess()), | ||||||
| &ExplicitTemplateArgs, Args, Overloads); | ||||||
| // Special handling for member function templates when object type is | ||||||
| // provided | ||||||
| if (has_invoking_object && ObjectArg && FTD->getTemplatedDecl() && | ||||||
| isa<CXXMethodDecl>(FTD->getTemplatedDecl())) { | ||||||
| llvm::errs() << "Adding method template candidate: " | ||||||
| << FTD->getQualifiedNameAsString() << "\n"; | ||||||
| S.AddMethodTemplateCandidate( | ||||||
| FTD, DeclAccessPair::make(FTD, FTD->getAccess()), | ||||||
| cast<CXXRecordDecl>(FTD->getDeclContext()), &ExplicitTemplateArgs, | ||||||
| ObjectArg->getType(), ObjectArg->Classify(C), CallArgs, Overloads); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: isa_and_nonnull<> is preferred over an explicit test for null followed by calling isa<> [llvm-prefer-isa-or-dyn-cast-in-conditionals]
Suggested change
|
||||||
| } else { | ||||||
| // If the templated declaration is a non-static method and we do not | ||||||
| // have an invoking object, skip adding it as a non-member candidate. | ||||||
| if (FTD->getTemplatedDecl() && | ||||||
| isa<CXXMethodDecl>(FTD->getTemplatedDecl())) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: isa_and_nonnull<> is preferred over an explicit test for null followed by calling isa<> [llvm-prefer-isa-or-dyn-cast-in-conditionals]
Suggested change
|
||||||
| auto* MD = cast<CXXMethodDecl>(FTD->getTemplatedDecl()); | ||||||
| // Only skip when the templated decl was defined *within* the class. | ||||||
| // Out-of-class definitions live in the translation unit and should be | ||||||
| // allowed as non-member candidates | ||||||
| if (isa<CXXRecordDecl>(FTD->getDeclContext())) { | ||||||
| if (!has_invoking_object && !MD->isStatic()) { | ||||||
| llvm::errs() | ||||||
| << "Skipping non-static method template as non-member " | ||||||
| "candidate: " | ||||||
| << MD->getQualifiedNameAsString() << "\n"; | ||||||
| continue; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| llvm::errs() << "Adding template overload candidate: " | ||||||
| << FTD->getQualifiedNameAsString() << "\n"; | ||||||
| // AddTemplateOverloadCandidate is causing a memory leak | ||||||
| // It is a known bug at clang | ||||||
| // call stack: AddTemplateOverloadCandidate -> MakeDeductionFailureInfo | ||||||
| // source: | ||||||
| // https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L731-L756 | ||||||
| S.AddTemplateOverloadCandidate( | ||||||
| FTD, DeclAccessPair::make(FTD, FTD->getAccess()), | ||||||
| &ExplicitTemplateArgs, Args, Overloads); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| OverloadCandidateSet::iterator Best; | ||||||
| Overloads.BestViableFunction(S, SourceLocation(), Best); | ||||||
|
|
||||||
| FunctionDecl* Result = Best != Overloads.end() ? Best->Function : nullptr; | ||||||
| FunctionDecl* Result = nullptr; | ||||||
|
|
||||||
| // If overload resolution succeeded or found an ambiguous match, use it | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead [cppcoreguidelines-owning-memory] delete[] Exprs;
^Additional contextlib/CppInterOp/CppInterOp.cpp:1296: variable declared here auto* Exprs = new WrapperExpr[num_exprs];
^ |
||||||
| if (Best != Overloads.end()) { | ||||||
| Result = Best->Function; | ||||||
| } | ||||||
|
|
||||||
| delete[] Exprs; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead [cppcoreguidelines-owning-memory] delete[] Exprs;
^Additional contextlib/CppInterOp/CppInterOp.cpp:1296: variable declared here auto* Exprs = new WrapperExpr[num_exprs];
^ |
||||||
| return Result; | ||||||
| } | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: initializing non-owner 'WrapperExpr *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]