Skip to content

Commit b4e404c

Browse files
Add BestOverloadFunctionMatch & IsFunction Remove BestTemplateFunctionMatch
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
1 parent 7caf10b commit b4e404c

File tree

3 files changed

+334
-66
lines changed

3 files changed

+334
-66
lines changed

include/clang/Interpreter/CppInterOp.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ namespace Cpp {
210210
/// Checks if the scope is a class or not.
211211
CPPINTEROP_API bool IsClass(TCppScope_t scope);
212212

213+
/// Checks if the scope is a function.
214+
CPPINTEROP_API bool IsFunction(TCppScope_t scope);
215+
213216
/// Checks if the type is a function pointer.
214217
CPPINTEROP_API bool IsFunctionPointerType(TCppType_t type);
215218

@@ -706,17 +709,16 @@ namespace Cpp {
706709
CPPINTEROP_API TCppFunction_t
707710
InstantiateTemplateFunctionFromString(const char* function_template);
708711

709-
/// Finds best template match based on explicit template parameters and
710-
/// argument types
712+
/// Finds best overload match based on explicit template parameters (if any)
713+
/// and argument types.
711714
///
712-
///\param[in] candidates - Vector of suitable candidates that come under the
713-
/// parent scope and have the same name (obtained using
714-
/// GetClassTemplatedMethods)
715+
///\param[in] candidates - vector of overloads that come under the
716+
/// parent scope and have the same name
715717
///\param[in] explicit_types - set of expicitly instantiated template types
716718
///\param[in] arg_types - set of argument types
717719
///\returns Instantiated function pointer
718720
CPPINTEROP_API TCppFunction_t
719-
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
721+
BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates,
720722
const std::vector<TemplateArgInfo>& explicit_types,
721723
const std::vector<TemplateArgInfo>& arg_types);
722724

lib/Interpreter/CppInterOp.cpp

Lines changed: 93 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,29 @@
1313

1414
#include "clang/AST/CXXInheritance.h"
1515
#include "clang/AST/Decl.h"
16+
#include "clang/AST/DeclAccessPair.h"
17+
#include "clang/AST/DeclBase.h"
1618
#include "clang/AST/DeclCXX.h"
19+
#include "clang/AST/DeclarationName.h"
20+
#include "clang/AST/Expr.h"
21+
#include "clang/AST/ExprCXX.h"
1722
#include "clang/AST/GlobalDecl.h"
1823
#include "clang/AST/Mangle.h"
24+
#include "clang/AST/NestedNameSpecifier.h"
1925
#include "clang/AST/QualTypeNames.h"
2026
#include "clang/AST/RecordLayout.h"
27+
#include "clang/AST/Stmt.h"
28+
#include "clang/AST/Type.h"
2129
#include "clang/Basic/DiagnosticSema.h"
2230
#include "clang/Basic/Linkage.h"
31+
#include "clang/Basic/OperatorKinds.h"
32+
#include "clang/Basic/SourceLocation.h"
33+
#include "clang/Basic/Specifiers.h"
2334
#include "clang/Basic/Version.h"
2435
#include "clang/Frontend/CompilerInstance.h"
2536
#include "clang/Sema/Lookup.h"
37+
#include "clang/Sema/Overload.h"
38+
#include "clang/Sema/Ownership.h"
2639
#include "clang/Sema/Sema.h"
2740
#if CLANG_VERSION_MAJOR >= 19
2841
#include "clang/Sema/Redeclaration.h"
@@ -210,6 +223,11 @@ namespace Cpp {
210223
return isa<CXXRecordDecl>(D);
211224
}
212225

226+
bool IsFunction(TCppScope_t scope) {
227+
Decl* D = static_cast<Decl*>(scope);
228+
return isa<FunctionDecl>(D);
229+
}
230+
213231
bool IsFunctionPointerType(TCppType_t type) {
214232
QualType QT = QualType::getFromOpaquePtr(type);
215233
return QT->isFunctionPointerType();
@@ -877,8 +895,19 @@ namespace Cpp {
877895
TCppType_t GetFunctionReturnType(TCppFunction_t func)
878896
{
879897
auto *D = (clang::Decl *) func;
880-
if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
881-
return FD->getReturnType().getAsOpaquePtr();
898+
if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
899+
QualType Type = FD->getReturnType();
900+
if (Type->isUndeducedAutoType() && IsTemplatedFunction(FD) &&
901+
!FD->isDefined()) {
902+
#ifdef CPPINTEROP_USE_CLING
903+
cling::Interpreter::PushTransactionRAII RAII(&I);
904+
#endif
905+
getSema().InstantiateFunctionDefinition(SourceLocation(), FD, true,
906+
true);
907+
Type = FD->getReturnType();
908+
}
909+
return Type.getAsOpaquePtr();
910+
}
882911

883912
if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
884913
return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr();
@@ -1027,61 +1056,74 @@ namespace Cpp {
10271056
}
10281057

10291058
TCppFunction_t
1030-
BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates,
1059+
BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates,
10311060
const std::vector<TemplateArgInfo>& explicit_types,
10321061
const std::vector<TemplateArgInfo>& arg_types) {
1062+
auto& S = getSema();
1063+
auto& C = S.getASTContext();
10331064

1034-
for (const auto& candidate : candidates) {
1035-
auto* TFD = (FunctionTemplateDecl*)candidate;
1036-
clang::TemplateParameterList* tpl = TFD->getTemplateParameters();
1037-
1038-
// template parameter size does not match
1039-
if (tpl->size() < explicit_types.size())
1040-
continue;
1041-
1042-
// right now uninstantiated functions give template typenames instead of
1043-
// actual types. We make this match solely based on count
1044-
1045-
const FunctionDecl* func = TFD->getTemplatedDecl();
1065+
llvm::SmallVector<Expr*> Args;
1066+
for (auto i : arg_types) {
1067+
QualType Type = QualType::getFromOpaquePtr(i.m_Type);
1068+
ExprValueKind ExprKind = ExprValueKind::VK_PRValue;
1069+
if (Type->isReferenceType())
1070+
ExprKind = ExprValueKind::VK_LValue;
1071+
Args.push_back(new (getSema().getASTContext())
1072+
OpaqueValueExpr(SourceLocation::getFromRawEncoding(1),
1073+
Type.getNonReferenceType(), ExprKind));
1074+
}
10461075

1047-
#ifdef CPPINTEROP_USE_CLING
1048-
if (func->getNumParams() > arg_types.size())
1049-
continue;
1050-
#else // CLANG_REPL
1051-
if (func->getMinRequiredArguments() > arg_types.size())
1052-
continue;
1053-
#endif
1076+
// Create a list of template arguments.
1077+
llvm::SmallVector<TemplateArgument> TemplateArgs;
1078+
TemplateArgs.reserve(explicit_types.size());
1079+
for (auto explicit_type : explicit_types) {
1080+
QualType ArgTy = QualType::getFromOpaquePtr(explicit_type.m_Type);
1081+
if (explicit_type.m_IntegralValue) {
1082+
// We have a non-type template parameter. Create an integral value from
1083+
// the string representation.
1084+
auto Res = llvm::APSInt(explicit_type.m_IntegralValue);
1085+
Res = Res.extOrTrunc(C.getIntWidth(ArgTy));
1086+
TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy));
1087+
} else {
1088+
TemplateArgs.push_back(ArgTy);
1089+
}
1090+
}
10541091

1055-
// TODO(aaronj0) : first score based on the type similarity before forcing
1056-
// instantiation.
1057-
1058-
TCppFunction_t instantiated =
1059-
InstantiateTemplate(candidate, arg_types.data(), arg_types.size());
1060-
if (instantiated)
1061-
return instantiated;
1062-
1063-
// Force the instantiation with template params in case of no args
1064-
// maybe steer instantiation better with arg set returned from
1065-
// TemplateProxy?
1066-
instantiated = InstantiateTemplate(candidate, explicit_types.data(),
1067-
explicit_types.size());
1068-
if (instantiated)
1069-
return instantiated;
1070-
1071-
// join explicit and arg_types
1072-
std::vector<TemplateArgInfo> total_arg_set;
1073-
total_arg_set.reserve(explicit_types.size() + arg_types.size());
1074-
total_arg_set.insert(total_arg_set.end(), explicit_types.begin(),
1075-
explicit_types.end());
1076-
total_arg_set.insert(total_arg_set.end(), arg_types.begin(),
1077-
arg_types.end());
1078-
1079-
instantiated = InstantiateTemplate(candidate, total_arg_set.data(),
1080-
total_arg_set.size());
1081-
if (instantiated)
1082-
return instantiated;
1092+
TemplateArgumentListInfo TLI{};
1093+
for (auto TA : TemplateArgs)
1094+
TLI.addArgument(
1095+
S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
1096+
1097+
OverloadCandidateSet Overloads(
1098+
SourceLocation(), OverloadCandidateSet::CandidateSetKind::CSK_Normal);
1099+
for (void* i : candidates) {
1100+
Decl* D = static_cast<Decl*>(i);
1101+
if (auto* MD = dyn_cast<CXXMethodDecl>(D)) {
1102+
S.AddMethodCandidate(
1103+
MD, DeclAccessPair::make(MD, MD->getAccess()), MD->getParent(),
1104+
C.getTypeDeclType(MD->getParent()),
1105+
Expr::Classification::makeSimpleLValue(), Args, Overloads);
1106+
} else if (auto* FD = dyn_cast<FunctionDecl>(D)) {
1107+
S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()),
1108+
Args, Overloads);
1109+
} else if (auto* FTD = dyn_cast<FunctionTemplateDecl>(D)) {
1110+
if (auto* CXXRD =
1111+
dyn_cast<CXXRecordDecl>(FTD->getTemplatedDecl()->getParent())) {
1112+
S.AddMethodTemplateCandidate(
1113+
FTD, DeclAccessPair::make(FTD, FTD->getAccess()), CXXRD, &TLI,
1114+
C.getTypeDeclType(CXXRD),
1115+
Expr::Classification::makeSimpleLValue(), Args, Overloads);
1116+
} else {
1117+
S.AddTemplateOverloadCandidate(
1118+
FTD, DeclAccessPair::make(FTD, FTD->getAccess()), &TLI, Args,
1119+
Overloads);
1120+
}
1121+
}
10831122
}
1084-
return nullptr;
1123+
OverloadCandidateSet::iterator Best;
1124+
Overloads.BestViableFunction(S, SourceLocation(), Best);
1125+
1126+
return Best != Overloads.end() ? Best->Function : nullptr;
10851127
}
10861128

10871129
// Gets the AccessSpecifier of the function and checks if it is equal to

0 commit comments

Comments
 (0)