|
13 | 13 |
|
14 | 14 | #include "clang/AST/CXXInheritance.h"
|
15 | 15 | #include "clang/AST/Decl.h"
|
| 16 | +#include "clang/AST/DeclAccessPair.h" |
| 17 | +#include "clang/AST/DeclBase.h" |
16 | 18 | #include "clang/AST/DeclCXX.h"
|
| 19 | +#include "clang/AST/DeclarationName.h" |
| 20 | +#include "clang/AST/Expr.h" |
| 21 | +#include "clang/AST/ExprCXX.h" |
17 | 22 | #include "clang/AST/GlobalDecl.h"
|
18 | 23 | #include "clang/AST/Mangle.h"
|
| 24 | +#include "clang/AST/NestedNameSpecifier.h" |
19 | 25 | #include "clang/AST/QualTypeNames.h"
|
20 | 26 | #include "clang/AST/RecordLayout.h"
|
| 27 | +#include "clang/AST/Stmt.h" |
| 28 | +#include "clang/AST/Type.h" |
21 | 29 | #include "clang/Basic/DiagnosticSema.h"
|
22 | 30 | #include "clang/Basic/Linkage.h"
|
| 31 | +#include "clang/Basic/OperatorKinds.h" |
| 32 | +#include "clang/Basic/SourceLocation.h" |
| 33 | +#include "clang/Basic/Specifiers.h" |
23 | 34 | #include "clang/Basic/Version.h"
|
24 | 35 | #include "clang/Frontend/CompilerInstance.h"
|
25 | 36 | #include "clang/Sema/Lookup.h"
|
| 37 | +#include "clang/Sema/Overload.h" |
| 38 | +#include "clang/Sema/Ownership.h" |
26 | 39 | #include "clang/Sema/Sema.h"
|
27 | 40 | #if CLANG_VERSION_MAJOR >= 19
|
28 | 41 | #include "clang/Sema/Redeclaration.h"
|
@@ -210,6 +223,11 @@ namespace Cpp {
|
210 | 223 | return isa<CXXRecordDecl>(D);
|
211 | 224 | }
|
212 | 225 |
|
| 226 | + bool IsFunction(TCppScope_t scope) { |
| 227 | + Decl* D = static_cast<Decl*>(scope); |
| 228 | + return isa<FunctionDecl>(D); |
| 229 | + } |
| 230 | + |
213 | 231 | bool IsFunctionPointerType(TCppType_t type) {
|
214 | 232 | QualType QT = QualType::getFromOpaquePtr(type);
|
215 | 233 | return QT->isFunctionPointerType();
|
@@ -877,8 +895,19 @@ namespace Cpp {
|
877 | 895 | TCppType_t GetFunctionReturnType(TCppFunction_t func)
|
878 | 896 | {
|
879 | 897 | 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(&getInterp()); |
| 904 | +#endif |
| 905 | + getSema().InstantiateFunctionDefinition(SourceLocation(), FD, true, |
| 906 | + true); |
| 907 | + Type = FD->getReturnType(); |
| 908 | + } |
| 909 | + return Type.getAsOpaquePtr(); |
| 910 | + } |
882 | 911 |
|
883 | 912 | if (auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
|
884 | 913 | return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr();
|
@@ -1026,62 +1055,89 @@ namespace Cpp {
|
1026 | 1055 | funcs.push_back(Found);
|
1027 | 1056 | }
|
1028 | 1057 |
|
| 1058 | + // Adapted from inner workings of Sema::BuildCallExpr |
1029 | 1059 | TCppFunction_t
|
1030 |
| - BestTemplateFunctionMatch(const std::vector<TCppFunction_t>& candidates, |
| 1060 | + BestOverloadFunctionMatch(const std::vector<TCppFunction_t>& candidates, |
1031 | 1061 | const std::vector<TemplateArgInfo>& explicit_types,
|
1032 | 1062 | const std::vector<TemplateArgInfo>& arg_types) {
|
| 1063 | + auto& S = getSema(); |
| 1064 | + auto& C = S.getASTContext(); |
1033 | 1065 |
|
1034 |
| - for (const auto& candidate : candidates) { |
1035 |
| - auto* TFD = (FunctionTemplateDecl*)candidate; |
1036 |
| - clang::TemplateParameterList* tpl = TFD->getTemplateParameters(); |
| 1066 | +#ifdef CPPINTEROP_USE_CLING |
| 1067 | + cling::Interpreter::PushTransactionRAII RAII(&getInterp()); |
| 1068 | +#endif |
1037 | 1069 |
|
1038 |
| - // template parameter size does not match |
1039 |
| - if (tpl->size() < explicit_types.size()) |
1040 |
| - continue; |
| 1070 | + // The overload resolution interfaces in Sema require a list of expressions. |
| 1071 | + // However, unlike handwritten C++, we do not always have a expression. |
| 1072 | + // Here we synthesize a placeholder expression to be able to use |
| 1073 | + // Sema::AddOverloadCandidate. Made up expressions are fine because the |
| 1074 | + // interface uses the list size and the expression types. |
| 1075 | + struct WrapperExpr : public OpaqueValueExpr { |
| 1076 | + WrapperExpr() : OpaqueValueExpr(clang::Stmt::EmptyShell()) {} |
| 1077 | + }; |
| 1078 | + auto* Exprs = new WrapperExpr[arg_types.size()]; |
| 1079 | + llvm::SmallVector<Expr*> Args; |
| 1080 | + Args.reserve(arg_types.size()); |
| 1081 | + size_t idx = 0; |
| 1082 | + for (auto i : arg_types) { |
| 1083 | + QualType Type = QualType::getFromOpaquePtr(i.m_Type); |
| 1084 | + ExprValueKind ExprKind = ExprValueKind::VK_PRValue; |
| 1085 | + if (Type->isReferenceType()) |
| 1086 | + ExprKind = ExprValueKind::VK_LValue; |
| 1087 | + |
| 1088 | + new (&Exprs[idx]) OpaqueValueExpr(SourceLocation::getFromRawEncoding(1), |
| 1089 | + Type.getNonReferenceType(), ExprKind); |
| 1090 | + Args.push_back(&Exprs[idx]); |
| 1091 | + ++idx; |
| 1092 | + } |
1041 | 1093 |
|
1042 |
| - // right now uninstantiated functions give template typenames instead of |
1043 |
| - // actual types. We make this match solely based on count |
| 1094 | + // Create a list of template arguments. |
| 1095 | + llvm::SmallVector<TemplateArgument> TemplateArgs; |
| 1096 | + TemplateArgs.reserve(explicit_types.size()); |
| 1097 | + for (auto explicit_type : explicit_types) { |
| 1098 | + QualType ArgTy = QualType::getFromOpaquePtr(explicit_type.m_Type); |
| 1099 | + if (explicit_type.m_IntegralValue) { |
| 1100 | + // We have a non-type template parameter. Create an integral value from |
| 1101 | + // the string representation. |
| 1102 | + auto Res = llvm::APSInt(explicit_type.m_IntegralValue); |
| 1103 | + Res = Res.extOrTrunc(C.getIntWidth(ArgTy)); |
| 1104 | + TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy)); |
| 1105 | + } else { |
| 1106 | + TemplateArgs.push_back(ArgTy); |
| 1107 | + } |
| 1108 | + } |
1044 | 1109 |
|
1045 |
| - const FunctionDecl* func = TFD->getTemplatedDecl(); |
| 1110 | + TemplateArgumentListInfo ExplicitTemplateArgs{}; |
| 1111 | + for (auto TA : TemplateArgs) |
| 1112 | + ExplicitTemplateArgs.addArgument( |
| 1113 | + S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation())); |
| 1114 | + |
| 1115 | + OverloadCandidateSet Overloads( |
| 1116 | + SourceLocation(), OverloadCandidateSet::CandidateSetKind::CSK_Normal); |
| 1117 | + |
| 1118 | + for (void* i : candidates) { |
| 1119 | + Decl* D = static_cast<Decl*>(i); |
| 1120 | + if (auto* FD = dyn_cast<FunctionDecl>(D)) { |
| 1121 | + S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()), |
| 1122 | + Args, Overloads); |
| 1123 | + } else if (auto* FTD = dyn_cast<FunctionTemplateDecl>(D)) { |
| 1124 | + // AddTemplateOverloadCandidate is causing a memory leak |
| 1125 | + // It is a known bug at clang |
| 1126 | + // call stack: AddTemplateOverloadCandidate -> MakeDeductionFailureInfo |
| 1127 | + // source: |
| 1128 | + // https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L731-L756 |
| 1129 | + S.AddTemplateOverloadCandidate( |
| 1130 | + FTD, DeclAccessPair::make(FTD, FTD->getAccess()), |
| 1131 | + &ExplicitTemplateArgs, Args, Overloads); |
| 1132 | + } |
| 1133 | + } |
1046 | 1134 |
|
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 |
| 1135 | + OverloadCandidateSet::iterator Best; |
| 1136 | + Overloads.BestViableFunction(S, SourceLocation(), Best); |
1054 | 1137 |
|
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; |
1083 |
| - } |
1084 |
| - return nullptr; |
| 1138 | + FunctionDecl* Result = Best != Overloads.end() ? Best->Function : nullptr; |
| 1139 | + delete[] Exprs; |
| 1140 | + return Result; |
1085 | 1141 | }
|
1086 | 1142 |
|
1087 | 1143 | // Gets the AccessSpecifier of the function and checks if it is equal to
|
|
0 commit comments