Skip to content

Commit f4949de

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 f4949de

File tree

2 files changed

+72
-20
lines changed

2 files changed

+72
-20
lines changed

include/clang/Interpreter/CppInterOp.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,27 @@ namespace Cpp {
416416
CPPINTEROP_API bool ExistsFunctionTemplate(const std::string& name,
417417
TCppScope_t parent = nullptr);
418418

419+
/// Sets a list of all the constructor for a scope/class that is
420+
/// supplied as a parameter.
421+
///\param[in] name - This string is used as a constraint, that clients can use
422+
/// to ensure the constructors match the name that they provide
423+
///\param[in] parent - Pointer to the scope/class for which the constructors
424+
/// are being looked up
425+
/// to be retrieved
426+
///\param[out] funcs - vector of handles to all constructors found under the
427+
/// given scope
428+
CPPINTEROP_API void LookupConstructors(const std::string& name,
429+
TCppScope_t parent,
430+
std::vector<TCppFunction_t>& funcs);
431+
419432
/// Sets a list of all the Templated Methods that are in the Class that is
420433
/// supplied as a parameter.
434+
///\returns true if the lookup succeeded, and false if there are no candidates
421435
///\param[in] name - method name
422436
///\param[in] parent - Pointer to the scope/class under which the methods have
423437
/// to be retrieved
424438
///\param[out] funcs - vector of function pointers matching the name
425-
CPPINTEROP_API void
439+
CPPINTEROP_API bool
426440
GetClassTemplatedMethods(const std::string& name, TCppScope_t parent,
427441
std::vector<TCppFunction_t>& funcs);
428442

lib/Interpreter/CppInterOp.cpp

+57-19
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,70 @@ 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+
for (auto* i : Result)
1057+
if (GetName(i) == name)
1058+
funcs.push_back(i);
1059+
}
1060+
}
10471061

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

1050-
llvm::StringRef Name(name);
1068+
// Accumulate constructors
1069+
LookupConstructors(name, parent, funcs);
10511070
auto& S = getSema();
1071+
D = GetUnderlyingScope(D);
1072+
llvm::StringRef Name(name);
10521073
DeclarationName DName = &getASTContext().Idents.get(name);
10531074
clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
10541075
For_Visible_Redeclaration);
1076+
auto* DC = clang::Decl::castToDeclContext(D);
1077+
Cpp_utils::Lookup::Named(&S, R, DC);
10551078

1056-
Cpp_utils::Lookup::Named(&S, R, Decl::castToDeclContext(D));
1057-
1058-
if (R.empty())
1059-
return;
1079+
if (R.getResultKind() == clang::LookupResult::NotFound && funcs.empty())
1080+
return false;
10601081

1061-
R.resolveKind();
1082+
// Distinct match, single Decl
1083+
else if (R.getResultKind() == clang::LookupResult::Found) {
1084+
if (IsTemplatedFunction(R.getFoundDecl()))
1085+
funcs.push_back(R.getFoundDecl());
1086+
}
1087+
// Loop over overload set
1088+
else if (R.getResultKind() == clang::LookupResult::FoundOverloaded) {
1089+
for (auto* Found : R)
1090+
if (IsTemplatedFunction(Found))
1091+
funcs.push_back(Found);
1092+
}
10621093

1063-
for (auto* Found : R)
1064-
if (llvm::isa<FunctionTemplateDecl>(Found))
1065-
funcs.push_back(Found);
1094+
// TODO: Handle ambiguously found LookupResult
1095+
// else if (R.getResultKind() == clang::LookupResult::Ambiguous) {
1096+
// auto kind = R.getAmbiguityKind();
1097+
// ...
1098+
// Produce a diagnostic describing the ambiguity that resulted
1099+
// from name lookup as done in Sema::DiagnoseAmbiguousLookup
1100+
//
1101+
return !funcs.empty();
10661102
}
10671103

10681104
// Adapted from inner workings of Sema::BuildCallExpr
@@ -1185,6 +1221,8 @@ namespace Cpp {
11851221
bool IsConstructor(TCppConstFunction_t method)
11861222
{
11871223
const auto* D = static_cast<const Decl*>(method);
1224+
if (const auto* FTD = dyn_cast<FunctionTemplateDecl>(D))
1225+
return IsConstructor(FTD->getTemplatedDecl());
11881226
return llvm::isa_and_nonnull<CXXConstructorDecl>(D);
11891227
}
11901228

0 commit comments

Comments
 (0)