Skip to content

Add full member function support in BestOverloadFunctionMatch#802

Open
Priyanshu3820 wants to merge 15 commits intocompiler-research:mainfrom
Priyanshu3820:main
Open

Add full member function support in BestOverloadFunctionMatch#802
Priyanshu3820 wants to merge 15 commits intocompiler-research:mainfrom
Priyanshu3820:main

Conversation

@Priyanshu3820
Copy link

Description

This PR enhances BestOverloadFunctionMatch to properly handle const-qualified member function overload resolution by utilizing Clang's AddMethodCandidate API instead of AddOverloadCandidate.
Fixes #590

Type of change

Please tick all options which are relevant.

  • [✅] Bug fix
  • [✅] New feature

Testing

Tested calling with both const object type and non-const object type

Checklist

  • [✅] I have read the contribution guide recently

@Priyanshu3820 Priyanshu3820 marked this pull request as ready for review February 5, 2026 19:49
Copilot AI review requested due to automatic review settings February 5, 2026 19:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the BestOverloadFunctionMatch function to properly support const-qualified member function overload resolution, addressing issue #590. The implementation switches from using Clang's AddOverloadCandidate API to AddMethodCandidate and AddMethodTemplateCandidate APIs when resolving member function overloads with an invoking object type specified.

Changes:

  • Added optional invoking_object_type parameter to BestOverloadFunctionMatch to enable overload resolution based on const-qualification and value category of the invoking object
  • Modified overload candidate selection logic to use appropriate Clang APIs (AddMethodCandidate for member functions, AddOverloadCandidate for regular functions)
  • Added comprehensive test coverage for const-qualified member function overload resolution
  • Applied code formatting improvements across test files

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
include/CppInterOp/CppInterOp.h Added optional invoking_object_type parameter with default value to maintain backward compatibility
lib/CppInterOp/CppInterOp.cpp Implemented logic to handle member function overload resolution with object type consideration; includes synthetic expression creation for the invoking object and refactored error message formatting
unittests/CppInterOp/FunctionReflectionTest.cpp Added new test case for const-qualified member function overload resolution and applied code formatting improvements throughout

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Priyanshu3820 Priyanshu3820 mentioned this pull request Feb 5, 2026
10 tasks
@Priyanshu3820
Copy link
Author

Wasn't sure whether to check the new feature option but did it anyways. Also, a lot of diffs happened after running clang-format

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 19. Check the log or trigger a new build to see more.

WrapperExpr() : OpaqueValueExpr(clang::Stmt::EmptyShell()) {}
};
auto* Exprs = new WrapperExpr[arg_types.size()];
// Check if we need to prepend the invoking object (for member functions)
Copy link
Contributor

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]

  auto* Exprs = new WrapperExpr[num_exprs];
  ^

FunctionDecl* Result = Best != Overloads.end() ? Best->Function : nullptr;
FunctionDecl* Result = nullptr;

// If overload resolution succeeded or found an ambiguous match, use it
Copy link
Contributor

Choose a reason for hiding this comment

The 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 context

lib/CppInterOp/CppInterOp.cpp:1296: variable declared here

  auto* Exprs = new WrapperExpr[num_exprs];
  ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "size_t" is directly included [misc-include-cleaner]

unittests/CppInterOp/FunctionReflectionTest.cpp:9:

- #include <llvm/ADT/ArrayRef.h>
+ #include <cstddef>
+ #include <llvm/ADT/ArrayRef.h>


TYPED_TEST(CPPINTEROP_TEST_MODE, FunctionReflection_IsPublicMethod) {
std::vector<Decl *> Decls, SubDecls;
std::vector<Decl*> Decls, SubDecls;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: multiple declarations in a single statement reduces readability [readability-isolate-declaration]

Suggested change
std::vector<Decl*> Decls, SubDecls;
std::vector<Decl*> Decls;
std::vector<Decl*> SubDecls;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

      (clang::CXXConstructorDecl*)Cpp::GetDefaultConstructor(Decls[0]);
      ^

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 16. Check the log or trigger a new build to see more.

S.AddMethodTemplateCandidate(
FTD, DeclAccessPair::make(FTD, FTD->getAccess()),
cast<CXXRecordDecl>(FTD->getDeclContext()), &ExplicitTemplateArgs,
ObjectArg->getType(), ObjectArg->Classify(C), CallArgs, Overloads);
Copy link
Contributor

Choose a reason for hiding this comment

The 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
ObjectArg->getType(), ObjectArg->Classify(C), CallArgs, Overloads);
if (isa_and_nonnull<CXXMethodDecl>(FTD->getTemplatedDecl())) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]

  void* args0[1] = {(void*)&i};
  ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]

  void* args1[1] = {(void*)&s};
  ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

  auto* CtorD = (clang::CXXConstructorDecl*)Cpp::GetDefaultConstructor(ClassC);
                ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

  auto* DtorD = (clang::CXXDestructorDecl*)Cpp::GetDestructor(ClassC);
                ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "clang::CXXDestructorDecl" is directly included [misc-include-cleaner]

unittests/CppInterOp/FunctionReflectionTest.cpp:9:

- #include <llvm/ADT/ArrayRef.h>
+ #include <clang/AST/DeclCXX.h>
+ #include <llvm/ADT/ArrayRef.h>

operators DFLT_OP_ARITY);
EXPECT_EQ(operators.size(), 2);

auto kp_int_type = Cpp::GetTypeFromScope(KlassProduct_int);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'auto kp_int_type' can be declared as 'auto *kp_int_type' [llvm-qualified-auto]

Suggested change
auto kp_int_type = Cpp::GetTypeFromScope(KlassProduct_int);
auto *kp_int_type = Cpp::GetTypeFromScope(KlassProduct_int);

