Skip to content

Commit 695de6e

Browse files
author
Your Name
committed
Handle global function template called from a class scope
1 parent a43039a commit 695de6e

2 files changed

Lines changed: 100 additions & 14 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,22 +1906,37 @@ void TemplateSimplifier::deduceFunctionTemplateArguments()
19061906
tok = tok->tokAt(2);
19071907
}
19081908
if (tok->strAt(1) == "(") {
1909-
std::string fullName;
1910-
if (!qualification.empty())
1911-
fullName = qualification + " :: " + tok->str();
1912-
else if (!scopeName.empty())
1913-
fullName = scopeName + " :: " + tok->str();
1914-
else
1915-
fullName = tok->str();
1909+
const auto range = functionNameMap.equal_range(tok->str());
1910+
1911+
// a visible variable with the same name hides the function templates
1912+
ParsedType shadowingVariable;
1913+
if (range.first == range.second || ctx.symbols.lookupVariable(tok->str(), shadowingVariable))
1914+
continue;
19161915

1917-
// get all declarations with this name
1916+
// The name is looked up like the compiler does: in the
1917+
// enclosing scopes from the innermost outwards, where a match
1918+
// in an inner scope shadows declarations in outer scopes.
19181919
std::vector<const DeductionCandidate *> candidates;
1919-
const auto range = functionNameMap.equal_range(tok->str());
1920-
for (auto pos = range.first; pos != range.second; ++pos) {
1921-
// look for declaration with same qualification or constructor with same qualification
1922-
if (pos->second.declaration->fullName() == fullName ||
1923-
(pos->second.declaration->scope() == fullName && tok->str() == pos->second.declaration->name()))
1924-
candidates.push_back(&pos->second);
1920+
std::string scopePath = scopeName;
1921+
for (;;) {
1922+
std::string fullName;
1923+
if (!scopePath.empty())
1924+
fullName = scopePath + " :: ";
1925+
if (!qualification.empty())
1926+
fullName += qualification + " :: ";
1927+
fullName += tok->str();
1928+
1929+
for (auto pos = range.first; pos != range.second; ++pos) {
1930+
// look for declaration with same qualification or constructor with same qualification
1931+
if (pos->second.declaration->fullName() == fullName ||
1932+
(pos->second.declaration->scope() == fullName && tok->str() == pos->second.declaration->name()))
1933+
candidates.push_back(&pos->second);
1934+
}
1935+
if (!candidates.empty() || scopePath.empty())
1936+
break;
1937+
// no match: retry in the next outer scope
1938+
const std::string::size_type separator = scopePath.rfind(" :: ");
1939+
scopePath = (separator == std::string::npos) ? "" : scopePath.substr(0, separator);
19251940
}
19261941

19271942
if (!candidates.empty())

test/testsimplifytemplate.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class TestSimplifyTemplate : public TestFixture {
289289
TEST_CASE(templateTypeDeduction8); // deduction from expressions
290290
TEST_CASE(templateTypeDeduction9); // multiple parameters, scopes, bailouts
291291
TEST_CASE(templateTypeDeduction10); // parameter visibility: init list, const method
292+
TEST_CASE(templateTypeDeduction11); // unqualified lookup: enclosing scopes, shadowing
292293

293294
TEST_CASE(simplifyTemplateArgs1);
294295
TEST_CASE(simplifyTemplateArgs2);
@@ -6536,6 +6537,76 @@ class TestSimplifyTemplate : public TestFixture {
65366537
ASSERT_EQUALS("", errout_str());
65376538
}
65386539

6540+
void templateTypeDeduction11() { // unqualified lookup: enclosing scopes, shadowing
6541+
{
6542+
// global function template called from a class scope
6543+
const char code[] = "template<typename T> void f(T n) { (void)n; }\n"
6544+
"struct A {\n"
6545+
" int m;\n"
6546+
" A(long n) : m(0) { f(n); }\n"
6547+
" void g(float v) const { f(v); }\n"
6548+
"};";
6549+
const char exp[] = "void f<long> ( long n ) ; "
6550+
"void f<float> ( float n ) ; "
6551+
"struct A { "
6552+
"int m ; "
6553+
"A ( long n ) : m ( 0 ) { f<long> ( n ) ; } "
6554+
"void g ( float v ) const { f<float> ( v ) ; } "
6555+
"} ; "
6556+
"void f<long> ( long n ) { ( void ) n ; } "
6557+
"void f<float> ( float n ) { ( void ) n ; }";
6558+
ASSERT_EQUALS(exp, tok(code));
6559+
}
6560+
{
6561+
// global function template called from a class nested in a namespace
6562+
const char code[] = "template<typename T> T twice(T v) { return v + v; }\n"
6563+
"namespace N {\n"
6564+
" struct Inner {\n"
6565+
" long go(int a) { return twice(a); }\n"
6566+
" };\n"
6567+
"}";
6568+
const char exp[] = "int twice<int> ( int v ) ; "
6569+
"namespace N { "
6570+
"struct Inner { "
6571+
"long go ( int a ) { return twice<int> ( a ) ; } "
6572+
"} ; "
6573+
"} "
6574+
"int twice<int> ( int v ) { return v + v ; }";
6575+
ASSERT_EQUALS(exp, tok(code));
6576+
}
6577+
{
6578+
// a variable with the same name hides the function template
6579+
const char code[] = "template<typename T> void call(T v) { (void)v; }\n"
6580+
"struct Functor { void operator()(int) const {} };\n"
6581+
"void g() {\n"
6582+
" Functor call;\n"
6583+
" call(5);\n"
6584+
"}";
6585+
const char exp[] = "template < typename T > void call ( T v ) { ( void ) v ; } "
6586+
"struct Functor { void operator() ( int ) const { } } ; "
6587+
"void g ( ) { "
6588+
"Functor call ; "
6589+
"call . operator() ( 5 ) ; "
6590+
"}";
6591+
ASSERT_EQUALS(exp, tok(code));
6592+
}
6593+
{
6594+
// a member function template shadows a global function template
6595+
const char code[] = "template<typename T> void dup(T t) { (void)t; }\n"
6596+
"struct B {\n"
6597+
" template<typename T> void dup(T t) { (void)t; }\n"
6598+
" void m() { dup(1L); }\n"
6599+
"};";
6600+
const char exp[] = "template < typename T > void dup ( T t ) { ( void ) t ; } "
6601+
"struct B { "
6602+
"void dup<long> ( long t ) ; "
6603+
"void m ( ) { dup<long> ( 1L ) ; } "
6604+
"} ; "
6605+
"void B :: dup<long> ( long t ) { ( void ) t ; }";
6606+
ASSERT_EQUALS(exp, tok(code));
6607+
}
6608+
}
6609+
65396610
void simplifyTemplateArgs1() {
65406611
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 2 ) >;"));
65416612
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < 1 + 1 >;"));

0 commit comments

Comments
 (0)