fix #10054 (debug: Executable scope 'x' with unknown function.) (#2994)

This commit is contained in:
IOBYTE 2020-12-30 02:09:34 -05:00 committed by GitHub
parent cb9efcb100
commit 277da763aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 240 additions and 2 deletions

View File

@ -3690,7 +3690,7 @@ void TemplateSimplifier::simplifyTemplates(
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
return;
if (passCount != 0 && mSettings->debugtemplate && mSettings->debugnormal) {
if (mSettings->debugtemplate && mSettings->debugnormal) {
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
}

View File

@ -1702,6 +1702,7 @@ namespace {
const Token * const bodyStart;
const Token * const bodyEnd;
std::set<std::string> usingNamespaces;
std::set<std::string> recordTypes;
};
std::string getScopeName(const std::list<ScopeInfo3> &scopeInfo)
@ -1778,12 +1779,16 @@ namespace {
return;
}
const bool record = Token::Match(tok, "class|struct|union %name%");
tok = tok->next();
std::string classname = tok->str();
while (Token::Match(tok, "%name% :: %name%")) {
tok = tok->tokAt(2);
classname += " :: " + tok->str();
}
// add record type to scope info
if (record)
scopeInfo->back().recordTypes.insert(classname);
tok = tok->next();
if (tok && tok->str() == ":") {
while (tok && !Token::Match(tok, ";|{"))
@ -1968,6 +1973,11 @@ bool Tokenizer::simplifyUsing()
// skip template declarations
if (Token::Match(tok, "template < !!>")) {
// add template record type to scope info
const Token *end = tok->next()->findClosingBracket();
if (end && Token::Match(end->next(), "class|struct|union %name%"))
scopeList.back().recordTypes.insert(end->strAt(2));
Token *endToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
if (endToken)
tok = endToken;
@ -2088,7 +2098,9 @@ bool Tokenizer::simplifyUsing()
// remove the qualification
std::string fullScope = scope;
std::string removed;
while (tok1->strAt(-1) == "::") {
removed = (tok1->strAt(-2) + " :: ") + removed;
if (fullScope == tok1->strAt(-2)) {
tok1->deletePrevious();
tok1->deletePrevious();
@ -2220,6 +2232,32 @@ bool Tokenizer::simplifyUsing()
substitute = true;
}
} else {
// add some qualification back if needed
std::string removed1 = removed;
std::string::size_type idx = removed1.rfind(" ::");
if (idx != std::string::npos)
removed1.resize(idx);
if (removed1 == scope && !removed1.empty()) {
for (std::list<ScopeInfo3>::const_reverse_iterator it = scopeList.crbegin(); it != scopeList.crend(); ++it) {
if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
std::string::size_type spaceIdx = 0;
std::string::size_type startIdx = 0;
while ((spaceIdx = removed1.find(" ", startIdx)) != std::string::npos) {
tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx).c_str());
startIdx = spaceIdx + 1;
}
tok1->previous()->insertToken(removed1.substr(startIdx).c_str());
tok1->previous()->insertToken("::");
break;
}
idx = removed1.rfind(" ::");
if (idx == std::string::npos)
break;
removed1.resize(idx);
}
}
// just replace simple type aliases
TokenList::copyTokens(tok1, start, usingEnd->previous());
tok1->deleteThis();

View File

@ -207,7 +207,7 @@ private:
TEST_CASE(template162);
TEST_CASE(template163); // #9685 syntax error
TEST_CASE(template164); // #9394
TEST_CASE(template162); // #10032 syntax error
TEST_CASE(template165); // #10032 syntax error
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)

View File

@ -76,6 +76,7 @@ private:
TEST_CASE(simplifyUsing9518);
TEST_CASE(simplifyUsing9757);
TEST_CASE(simplifyUsing10008);
TEST_CASE(simplifyUsing10054);
}
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
@ -663,6 +664,205 @@ private:
"}";
ASSERT_EQUALS(exp, tok(code, false));
}
void simplifyUsing10054() { // debug: Executable scope 'x' with unknown function.
{
// original example: using "namespace external::ns1;" but redundant qualification
const char code[] = "namespace external {\n"
" namespace ns1 {\n"
" template <int size> struct B { };\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"namespace ns {\n"
" struct A {\n"
" void f(external::ns1::V);\n"
" };\n"
"}\n"
"using namespace external::ns1;\n"
"namespace ns {\n"
" void A::f(external::ns1::V) {}\n"
"}";
const char exp[] = "namespace external { "
"namespace ns1 { "
"struct B<1> ; "
"} "
"} "
"namespace ns { "
"struct A { "
"void f ( external :: ns1 :: B<1> ) ; "
"} ; "
"} "
"using namespace external :: ns1 ; "
"namespace ns { "
"void A :: f ( external :: ns1 :: B<1> ) { } "
"} "
"struct external :: ns1 :: B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
{
// no using "namespace external::ns1;"
const char code[] = "namespace external {\n"
" namespace ns1 {\n"
" template <int size> struct B { };\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"namespace ns {\n"
" struct A {\n"
" void f(external::ns1::V);\n"
" };\n"
"}\n"
"namespace ns {\n"
" void A::f(external::ns1::V) {}\n"
"}";
const char exp[] = "namespace external { "
"namespace ns1 { "
"struct B<1> ; "
"} "
"} "
"namespace ns { "
"struct A { "
"void f ( external :: ns1 :: B<1> ) ; "
"} ; "
"} "
"namespace ns { "
"void A :: f ( external :: ns1 :: B<1> ) { } "
"} "
"struct external :: ns1 :: B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
{
// using "namespace external::ns1;" without redundant qualification
const char code[] = "namespace external {\n"
" namespace ns1 {\n"
" template <int size> struct B { };\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"namespace ns {\n"
" struct A {\n"
" void f(external::ns1::V);\n"
" };\n"
"}\n"
"using namespace external::ns1;\n"
"namespace ns {\n"
" void A::f(V) {}\n"
"}";
const char exp[] = "namespace external { "
"namespace ns1 { "
"struct B<1> ; "
"} "
"} "
"namespace ns { "
"struct A { "
"void f ( external :: ns1 :: B<1> ) ; "
"} ; "
"} "
"using namespace external :: ns1 ; "
"namespace ns { "
"void A :: f ( external :: ns1 :: B<1> ) { } "
"} "
"struct external :: ns1 :: B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
{
// using "namespace external::ns1;" without redundant qualification on declaration and definition
const char code[] = "namespace external {\n"
" namespace ns1 {\n"
" template <int size> struct B { };\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"using namespace external::ns1;\n"
"namespace ns {\n"
" struct A {\n"
" void f(V);\n"
" };\n"
"}\n"
"namespace ns {\n"
" void A::f(V) {}\n"
"}";
const char exp[] = "namespace external { "
"namespace ns1 { "
"struct B<1> ; "
"} "
"} "
"using namespace external :: ns1 ; "
"namespace ns { "
"struct A { "
"void f ( external :: ns1 :: B<1> ) ; "
"} ; "
"} "
"namespace ns { "
"void A :: f ( external :: ns1 :: B<1> ) { } "
"} "
"struct external :: ns1 :: B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
{
const char code[] = "namespace external {\n"
" template <int size> struct B { };\n"
" namespace ns1 {\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"namespace ns {\n"
" struct A {\n"
" void f(external::ns1::V);\n"
" };\n"
"}\n"
"namespace ns {\n"
" void A::f(external::ns1::V) {}\n"
"}";
const char exp[] = "namespace external { "
"struct B<1> ; "
"} "
"namespace ns { "
"struct A { "
"void f ( external :: B<1> ) ; "
"} ; "
"} "
"namespace ns { "
"void A :: f ( external :: B<1> ) { } "
"} "
"struct external :: B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
{
const char code[] = "template <int size> struct B { };\n"
"namespace external {\n"
" namespace ns1 {\n"
" using V = B<sizeof(bool)>;\n"
" }\n"
"}\n"
"namespace ns {\n"
" struct A {\n"
" void f(external::ns1::V);\n"
" };\n"
"}\n"
"namespace ns {\n"
" void A::f(external::ns1::V) {}\n"
"}";
const char exp[] = "struct B<1> ; "
"namespace ns { "
"struct A { "
"void f ( B<1> ) ; "
"} ; "
"} "
"namespace ns { "
"void A :: f ( B<1> ) { } "
"} "
"struct B<1> { } ;";
ASSERT_EQUALS(exp, tok(code, true));
ASSERT_EQUALS("", errout.str());
}
}
};
REGISTER_TEST(TestSimplifyUsing)