EXPECT_EQ(operators.size(), 2);

auto kp_int_type = Cpp::GetTypeFromScope(KlassProduct_int);
auto kp_int_lvalue = Cpp::GetReferencedType(kp_int_type, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'auto kp_int_lvalue' can be declared as 'auto *kp_int_lvalue' [llvm-qualified-auto]

Suggested change
auto kp_int_lvalue = Cpp::GetReferencedType(kp_int_type, false);
auto *kp_int_lvalue = Cpp::GetReferencedType(kp_int_type, false);

EXPECT_TRUE(where == Cpp::Construct(scope, where DFLT_1));
// Check for the value of x which should be at the start of the object.
EXPECT_TRUE(*(int *)where == 12345);
EXPECT_TRUE(*(int*)where == 12345);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

  EXPECT_TRUE(*(int*)where == 12345);
               ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]

  auto* new_head = reinterpret_cast<void*>(reinterpret_cast<char*>(where) +
                                           ^

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random change. Revert.

Comment on lines 378 to 379
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random formatting change. Revert.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]

  auto* new_head = reinterpret_cast<void*>(reinterpret_cast<char*>(where) +
                   ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unused variable 'C' [clang-diagnostic-unused-variable]

  ASTContext& C = Interp->getCI()->getASTContext();
              ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::vector" is directly included [misc-include-cleaner]

unittests/CppInterOp/InterpreterTest.cpp:2:

+ #include <vector>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

  auto* CXI = clang_createInterpreter(argv, 1);
                                      ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]

  auto* CXI = clang_createInterpreter(argv, 3);
                                      ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::end" is directly included [misc-include-cleaner]

unittests/CppInterOp/InterpreterTest.cpp:2:

+ #include <iterator>

@Priyanshu3820
Copy link
Author

@mcbarton, actually these changes occured after running clang-format

@mcbarton
Copy link
Collaborator

mcbarton commented Feb 6, 2026

@mcbarton, actually these changes occured after running clang-format

@Priyanshu3820 clang-format on the code may suggest these changes, but we use git clang format to only apply clang-format to the changes in the PR/commits.

@Priyanshu3820
Copy link
Author

@mcbarton, actually these changes occured after running clang-format

@Priyanshu3820 clang-format on the code may suggest these changes, but we use git clang format to only apply clang-format to the changes in the PR/commits.

I get it now, I was supposed to run git-clang-format not clang-format on the files. I'll revert the changes(there are too many though)

@Priyanshu3820
Copy link
Author

@mcbarton, I've fixed the formatting

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: too few arguments to function call, expected 4, have 3 [clang-diagnostic-error]

      operators, {}, {{Cpp::GetTypeFromScope(KlassProduct_float)}});
                                                                  ^

@Priyanshu3820
Copy link
Author

hi @mcbarton, can you please re-run the workflow once more, I am sure the tests would pass this time. All the tests pass locally.

@codecov
Copy link

codecov bot commented Feb 7, 2026

Codecov Report

❌ Patch coverage is 87.93103% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.56%. Comparing base (76d0600) to head (fecfeca).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
lib/CppInterOp/CppInterOp.cpp 87.93% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #802      +/-   ##
==========================================
+ Coverage   79.46%   79.56%   +0.10%     
==========================================
  Files          11       11              
  Lines        4002     4056      +54     
==========================================
+ Hits         3180     3227      +47     
- Misses        822      829       +7     
Files with missing lines Coverage Δ
include/CppInterOp/CppInterOp.h 95.12% <ø> (ø)
lib/CppInterOp/CppInterOp.cpp 87.82% <87.93%> (-0.02%) ⬇️
Files with missing lines Coverage Δ
include/CppInterOp/CppInterOp.h 95.12% <ø> (ø)
lib/CppInterOp/CppInterOp.cpp 87.82% <87.93%> (-0.02%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

bool has_invoking_object = (invoking_object_type != nullptr);
if (has_invoking_object)
num_exprs++;
auto* Exprs = new WrapperExpr[num_exprs];
Copy link
Contributor

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]

  auto* Exprs = new WrapperExpr[num_exprs];
  ^

// 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())) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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
isa<CXXMethodDecl>(FTD->getTemplatedDecl())) {
if (isa_and_nonnull<CXXMethodDecl>(FTD->getTemplatedDecl())) {

Result = Best->Function;
}

delete[] Exprs;
Copy link
Contributor

Choose a reason for hiding this comment

The 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 context

lib/CppInterOp/CppInterOp.cpp:1296: variable declared here

  auto* Exprs = new WrapperExpr[num_exprs];
  ^

@Priyanshu3820
Copy link
Author

@mcbarton, can you guide me how do we go forward in cases like this. Should I create a PR in cppyy-backend at the same time for simultaneous review or should I wait for this to land first?

@mcbarton
Copy link
Collaborator

mcbarton commented Feb 9, 2026

@Priyanshu3820 Although we have this situation come up occasionally I don't think we have a set procedure on how to deal with it. My suggestion is as follows.

  1. First wait until @Vipul-Cariappa , @aaronj0 or @vgvassilev has the bandwidth to review your PR, and address any comments they have.
  2. Once this PR is approved (not taken in, just approved), open a PR(PRs) in the cppyy related repos needed to get the ci to go green. Get these PRs reviewed and approved.
  3. Modify the ci in this PR with a dummy commit which checks out these cppyy PRs to show that the ci is green with them. Then revert this dummy commit after showing that the ci is green if all these PRs go in. Squash all commits into a single commit with a useful commit message. Once this is all done Vassil, Vipul or aaron can take the PRs in if happy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Full member function support in BestOverloadFunctionMatch

2 participants

Comments