Skip to content

Add BestOverloadFunctionMatch & IsFunction Remove BestTemplateFunctionMatch #514

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

Conversation

Vipul-Cariappa
Copy link
Collaborator

Description

Resolve and instantiate (if templated) overload from vector of overloads for the given template parameter types and argument types.
With these changes, we replicate clang's overload resolution and template instantiation.

Fixes # (issue)

Fixes 10 test cases in cppyy.
Can close #352 and #511.

Type of change

Please tick all options which are relevant.

  • Bug fix
  • New feature
  • Requires documentation updates

Testing

Included tests

Checklist

  • I have read the contribution guide recently

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

ExprValueKind ExprKind = ExprValueKind::VK_PRValue;
if (Type->isReferenceType())
ExprKind = ExprValueKind::VK_LValue;
Args.push_back(new (getSema().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: initializing non-owner argument of type 'ValueParamT' (aka 'clang::Expr *') with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

      Args.push_back(new (getSema().getASTContext())
                     ^

Copy link

codecov bot commented Mar 5, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 72.71%. Comparing base (16c67f9) to head (2b81002).
Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #514      +/-   ##
==========================================
+ Coverage   72.45%   72.71%   +0.26%     
==========================================
  Files           9        9              
  Lines        3591     3618      +27     
==========================================
+ Hits         2602     2631      +29     
+ Misses        989      987       -2     
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 83.00% <100.00%> (+0.34%) ⬆️
Files with missing lines Coverage Δ
include/clang/Interpreter/CppInterOp.h 96.29% <ø> (ø)
lib/Interpreter/CppInterOp.cpp 83.00% <100.00%> (+0.34%) ⬆️
🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

ExprValueKind ExprKind = ExprValueKind::VK_PRValue;
if (Type->isReferenceType())
ExprKind = ExprValueKind::VK_LValue;
Args.push_back(new (getSema().getASTContext())
Copy link
Contributor

Choose a reason for hiding this comment

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

Construct the Expr on the stack and pass it as a reference. This way if we start using something outside of the types and expression values valgrind will be able to tell us (upon future changes of the implementation in clang). To do this you will need an std::vector<Expr> Exprs with the same lifetime as Args and Args taking Exprs addresses elementwise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Exprs.push_back fails. I guess it is because move constructor is deleted. Error message:

[ 68%] Building CXX object lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o
In file included from /usr/include/c++/14.2.1/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
                 from /usr/include/c++/14.2.1/bits/allocator.h:46,
                 from /usr/include/c++/14.2.1/bits/stl_tree.h:64,
                 from /usr/include/c++/14.2.1/set:62,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:15,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:10:
/usr/include/c++/14.2.1/bits/new_allocator.h: In instantiation of ‘void std::__new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = clang::OpaqueValueExpr; _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr]’:
/usr/include/c++/14.2.1/bits/alloc_traits.h:575:17:   required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = clang::OpaqueValueExpr; _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; allocator_type = std::allocator<clang::OpaqueValueExpr>]’
  575 |           __a.construct(__p, std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:117:30:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  117 |             _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  118 |                                      std::forward<_Args>(__args)...);
      |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_vector.h:1301:21:   required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; value_type = clang::OpaqueValueExpr]’
 1301 |       { emplace_back(std::move(__x)); }
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:22:   required from here
 1082 |       Exprs.push_back(OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind));
      |       ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/new_allocator.h:191:11: error: use of deleted function ‘clang::OpaqueValueExpr::OpaqueValueExpr(clang::OpaqueValueExpr&&)’
  191 |         { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/DeclCXX.h:22,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/GlobalDecl.h:18,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/Compatibility.h:8,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:12:
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: note: ‘clang::OpaqueValueExpr::OpaqueValueExpr(clang::OpaqueValueExpr&&)’ is implicitly deleted because the default definition would be ill-formed:
 1173 | class OpaqueValueExpr : public Expr {
      |       ^~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: error: use of deleted function ‘clang::Expr::Expr(clang::Expr&&)’
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:116:3: note: declared here
  116 |   Expr(Expr &&) = delete;
      |   ^~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: note: use ‘-fdiagnostics-all-candidates’ to display considered candidates
 1173 | class OpaqueValueExpr : public Expr {
      |       ^~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/new_allocator.h:191:11: note: use ‘-fdiagnostics-all-candidates’ to display considered candidates
  191 |         { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/14.2.1/vector:65,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:17:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = clang::OpaqueValueExpr; _Tp = clang::OpaqueValueExpr&&]’:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:182:4:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*]’
  182 |         = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:373:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*; _Tp = clang::OpaqueValueExpr]’
  373 |       return std::uninitialized_copy(__first, __last, __result);
      |              ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:399:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = clang::OpaqueValueExpr*; _ForwardIterator = clang::OpaqueValueExpr*; _Allocator = allocator<clang::OpaqueValueExpr>]’
  398 |       return std::__uninitialized_copy_a
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  399 |         (_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__first),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  400 |          _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__last), __result, __alloc);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:676:60:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_append(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>]’
  676 |             __new_finish = std::__uninitialized_move_if_noexcept_a(
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  677 |                              __old_start, __old_finish,
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~            
  678 |                              __new_start, _M_get_Tp_allocator());
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   
/usr/include/c++/14.2.1/bits/vector.tcc:123:21:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  123 |           _M_realloc_append(std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_vector.h:1301:21:   required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; value_type = clang::OpaqueValueExpr]’
 1301 |       { emplace_back(std::move(__x)); }
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:22:   required from here
 1082 |       Exprs.push_back(OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind));
      |       ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,
      |                                                        ^~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
