Skip to content

Commit 222fd9c

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 f0f59f2 commit 222fd9c

File tree

2 files changed

+58
-19
lines changed

2 files changed

+58
-19
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 & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -978,9 +978,10 @@ namespace Cpp {
978978
// encompassed in an anonymous namespace as follows.
979979
namespace {
980980
bool IsTemplatedFunction(Decl *D) {
981-
if (llvm::isa_and_nonnull<FunctionTemplateDecl>(D))
982-
return true;
981+
return llvm::isa_and_nonnull<FunctionTemplateDecl>(D);
982+
}
983983

984+
bool IsTemplateInstantiationOrSpecialization(Decl* D) {
984985
if (auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
985986
auto TK = FD->getTemplatedKind();
986987
return TK == FunctionDecl::TemplatedKind::
@@ -1003,9 +1004,12 @@ namespace Cpp {
10031004
bool IsTemplatedFunction(TCppFunction_t func)
10041005
{
10051006
auto *D = (Decl *) func;
1006-
return IsTemplatedFunction(D);
1007+
return IsTemplatedFunction(D) || IsTemplateInstantiationOrSpecialization(D);
10071008
}
10081009

1010+
// FIXME: This lookup is broken, and should no longer be used in favour of
1011+
// `GetClassTemplatedMethods` If the candidate set returned is =1, that means
1012+
// the template function exists and >1 means overloads
10091013
bool ExistsFunctionTemplate(const std::string& name,
10101014
TCppScope_t parent)
10111015
{
@@ -1021,38 +1025,70 @@ namespace Cpp {
10211025
return false;
10221026

10231027
if ((intptr_t) ND != (intptr_t) -1)
1024-
return IsTemplatedFunction(ND);
1028+
return IsTemplatedFunction(ND) ||
1029+
IsTemplateInstantiationOrSpecialization(ND);
10251030

10261031
// FIXME: Cycle through the Decls and check if there is a templated function
10271032
return true;
10281033
}
10291034

1030-
void GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
1031-
std::vector<TCppFunction_t>& funcs) {
1035+
// Looks up all constructors in the current DeclContext
1036+
void LookupConstructors(const std::string& name, TCppScope_t parent,
1037+
std::vector<TCppFunction_t>& funcs) {
10321038

10331039
auto* D = (Decl*)parent;
10341040

1035-
if (!parent || name.empty())
1036-
return;
1041+
if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1042+
getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1043+
DeclContextLookupResult Result = getSema().LookupConstructors(CXXRD);
1044+
// Obtaining all constructors when we intend to lookup a method under a
1045+
// scope can lead to crashes. We avoid that by accumulating constructors
1046+
// only if the Decl matches the lookup name.
1047+
if (!Result.empty())
1048+
for (auto* i : Result)
1049+
if (GetName(i) == name)
1050+
funcs.push_back(i);
1051+
}
1052+
}
10371053

1038-
D = GetUnderlyingScope(D);
1054+
bool GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
1055+
std::vector<TCppFunction_t>& funcs) {
1056+
auto* D = (Decl*)parent;
1057+
if (!D && name.empty())
1058+
return false;
10391059

1040-
llvm::StringRef Name(name);
1060+
// Accumulate constructors
1061+
LookupConstructors(name, parent, funcs);
10411062
auto& S = getSema();
1063+
D = GetUnderlyingScope(D);
1064+
llvm::StringRef Name(name);
10421065
DeclarationName DName = &getASTContext().Idents.get(name);
10431066
clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
10441067
For_Visible_Redeclaration);
1068+
auto DC = clang::Decl::castToDeclContext(D);
1069+
Cpp_utils::Lookup::Named(&S, R, DC);
10451070

1046-
Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D));
1047-
1048-
if (R.empty())
1049-
return;
1071+
// Distinct match, single Decl
1072+
if (R.getResultKind() == clang::LookupResult::Found) {
1073+
funcs.push_back(R.getFoundDecl());
1074+
}
1075+
// Loop over overload set
1076+
else if (R.getResultKind() == clang::LookupResult::FoundOverloaded) {
1077+
for (auto* Found : R)
1078+
if (IsTemplatedFunction(Found))
1079+
funcs.push_back(Found);
1080+
}
10501081

1051-
R.resolveKind();
1082+
// Ambiguously found
1083+
// FIXME : if result not empty, add them anyway?
1084+
else {
1085+
if (!R.empty()) {
1086+
for (auto* Found : R)
1087+
funcs.push_back(Found);
1088+
}
1089+
}
10521090

1053-
for (auto* Found : R)
1054-
if (llvm::isa<FunctionTemplateDecl>(Found))
1055-
funcs.push_back(Found);
1091+
return !funcs.empty();
10561092
}
10571093

10581094
// Adapted from inner workings of Sema::BuildCallExpr
@@ -1175,6 +1211,8 @@ namespace Cpp {
11751211
bool IsConstructor(TCppConstFunction_t method)
11761212
{
11771213
const auto* D = static_cast<const Decl*>(method);
1214+
if (const auto* FTD = dyn_cast<FunctionTemplateDecl>(D))
1215+
return IsConstructor(FTD->getTemplatedDecl());
11781216
return llvm::isa_and_nonnull<CXXConstructorDecl>(D);
11791217
}
11801218

0 commit comments

Comments
 (0)