* Fixed #8971 ("(debug) Unknown type 'x'." using alias in class members) * template simplifier: partial fix for #8972 Add support for multi-token default template parameters. * template simplifier: fix for #8971 Remove typename outside of templates.
This commit is contained in:
parent
851b537d15
commit
155e4ce912
|
@ -2415,6 +2415,10 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||||
getTemplateParametersInDeclaration(forwardDecl.token->tokAt(2), params1);
|
getTemplateParametersInDeclaration(forwardDecl.token->tokAt(2), params1);
|
||||||
|
|
||||||
for (auto & decl : mTemplateDeclarations) {
|
for (auto & decl : mTemplateDeclarations) {
|
||||||
|
// skip partializations
|
||||||
|
if (decl.isPartialSpecialization())
|
||||||
|
continue;
|
||||||
|
|
||||||
std::vector<const Token *> params2;
|
std::vector<const Token *> params2;
|
||||||
|
|
||||||
getTemplateParametersInDeclaration(decl.token->tokAt(2), params2);
|
getTemplateParametersInDeclaration(decl.token->tokAt(2), params2);
|
||||||
|
@ -2432,8 +2436,18 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||||
for (size_t k = 0; k < params1.size(); k++) {
|
for (size_t k = 0; k < params1.size(); k++) {
|
||||||
// copy default value to declaration if not present
|
// copy default value to declaration if not present
|
||||||
if (params1[k]->strAt(1) == "=" && params2[k]->strAt(1) != "=") {
|
if (params1[k]->strAt(1) == "=" && params2[k]->strAt(1) != "=") {
|
||||||
const_cast<Token *>(params2[k])->insertToken(params1[k]->strAt(2));
|
int level = 0;
|
||||||
const_cast<Token *>(params2[k])->insertToken(params1[k]->strAt(1));
|
const Token *end = params1[k]->next();
|
||||||
|
while (end && !(level == 0 && Token::Match(end, ",|>"))) {
|
||||||
|
if (Token::Match(end, "{|(|<"))
|
||||||
|
level++;
|
||||||
|
else if (Token::Match(end, "}|)|>"))
|
||||||
|
level--;
|
||||||
|
end = end->next();
|
||||||
|
}
|
||||||
|
if (end)
|
||||||
|
TokenList::copyTokens(const_cast<Token *>(params2[k]), params1[k]->next(), end->previous());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2629,6 +2643,97 @@ static Token *findSemicolon(Token *tok)
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool usingMatch(
|
||||||
|
const Token *nameToken,
|
||||||
|
const std::string &scope,
|
||||||
|
Token **tok,
|
||||||
|
const std::string &scope1,
|
||||||
|
const std::list<ScopeInfo2> &scopeList1)
|
||||||
|
{
|
||||||
|
Token *tok1 = *tok;
|
||||||
|
|
||||||
|
if (tok1 && tok1->str() != nameToken->str())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// skip this using
|
||||||
|
if (tok1 == nameToken) {
|
||||||
|
*tok = findSemicolon(tok1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip other using with this name
|
||||||
|
if (tok1->strAt(-1) == "using") {
|
||||||
|
// fixme: this is wrong
|
||||||
|
// skip to end of scope
|
||||||
|
if (scopeList1.back().bodyEnd)
|
||||||
|
*tok = scopeList1.back().bodyEnd->previous();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok1->tokAt(-1), "struct|union|enum")) {
|
||||||
|
// fixme
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get qualification
|
||||||
|
std::string qualification;
|
||||||
|
const Token* tok2 = tok1;
|
||||||
|
std::string::size_type index = scope.size();
|
||||||
|
std::string::size_type new_index = std::string::npos;
|
||||||
|
bool match = true;
|
||||||
|
while (tok2->strAt(-1) == "::") {
|
||||||
|
std::string last;
|
||||||
|
if (match && !scope1.empty()) {
|
||||||
|
new_index = scope1.rfind(' ', index - 1);
|
||||||
|
if (new_index != std::string::npos)
|
||||||
|
last = scope1.substr(new_index, index - new_index);
|
||||||
|
else if (!qualification.empty())
|
||||||
|
last.clear();
|
||||||
|
else
|
||||||
|
last = scope1;
|
||||||
|
} else
|
||||||
|
match = false;
|
||||||
|
if (match && tok2->strAt(-2) == last)
|
||||||
|
index = new_index;
|
||||||
|
else {
|
||||||
|
if (!qualification.empty())
|
||||||
|
qualification = " :: " + qualification;
|
||||||
|
qualification = tok2->strAt(-2) + qualification;
|
||||||
|
}
|
||||||
|
tok2 = tok2->tokAt(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: check using namespace
|
||||||
|
std::string fullScope1 = scope1;
|
||||||
|
if (!scope1.empty() && !qualification.empty())
|
||||||
|
fullScope1 += " :: ";
|
||||||
|
fullScope1 += qualification;
|
||||||
|
|
||||||
|
if (scope == fullScope1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string newScope1 = scope1;
|
||||||
|
|
||||||
|
// scopes didn't match so try higher scopes
|
||||||
|
while (!newScope1.empty()) {
|
||||||
|
std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
|
||||||
|
if (separator != std::string::npos)
|
||||||
|
newScope1 = newScope1.substr(0, separator);
|
||||||
|
else
|
||||||
|
newScope1.clear();
|
||||||
|
|
||||||
|
std::string newFullScope1 = newScope1;
|
||||||
|
if (!newScope1.empty() && !qualification.empty())
|
||||||
|
newFullScope1 += " :: ";
|
||||||
|
newFullScope1 += qualification;
|
||||||
|
|
||||||
|
if (scope == newFullScope1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TemplateSimplifier::simplifyUsing()
|
bool TemplateSimplifier::simplifyUsing()
|
||||||
{
|
{
|
||||||
bool substitute = false;
|
bool substitute = false;
|
||||||
|
@ -2755,203 +2860,152 @@ bool TemplateSimplifier::simplifyUsing()
|
||||||
scope1 = getScopeName(scopeList1);
|
scope1 = getScopeName(scopeList1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (tok1 && tok1->str() == name) {
|
|
||||||
// skip this using
|
if (!usingMatch(nameToken, scope, &tok1, scope1, scopeList1))
|
||||||
if (tok1 == nameToken) {
|
continue;
|
||||||
tok1 = findSemicolon(tok1);
|
|
||||||
continue;
|
// remove the qualification
|
||||||
}
|
while (tok1->strAt(-1) == "::" && tok1->strAt(-2) == scope) {
|
||||||
// skip other using with this name
|
tok1->deletePrevious();
|
||||||
if (tok1->strAt(-1) == "using") {
|
tok1->deletePrevious();
|
||||||
// fixme: this is wrong
|
}
|
||||||
// skip to end of scope
|
|
||||||
if (scopeList1.back().bodyEnd)
|
Token * arrayStart = nullptr;
|
||||||
tok1 = scopeList1.back().bodyEnd->previous();
|
|
||||||
continue;
|
// parse the type
|
||||||
}
|
Token *type = start;
|
||||||
if (Token::Match(tok1->tokAt(-1), "struct|union|enum")) {
|
if (type->str() == "::") {
|
||||||
// fixme
|
type = type->next();
|
||||||
continue;
|
while (Token::Match(type, "%type% ::"))
|
||||||
|
type = type->tokAt(2);
|
||||||
|
if (Token::Match(type, "%type%"))
|
||||||
|
type = type->next();
|
||||||
|
} else if (Token::Match(type, "%type% ::")) {
|
||||||
|
do {
|
||||||
|
type = type->tokAt(2);
|
||||||
|
} while (Token::Match(type, "%type% ::"));
|
||||||
|
if (Token::Match(type, "%type%"))
|
||||||
|
type = type->next();
|
||||||
|
} else if (Token::Match(type, "%type%")) {
|
||||||
|
while (Token::Match(type, "const|struct|union|enum %type%") ||
|
||||||
|
(type->next() && type->next()->isStandardType()))
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
while (Token::Match(type, "%type%") &&
|
||||||
|
(type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
|
||||||
|
type = type->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get qualification
|
bool atEnd = false;
|
||||||
std::string qualification;
|
while (!atEnd) {
|
||||||
const Token* tok2 = tok1;
|
if (type && type->str() == "::") {
|
||||||
std::string::size_type index = scope.size();
|
type = type->next();
|
||||||
std::string::size_type new_index = std::string::npos;
|
}
|
||||||
bool match = true;
|
|
||||||
while (tok2->strAt(-1) == "::") {
|
if (Token::Match(type, "%type%") &&
|
||||||
std::string last;
|
type->next() && !Token::Match(type->next(), "[|;|,|(")) {
|
||||||
if (match && !scope1.empty()) {
|
type = type->next();
|
||||||
new_index = scope1.rfind(' ', index - 1);
|
} else if (Token::simpleMatch(type, "const (")) {
|
||||||
if (new_index != std::string::npos)
|
type = type->next();
|
||||||
last = scope1.substr(new_index, index - new_index);
|
atEnd = true;
|
||||||
else if (!qualification.empty())
|
} else
|
||||||
last.clear();
|
atEnd = true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
syntaxError(type);
|
||||||
|
|
||||||
|
// check for invalid input
|
||||||
|
if (!type)
|
||||||
|
syntaxError(tok1);
|
||||||
|
|
||||||
|
// check for template
|
||||||
|
if (type->str() == "<") {
|
||||||
|
type = type->findClosingBracket();
|
||||||
|
|
||||||
|
while (type && Token::Match(type->next(), ":: %type%"))
|
||||||
|
type = type->tokAt(2);
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
syntaxError(tok1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Token::Match(type->next(), "const|volatile"))
|
||||||
|
type = type->next();
|
||||||
|
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for pointers and references
|
||||||
|
std::list<std::string> pointers;
|
||||||
|
while (Token::Match(type, "*|&|&&|const")) {
|
||||||
|
pointers.push_back(type->str());
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for array
|
||||||
|
if (type && type->str() == "[") {
|
||||||
|
do {
|
||||||
|
if (!arrayStart)
|
||||||
|
arrayStart = type;
|
||||||
|
|
||||||
|
bool atEnd = false;
|
||||||
|
while (!atEnd) {
|
||||||
|
while (type->next() && !Token::Match(type->next(), ";|,")) {
|
||||||
|
type = type->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type->next())
|
||||||
|
syntaxError(type); // invalid input
|
||||||
|
else if (type->next()->str() == ";")
|
||||||
|
atEnd = true;
|
||||||
|
else if (type->str() == "]")
|
||||||
|
atEnd = true;
|
||||||
else
|
else
|
||||||
last = scope1;
|
type = type->next();
|
||||||
} else
|
|
||||||
match = false;
|
|
||||||
if (match && tok2->strAt(-2) == last)
|
|
||||||
index = new_index;
|
|
||||||
else {
|
|
||||||
if (!qualification.empty())
|
|
||||||
qualification = " :: " + qualification;
|
|
||||||
qualification = tok2->strAt(-2) + qualification;
|
|
||||||
}
|
}
|
||||||
tok2 = tok2->tokAt(-2);
|
|
||||||
|
type = type->next();
|
||||||
|
} while (type && type->str() == "[");
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* after = tok1->next();
|
||||||
|
// check if type was parsed
|
||||||
|
if (type && type == usingEnd) {
|
||||||
|
// check for array syntax and add type around variable
|
||||||
|
if (arrayStart) {
|
||||||
|
if (Token::Match(tok1->next(), "%name%")) {
|
||||||
|
mTokenList.copyTokens(tok1->next(), arrayStart, usingEnd->previous());
|
||||||
|
mTokenList.copyTokens(tok1, start, arrayStart->previous());
|
||||||
|
tok1->deleteThis();
|
||||||
|
substitute = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just replace simple type aliases
|
||||||
|
mTokenList.copyTokens(tok1, start, usingEnd->previous());
|
||||||
|
tok1->deleteThis();
|
||||||
|
substitute = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// todo: check using namespace
|
skip = true;
|
||||||
std::string fullScope1 = scope1;
|
if (mSettings->debugwarnings && mErrorLogger) {
|
||||||
if (!scope1.empty() && !qualification.empty())
|
std::string str;
|
||||||
fullScope1 += " :: ";
|
for (Token *tok3 = usingStart; tok3 && tok3 != usingEnd; tok3 = tok3->next()) {
|
||||||
fullScope1 += qualification;
|
if (!str.empty())
|
||||||
|
str += ' ';
|
||||||
if (scope == fullScope1) {
|
str += tok3->str();
|
||||||
// remove the qualification
|
|
||||||
while (tok1->strAt(-1) == "::" && tok1->strAt(-2) == scope) {
|
|
||||||
tok1->deletePrevious();
|
|
||||||
tok1->deletePrevious();
|
|
||||||
}
|
}
|
||||||
|
str += " ;";
|
||||||
|
std::list<const Token *> callstack(1, usingStart);
|
||||||
|
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||||
|
|
||||||
Token * arrayStart = nullptr;
|
"Failed to parse \'" + str + "\'. The checking continues anyway.", false));
|
||||||
|
|
||||||
// parse the type
|
|
||||||
Token *type = start;
|
|
||||||
if (type->str() == "::") {
|
|
||||||
type = type->next();
|
|
||||||
while (Token::Match(type, "%type% ::"))
|
|
||||||
type = type->tokAt(2);
|
|
||||||
if (Token::Match(type, "%type%"))
|
|
||||||
type = type->next();
|
|
||||||
} else if (Token::Match(type, "%type% ::")) {
|
|
||||||
do {
|
|
||||||
type = type->tokAt(2);
|
|
||||||
} while (Token::Match(type, "%type% ::"));
|
|
||||||
if (Token::Match(type, "%type%"))
|
|
||||||
type = type->next();
|
|
||||||
} else if (Token::Match(type, "%type%")) {
|
|
||||||
while (Token::Match(type, "const|struct|union|enum %type%") ||
|
|
||||||
(type->next() && type->next()->isStandardType()))
|
|
||||||
type = type->next();
|
|
||||||
|
|
||||||
type = type->next();
|
|
||||||
|
|
||||||
while (Token::Match(type, "%type%") &&
|
|
||||||
(type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool atEnd = false;
|
|
||||||
while (!atEnd) {
|
|
||||||
if (type && type->str() == "::") {
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(type, "%type%") &&
|
|
||||||
type->next() && !Token::Match(type->next(), "[|;|,|(")) {
|
|
||||||
type = type->next();
|
|
||||||
} else if (Token::simpleMatch(type, "const (")) {
|
|
||||||
type = type->next();
|
|
||||||
atEnd = true;
|
|
||||||
} else
|
|
||||||
atEnd = true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
syntaxError(type);
|
|
||||||
|
|
||||||
// check for invalid input
|
|
||||||
if (!type)
|
|
||||||
syntaxError(tok1);
|
|
||||||
|
|
||||||
// check for template
|
|
||||||
if (type->str() == "<") {
|
|
||||||
type = type->findClosingBracket();
|
|
||||||
|
|
||||||
while (type && Token::Match(type->next(), ":: %type%"))
|
|
||||||
type = type->tokAt(2);
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
syntaxError(tok1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (Token::Match(type->next(), "const|volatile"))
|
|
||||||
type = type->next();
|
|
||||||
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for pointers and references
|
|
||||||
std::list<std::string> pointers;
|
|
||||||
while (Token::Match(type, "*|&|&&|const")) {
|
|
||||||
pointers.push_back(type->str());
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for array
|
|
||||||
if (type && type->str() == "[") {
|
|
||||||
do {
|
|
||||||
if (!arrayStart)
|
|
||||||
arrayStart = type;
|
|
||||||
|
|
||||||
bool atEnd = false;
|
|
||||||
while (!atEnd) {
|
|
||||||
while (type->next() && !Token::Match(type->next(), ";|,")) {
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!type->next())
|
|
||||||
syntaxError(type); // invalid input
|
|
||||||
else if (type->next()->str() == ";")
|
|
||||||
atEnd = true;
|
|
||||||
else if (type->str() == "]")
|
|
||||||
atEnd = true;
|
|
||||||
else
|
|
||||||
type = type->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
type = type->next();
|
|
||||||
} while (type && type->str() == "[");
|
|
||||||
}
|
|
||||||
|
|
||||||
Token* after = tok1->next();
|
|
||||||
// check if type was parsed
|
|
||||||
if (type && type == usingEnd) {
|
|
||||||
// check for array syntax and add type around variable
|
|
||||||
if (arrayStart) {
|
|
||||||
if (Token::Match(tok1->next(), "%name%")) {
|
|
||||||
mTokenList.copyTokens(tok1->next(), arrayStart, usingEnd->previous());
|
|
||||||
mTokenList.copyTokens(tok1, start, arrayStart->previous());
|
|
||||||
tok1->deleteThis();
|
|
||||||
substitute = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// just replace simple type aliases
|
|
||||||
mTokenList.copyTokens(tok1, start, usingEnd->previous());
|
|
||||||
tok1->deleteThis();
|
|
||||||
substitute = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
skip = true;
|
|
||||||
if (mSettings->debugwarnings && mErrorLogger) {
|
|
||||||
std::string str;
|
|
||||||
for (Token *tok3 = usingStart; tok3 && tok3 != usingEnd; tok3 = tok3->next()) {
|
|
||||||
if (!str.empty())
|
|
||||||
str += ' ';
|
|
||||||
str += tok3->str();
|
|
||||||
}
|
|
||||||
str += " ;";
|
|
||||||
std::list<const Token *> callstack(1, usingStart);
|
|
||||||
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
|
||||||
|
|
||||||
"Failed to parse \'" + str + "\'. The checking continues anyway.", false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tok1 = after;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tok1 = after;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip)
|
if (!skip)
|
||||||
usingList.emplace_back(usingStart, usingEnd);
|
usingList.emplace_back(usingStart, usingEnd);
|
||||||
}
|
}
|
||||||
|
@ -2988,6 +3042,19 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
const std::time_t maxtime,
|
const std::time_t maxtime,
|
||||||
bool &codeWithTemplates)
|
bool &codeWithTemplates)
|
||||||
{
|
{
|
||||||
|
// Remove "typename" unless used in template arguments..
|
||||||
|
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "typename %name%"))
|
||||||
|
tok->deleteThis();
|
||||||
|
|
||||||
|
if (Token::simpleMatch(tok, "template <")) {
|
||||||
|
while (tok && tok->str() != ">")
|
||||||
|
tok = tok->next();
|
||||||
|
if (!tok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: 2 is not the ideal number of loops.
|
// TODO: 2 is not the ideal number of loops.
|
||||||
// We should loop until the number of declarations is 0 but we can't
|
// We should loop until the number of declarations is 0 but we can't
|
||||||
// do that until we instantiate unintstantiated templates with their symbolic types.
|
// do that until we instantiate unintstantiated templates with their symbolic types.
|
||||||
|
@ -3014,24 +3081,8 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
|
|
||||||
bool hasTemplates = getTemplateDeclarations();
|
bool hasTemplates = getTemplateDeclarations();
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0)
|
||||||
codeWithTemplates = hasTemplates;
|
codeWithTemplates = hasTemplates;
|
||||||
if (hasTemplates) {
|
|
||||||
// There are templates..
|
|
||||||
// Remove "typename" unless used in template arguments..
|
|
||||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
|
||||||
if (tok->str() == "typename")
|
|
||||||
tok->deleteThis();
|
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "template <")) {
|
|
||||||
while (tok && tok->str() != ">")
|
|
||||||
tok = tok->next();
|
|
||||||
if (!tok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure there is something to simplify.
|
// Make sure there is something to simplify.
|
||||||
if (mTemplateDeclarations.empty())
|
if (mTemplateDeclarations.empty())
|
||||||
|
|
|
@ -138,6 +138,7 @@ private:
|
||||||
TEST_CASE(template98); // #8959
|
TEST_CASE(template98); // #8959
|
||||||
TEST_CASE(template99); // #8960
|
TEST_CASE(template99); // #8960
|
||||||
TEST_CASE(template100); // #8967
|
TEST_CASE(template100); // #8967
|
||||||
|
TEST_CASE(template101); // #8968
|
||||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
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_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)
|
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
|
@ -2117,6 +2118,24 @@ private:
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template101() { // #8968
|
||||||
|
const char code[] = "class A {\n"
|
||||||
|
"public:\n"
|
||||||
|
" using ArrayType = std::vector<int>;\n"
|
||||||
|
" void func(typename ArrayType::size_type i) {\n"
|
||||||
|
" }\n"
|
||||||
|
"};";
|
||||||
|
|
||||||
|
const char exp[] = "class A { "
|
||||||
|
"public: "
|
||||||
|
"void func ( std :: vector < int > :: size_type i ) { "
|
||||||
|
"} "
|
||||||
|
"} ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
const char code[] = "template <typename T> struct C {};\n"
|
const char code[] = "template <typename T> struct C {};\n"
|
||||||
"template <typename T> struct S {a};\n"
|
"template <typename T> struct S {a};\n"
|
||||||
|
@ -2334,6 +2353,25 @@ private:
|
||||||
"{ int ar [ 3 ] ; } ;";
|
"{ int ar [ 3 ] ; } ;";
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const char code[] = "template<typename Lhs, int TriangularPart = (int(Lhs::Flags) & LowerTriangularBit)>\n"
|
||||||
|
"struct ei_solve_triangular_selector;\n"
|
||||||
|
"template<typename Lhs, int UpLo>\n"
|
||||||
|
"struct ei_solve_triangular_selector<Lhs,UpLo> {\n"
|
||||||
|
"};\n"
|
||||||
|
"template<typename Lhs, int TriangularPart>\n"
|
||||||
|
"struct ei_solve_triangular_selector { };";
|
||||||
|
|
||||||
|
const char exp[] = "template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
||||||
|
"struct ei_solve_triangular_selector ; "
|
||||||
|
"template < typename Lhs , int UpLo > "
|
||||||
|
"struct ei_solve_triangular_selector < Lhs , UpLo > { "
|
||||||
|
"} ; "
|
||||||
|
"template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
||||||
|
"struct ei_solve_triangular_selector { } ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_default_type() {
|
void template_default_type() {
|
||||||
|
|
|
@ -2307,25 +2307,25 @@ private:
|
||||||
const char code1[] = "typedef typename A B;\n"
|
const char code1[] = "typedef typename A B;\n"
|
||||||
"typedef typename B C;\n"
|
"typedef typename B C;\n"
|
||||||
"typename C c;\n";
|
"typename C c;\n";
|
||||||
const char expected1[] = "typename A c ;";
|
const char expected1[] = "A c ;";
|
||||||
ASSERT_EQUALS(expected1, tok(code1));
|
ASSERT_EQUALS(expected1, tok(code1));
|
||||||
|
|
||||||
const char code2[] = "typedef typename A B;\n"
|
const char code2[] = "typedef typename A B;\n"
|
||||||
"typedef typename B C;\n"
|
"typedef typename B C;\n"
|
||||||
"C c;\n";
|
"C c;\n";
|
||||||
const char expected2[] = "typename A c ;";
|
const char expected2[] = "A c ;";
|
||||||
ASSERT_EQUALS(expected2, tok(code2));
|
ASSERT_EQUALS(expected2, tok(code2));
|
||||||
|
|
||||||
const char code3[] = "typedef typename A B;\n"
|
const char code3[] = "typedef typename A B;\n"
|
||||||
"typedef B C;\n"
|
"typedef B C;\n"
|
||||||
"C c;\n";
|
"C c;\n";
|
||||||
const char expected3[] = "typename A c ;";
|
const char expected3[] = "A c ;";
|
||||||
ASSERT_EQUALS(expected3, tok(code3));
|
ASSERT_EQUALS(expected3, tok(code3));
|
||||||
|
|
||||||
const char code4[] = "typedef A B;\n"
|
const char code4[] = "typedef A B;\n"
|
||||||
"typedef typename B C;\n"
|
"typedef typename B C;\n"
|
||||||
"C c;\n";
|
"C c;\n";
|
||||||
const char expected4[] = "typename A c ;";
|
const char expected4[] = "A c ;";
|
||||||
ASSERT_EQUALS(expected4, tok(code4));
|
ASSERT_EQUALS(expected4, tok(code4));
|
||||||
|
|
||||||
const char code5[] = "typedef A B;\n"
|
const char code5[] = "typedef A B;\n"
|
||||||
|
|
|
@ -58,6 +58,9 @@ private:
|
||||||
TEST_CASE(simplifyUsing14);
|
TEST_CASE(simplifyUsing14);
|
||||||
TEST_CASE(simplifyUsing15);
|
TEST_CASE(simplifyUsing15);
|
||||||
TEST_CASE(simplifyUsing16);
|
TEST_CASE(simplifyUsing16);
|
||||||
|
|
||||||
|
TEST_CASE(simplifyUsing8970);
|
||||||
|
TEST_CASE(simplifyUsing8971);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
|
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
|
||||||
|
@ -412,6 +415,43 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyUsing8970() {
|
||||||
|
const char code[] = "using V = std::vector<int>;\n"
|
||||||
|
"struct A {\n"
|
||||||
|
" V p;\n"
|
||||||
|
"};";
|
||||||
|
|
||||||
|
const char expected[] = "struct A { "
|
||||||
|
"std :: vector < int > p ; "
|
||||||
|
"} ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void simplifyUsing8971() {
|
||||||
|
const char code[] = "class A {\n"
|
||||||
|
"public:\n"
|
||||||
|
" using V = std::vector<double>;\n"
|
||||||
|
"};\n"
|
||||||
|
"using V = std::vector<int>;\n"
|
||||||
|
"class I {\n"
|
||||||
|
"private:\n"
|
||||||
|
" A::V v_;\n"
|
||||||
|
" V v2_;\n"
|
||||||
|
"};";
|
||||||
|
|
||||||
|
const char expected[] = "class A { "
|
||||||
|
"public: "
|
||||||
|
"} ; "
|
||||||
|
"class I { "
|
||||||
|
"private: "
|
||||||
|
"std :: vector < double > v_ ; "
|
||||||
|
"std :: vector < int > v2_ ; "
|
||||||
|
"} ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestSimplifyUsing)
|
REGISTER_TEST(TestSimplifyUsing)
|
||||||
|
|
|
@ -2187,7 +2187,7 @@ private:
|
||||||
|
|
||||||
ASSERT_EQUALS("1: template < int d , typename A , typename B > struct S { } ;\n", tokenize("template<int d, typename A, typename B> struct S {};"));
|
ASSERT_EQUALS("1: template < int d , typename A , typename B > struct S { } ;\n", tokenize("template<int d, typename A, typename B> struct S {};"));
|
||||||
|
|
||||||
ASSERT_EQUALS("1: typename A a@1 ;\n", tokenize("typename A a;"));
|
ASSERT_EQUALS("1: A a@1 ;\n", tokenize("typename A a;"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void varid_rvalueref() {
|
void varid_rvalueref() {
|
||||||
|
|
Loading…
Reference in New Issue