make[2]: *** [lib/Interpreter/CMakeFiles/clangCppInterOp.dir/build.make:79: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:426: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/all] Error 2
make: *** [Makefile:136: all] Error 2

Similarly, Exprs.emplace_back also fails with the following error message.

[ 68%] Building CXX object lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o
In file included from /usr/include/c++/14.2.1/vector:65,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:17,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:10:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = clang::OpaqueValueExpr; _Tp = clang::OpaqueValueExpr&&]’:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:182:4:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*]’
  182 |         = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:373:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*; _Tp = clang::OpaqueValueExpr]’
  373 |       return std::uninitialized_copy(__first, __last, __result);
      |              ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:399:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = clang::OpaqueValueExpr*; _ForwardIterator = clang::OpaqueValueExpr*; _Allocator = allocator<clang::OpaqueValueExpr>]’
  398 |       return std::__uninitialized_copy_a
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  399 |         (_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__first),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  400 |          _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__last), __result, __alloc);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:676:60:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_append(_Args&& ...) [with _Args = {clang::SourceLocation, clang::QualType, clang::ExprValueKind&}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>]’
  676 |             __new_finish = std::__uninitialized_move_if_noexcept_a(
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  677 |                              __old_start, __old_finish,
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~            
  678 |                              __new_start, _M_get_Tp_allocator());
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   
/usr/include/c++/14.2.1/bits/vector.tcc:123:21:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::SourceLocation, clang::QualType, clang::ExprValueKind&}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  123 |           _M_realloc_append(std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:25:   required from here
 1082 |       Exprs.emplace_back(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind);
      |       ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,
      |                                                        ^~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
make[2]: *** [lib/Interpreter/CMakeFiles/clangCppInterOp.dir/build.make:79: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:426: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/all] Error 2

Do we need to specify an allocator provided by clang?

Copy link
Contributor

Choose a reason for hiding this comment

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

I seem to remember that we could create an expression on the stack but apparently I am confusing myself. We should probably put it in some scratch area, call placement new there and then destroy it...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not sure how I would go about destroying it. The default delete operator is marked unreachable (reference: https://github.com/llvm/llvm-project/blob/release/19.x/clang/include/clang/AST/Stmt.h#L106-L109). And the delete operators defined are empty (reference: https://github.com/llvm/llvm-project/blob/release/19.x/clang/include/clang/AST/Stmt.h#L1289-L1293).
I can call into one of these delete operators if required?

Comment on lines 1106 to 1110
S.AddMethodCandidate(
MD, DeclAccessPair::make(MD, MD->getAccess()), MD->getParent(),
C.getTypeDeclType(MD->getParent()),
Expr::Classification::makeSimpleLValue(), Args, Overloads);
} else if (auto* FD = dyn_cast<FunctionDecl>(D)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

AddOverloadCandidate already calls AddMethodCandidate if we got a CXXMethodDecl...


OverloadCandidateSet Overloads(
SourceLocation(), OverloadCandidateSet::CandidateSetKind::CSK_Normal);
for (void* i : candidates) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not using Sema::AddFunctionCandidates instead of this loop?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We will still require a loop to populate UnresolvedSetImpl from candidates. Also, when trying it locally, the following assertion fails https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L5692 for one of the test cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe that assertion is coming from an interface on our end that needs fixing?

Copy link
Contributor

Choose a reason for hiding this comment

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

We will still require a loop to populate UnresolvedSetImpl from candidates.

It seems to have an append operator taking a range...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It seems to have an append operator taking a range...

The iterator is a UnresolvedSetIterator(reference: https://clang.llvm.org/doxygen/classclang_1_1UnresolvedSetImpl.html#ad1e4dde3cd343da5f9918eb0caedd0a7)


Maybe that assertion is coming from an interface on our end that needs fixing?

I have been debugging this. I am not able to detect the cause. Our interfaces are being used correctly, as far as I can see.

@@ -1027,61 +1056,78 @@ namespace Cpp {
}

TCppFunction_t
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates,
Copy link
Contributor

Choose a reason for hiding this comment

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

This function feels very similar to Sema::BuildCallExpr can we use that instead and unwrap the result from the call expression? I think the cost would be an AST node allocation per call but we currently do that anyway...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will recommend against it. We will need to create a C++ function call expression for it to work.
I did adapt this function from Sema::BuildCallExpr.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, it will but we do that anyway. If you prefer not to do it, then write a comment that this is copied from there. FWIW, that did not seem the case when I looked...

Copy link
Collaborator Author

@Vipul-Cariappa Vipul-Cariappa left a comment

Choose a reason for hiding this comment

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

I will make the necessary changes in my next commit.
For the comments where I have not replied.

ExprValueKind ExprKind = ExprValueKind::VK_PRValue;
if (Type->isReferenceType())
ExprKind = ExprValueKind::VK_LValue;
Args.push_back(new (getSema().getASTContext())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Exprs.push_back fails. I guess it is because move constructor is deleted. Error message:

[ 68%] Building CXX object lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o
In file included from /usr/include/c++/14.2.1/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
                 from /usr/include/c++/14.2.1/bits/allocator.h:46,
                 from /usr/include/c++/14.2.1/bits/stl_tree.h:64,
                 from /usr/include/c++/14.2.1/set:62,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:15,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:10:
/usr/include/c++/14.2.1/bits/new_allocator.h: In instantiation of ‘void std::__new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = clang::OpaqueValueExpr; _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr]’:
/usr/include/c++/14.2.1/bits/alloc_traits.h:575:17:   required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = clang::OpaqueValueExpr; _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; allocator_type = std::allocator<clang::OpaqueValueExpr>]’
  575 |           __a.construct(__p, std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:117:30:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  117 |             _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  118 |                                      std::forward<_Args>(__args)...);
      |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_vector.h:1301:21:   required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; value_type = clang::OpaqueValueExpr]’
 1301 |       { emplace_back(std::move(__x)); }
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:22:   required from here
 1082 |       Exprs.push_back(OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind));
      |       ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/new_allocator.h:191:11: error: use of deleted function ‘clang::OpaqueValueExpr::OpaqueValueExpr(clang::OpaqueValueExpr&&)’
  191 |         { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/DeclCXX.h:22,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/GlobalDecl.h:18,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/Compatibility.h:8,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:12:
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: note: ‘clang::OpaqueValueExpr::OpaqueValueExpr(clang::OpaqueValueExpr&&)’ is implicitly deleted because the default definition would be ill-formed:
 1173 | class OpaqueValueExpr : public Expr {
      |       ^~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: error: use of deleted function ‘clang::Expr::Expr(clang::Expr&&)’
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:116:3: note: declared here
  116 |   Expr(Expr &&) = delete;
      |   ^~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/llvm-project/clang/include/clang/AST/Expr.h:1173:7: note: use ‘-fdiagnostics-all-candidates’ to display considered candidates
 1173 | class OpaqueValueExpr : public Expr {
      |       ^~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/new_allocator.h:191:11: note: use ‘-fdiagnostics-all-candidates’ to display considered candidates
  191 |         { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/14.2.1/vector:65,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:17:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = clang::OpaqueValueExpr; _Tp = clang::OpaqueValueExpr&&]’:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:182:4:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*]’
  182 |         = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:373:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*; _Tp = clang::OpaqueValueExpr]’
  373 |       return std::uninitialized_copy(__first, __last, __result);
      |              ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:399:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = clang::OpaqueValueExpr*; _ForwardIterator = clang::OpaqueValueExpr*; _Allocator = allocator<clang::OpaqueValueExpr>]’
  398 |       return std::__uninitialized_copy_a
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  399 |         (_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__first),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  400 |          _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__last), __result, __alloc);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:676:60:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_append(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>]’
  676 |             __new_finish = std::__uninitialized_move_if_noexcept_a(
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  677 |                              __old_start, __old_finish,
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~            
  678 |                              __new_start, _M_get_Tp_allocator());
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   
/usr/include/c++/14.2.1/bits/vector.tcc:123:21:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::OpaqueValueExpr}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  123 |           _M_realloc_append(std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_vector.h:1301:21:   required from ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; value_type = clang::OpaqueValueExpr]’
 1301 |       { emplace_back(std::move(__x)); }
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:22:   required from here
 1082 |       Exprs.push_back(OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind));
      |       ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,
      |                                                        ^~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
