Skip to content

Commit 82691dc

Browse files
committed
Add LookupConstructors and fix logic in IsConstructor for templates
Also splits IsTemplatedFunction into `IsTemplatedFunction` for FunctionTemplateDecl, and `IsTemplateInstantiationOrSpecialization` when we have an instantiation or a specialization. Accumulate constructors with the new lookup in `GetClassTemplatedMethods` enabling 8 tests.
1 parent a9a865e commit 82691dc

File tree

2 files changed

+58
-20
lines changed

2 files changed

+58
-20
lines changed

include/clang/Interpreter/CppInterOp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,11 +418,12 @@ namespace Cpp {
418418

419419
/// Sets a list of all the Templated Methods that are in the Class that is
420420
/// supplied as a parameter.
421+
///\returns true if the lookup succeeded, and false if there are no candidates
421422
///\param[in] name - method name
422423
///\param[in] parent - Pointer to the scope/class under which the methods have
423424
/// to be retrieved
424425
///\param[out] funcs - vector of function pointers matching the name
425-
CPPINTEROP_API void
426+
CPPINTEROP_API bool
426427
GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
427428
std::vector<TCppFunction_t>& funcs);
428429

lib/Interpreter/CppInterOp.cpp

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -988,9 +988,10 @@ namespace Cpp {
988988
// encompassed in an anonymous namespace as follows.
989989
namespace {
990990
bool IsTemplatedFunction(Decl *D) {
991-
if (llvm::isa_and_nonnull<FunctionTemplateDecl>(D))
992-
return true;
991+
return llvm::isa_and_nonnull<FunctionTemplateDecl>(D);
992+
}
993993

994+
bool IsTemplateInstantiationOrSpecialization(Decl* D) {
994995
if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
995996
auto TK = FD->getTemplatedKind();
996997
return TK == FunctionDecl::TemplatedKind::
@@ -1013,9 +1014,12 @@ namespace Cpp {
10131014
bool IsTemplatedFunction(TCppFunction_t func)
10141015
{
10151016
auto *D = (Decl *) func;
1016-
return IsTemplatedFunction(D);
1017+
return IsTemplatedFunction(D) || IsTemplateInstantiationOrSpecialization(D);
10171018
}
10181019

1020+
// FIXME: This lookup is broken, and should no longer be used in favour of
1021+
// `GetClassTemplatedMethods` If the candidate set returned is =1, that means
1022+
// the template function exists and >1 means overloads
10191023
bool ExistsFunctionTemplate(const std::string& name,
10201024
TCppScope_t parent)
10211025
{
@@ -1031,38 +1035,69 @@ namespace Cpp {
10311035
return false;
10321036

10331037
if ((intptr_t) ND != (intptr_t) -1)
1034-
return IsTemplatedFunction(ND);
1038+
return IsTemplatedFunction(ND) ||
1039+
IsTemplateInstantiationOrSpecialization(ND);
10351040

10361041
// FIXME: Cycle through the Decls and check if there is a templated function
10371042
return true;
10381043
}
10391044

1040-
void GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
1041-
std::vector<TCppFunction_t>& funcs) {
1042-
1045+
// Looks up all constructors in the current DeclContext
1046+
void LookupConstructors(const std::string& name, TCppScope_t parent,
1047+
std::vector<TCppFunction_t>& funcs) {
10431048
auto* D = (Decl*)parent;
10441049

1045-
if (!parent || name.empty())
1046-
return;
1050+
if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1051+
getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1052+
DeclContextLookupResult Result = getSema().LookupConstructors(CXXRD);
1053+
// Obtaining all constructors when we intend to lookup a method under a
1054+
// scope can lead to crashes. We avoid that by accumulating constructors
1055+
// only if the Decl matches the lookup name.
1056+
if (!Result.empty())
1057+
for (auto* i : Result)
1058+
if (GetName(i) == name)
1059+
funcs.push_back(i);
1060+
}
1061+
}
10471062

1048-
D = GetUnderlyingScope(D);
1063+
bool GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
1064+
std::vector<TCppFunction_t>& funcs) {
1065+
auto* D = (Decl*)parent;
1066+
if (!D && name.empty())
1067+
return false;
10491068

1050-
llvm::StringRef Name(name);
1069+
// Accumulate constructors
1070+
LookupConstructors(name, parent, funcs);
10511071
auto& S = getSema();
1072+
D = GetUnderlyingScope(D);
1073+
llvm::StringRef Name(name);
10521074
DeclarationName DName = &getASTContext().Idents.get(name);
10531075
clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
10541076
For_Visible_Redeclaration);
1077+
auto* DC = clang::Decl::castToDeclContext(D);
1078+
Cpp_utils::Lookup::Named(&S, R, DC);
10551079

1056-
Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D));
1057-
1058-
if (R.empty())
1059-
return;
1080+
// Distinct match, single Decl
1081+
if (R.getResultKind() == clang::LookupResult::Found) {
1082+
funcs.push_back(R.getFoundDecl());
1083+
}
1084+
// Loop over overload set
1085+
else if (R.getResultKind() == clang::LookupResult::FoundOverloaded) {
1086+
for (auto* Found : R)
1087+
if (IsTemplatedFunction(Found))
1088+
funcs.push_back(Found);
1089+
}
10601090

1061-
R.resolveKind();
1091+
// Ambiguously found
1092+
// FIXME : if result not empty, add them anyway?
1093+
else {
1094+
if (!R.empty()) {
1095+
for (auto* Found : R)
1096+
funcs.push_back(Found);
1097+
}
1098+
}
10621099

1063-
for (auto* Found : R)
1064-
if (llvm::isa<FunctionTemplateDecl>(Found))
1065-
funcs.push_back(Found);
1100+
return !funcs.empty();
10661101
}
10671102

10681103
// Adapted from inner workings of Sema::BuildCallExpr
@@ -1185,6 +1220,8 @@ namespace Cpp {
11851220
bool IsConstructor(TCppConstFunction_t method)
11861221
{
11871222
const auto* D = static_cast<const Decl*>(method);
1223+
if (const auto* FTD = dyn_cast<FunctionTemplateDecl>(D))
1224+
return IsConstructor(FTD->getTemplatedDecl());
11881225
return llvm::isa_and_nonnull<CXXConstructorDecl>(D);
11891226
}
11901227

0 commit comments

Comments
 (0)