make[2]: *** [lib/Interpreter/CMakeFiles/clangCppInterOp.dir/build.make:79: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:426: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/all] Error 2
make: *** [Makefile:136: all] Error 2

Similarly, Exprs.emplace_back also fails with the following error message.

[ 68%] Building CXX object lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o
In file included from /usr/include/c++/14.2.1/vector:65,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/include/clang/Interpreter/CppInterOp.h:17,
                 from /home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:10:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h: In instantiation of ‘constexpr bool std::__check_constructible() [with _ValueType = clang::OpaqueValueExpr; _Tp = clang::OpaqueValueExpr&&]’:
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:182:4:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*]’
  182 |         = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:373:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<clang::OpaqueValueExpr*>; _ForwardIterator = clang::OpaqueValueExpr*; _Tp = clang::OpaqueValueExpr]’
  373 |       return std::uninitialized_copy(__first, __last, __result);
      |              ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:399:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = clang::OpaqueValueExpr*; _ForwardIterator = clang::OpaqueValueExpr*; _Allocator = allocator<clang::OpaqueValueExpr>]’
  398 |       return std::__uninitialized_copy_a
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  399 |         (_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__first),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  400 |          _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__last), __result, __alloc);
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/vector.tcc:676:60:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_append(_Args&& ...) [with _Args = {clang::SourceLocation, clang::QualType, clang::ExprValueKind&}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>]’
  676 |             __new_finish = std::__uninitialized_move_if_noexcept_a(
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  677 |                              __old_start, __old_finish,
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~            
  678 |                              __new_start, _M_get_Tp_allocator());
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   
/usr/include/c++/14.2.1/bits/vector.tcc:123:21:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {clang::SourceLocation, clang::QualType, clang::ExprValueKind&}; _Tp = clang::OpaqueValueExpr; _Alloc = std::allocator<clang::OpaqueValueExpr>; reference = clang::OpaqueValueExpr&]’
  123 |           _M_realloc_append(std::forward<_Args>(__args)...);
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/vipul-cariappa/Documents/Workspace/cpp-py/compiler-research/CppInterOp/lib/Interpreter/CppInterOp.cpp:1082:25:   required from here
 1082 |       Exprs.emplace_back(SourceLocation::getFromRawEncoding(1), Type.getNonReferenceType(), ExprKind);
      |       ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: error: static assertion failed: result type must be constructible from input type
   90 |       static_assert(is_constructible<_ValueType, _Tp>::value,
      |                                                        ^~~~~
/usr/include/c++/14.2.1/bits/stl_uninitialized.h:90:56: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
make[2]: *** [lib/Interpreter/CMakeFiles/clangCppInterOp.dir/build.make:79: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/CppInterOp.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:426: lib/Interpreter/CMakeFiles/clangCppInterOp.dir/all] Error 2

Do we need to specify an allocator provided by clang?

@@ -1027,61 +1056,78 @@ namespace Cpp {
}

TCppFunction_t
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will recommend against it. We will need to create a C++ function call expression for it to work.
I did adapt this function from Sema::BuildCallExpr.


OverloadCandidateSet Overloads(
SourceLocation(), OverloadCandidateSet::CandidateSetKind::CSK_Normal);
for (void* i : candidates) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We will still require a loop to populate UnresolvedSetImpl from candidates. Also, when trying it locally, the following assertion fails https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L5692 for one of the test cases.

@@ -1027,61 +1056,73 @@ namespace Cpp {
}

TCppFunction_t
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates,
Copy link
Contributor

Choose a reason for hiding this comment

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

Another note is that we should check the memory growth when we call this function N times. Ideally it should be 0 for failed overload resolution candidate set. In reality it should be close to 0...

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

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

Nicely done. Please run clang-format and squash on merge.

@Vipul-Cariappa Vipul-Cariappa requested a review from mcbarton March 9, 2025 10:30
@Vipul-Cariappa
Copy link
Collaborator Author

Hi @mcbarton, the Windows CI is failing in the build step of CppInterOp. I am not sure what is causing this. Can you please look into this. This PR is good to go otherwise. I expect it to fail while building cppyy, with an error message similar to the Ubuntu/OSX CI run (but I guess we don't test cppyy on Windows).

…nctionMatch`

Resolve and instantiate (if templated) overload from vector of  overloads, for the given template parameter types and argument types
With this changes we replicate clang's overload resolution and template instantiation
Using `AddOverloadCandidate` over `AddMethodCandidate`
and `AddTemplateOverloadCandidate` over `AddMethodTemplateCandidate`
@Vipul-Cariappa Vipul-Cariappa force-pushed the dev/FindBestViableOverload branch from 7a235e1 to 323b5fc Compare March 9, 2025 10:35
@Vipul-Cariappa
Copy link
Collaborator Author

@mcbarton, I have fixed the CI problem. Now it looks like a code problem. Sorry, I should have read the error message properly before pinging you.


@vgvassilev, it looks like MSVC does not support Variable Length Array, reference: https://stackoverflow.com/a/33423538.
How to proceed?

@Vipul-Cariappa Vipul-Cariappa merged commit 59b7c11 into compiler-research:main Mar 9, 2025
49 of 73 checks passed
@Vipul-Cariappa Vipul-Cariappa deleted the dev/FindBestViableOverload branch March 9, 2025 14:59
Vipul-Cariappa added a commit to Vipul-Cariappa/cppyy-backend-compiler-research that referenced this pull request Mar 9, 2025
Vipul-Cariappa added a commit to compiler-research/cppyy-backend that referenced this pull request Mar 10, 2025
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.

2 participants