This commit is contained in:
parent
e6576dd949
commit
f72db74817
|
@ -221,13 +221,15 @@ void CheckClass::constructors()
|
|||
if (!usage.assign && !usage.init)
|
||||
continue;
|
||||
const Scope* varScope1 = var.nameToken()->scope();
|
||||
while (varScope1->type == Scope::ScopeType::eStruct)
|
||||
varScope1 = varScope1->nestedIn;
|
||||
if (varScope1->type == Scope::ScopeType::eUnion) {
|
||||
for (Usage &usage2 : usageList) {
|
||||
const Variable& var2 = *usage2.var;
|
||||
if (usage2.assign || usage2.init || var2.isStatic())
|
||||
continue;
|
||||
const Scope* varScope2 = var2.nameToken()->scope();
|
||||
if (varScope2->type == Scope::ScopeType::eStruct)
|
||||
while (varScope2->type == Scope::ScopeType::eStruct)
|
||||
varScope2 = varScope2->nestedIn;
|
||||
if (varScope1 == varScope2)
|
||||
usage2.assign = true;
|
||||
|
|
|
@ -3842,6 +3842,12 @@ void CheckOther::checkOverlappingWrite()
|
|||
return ChildrenToVisit::none;
|
||||
if (lhsmember->str() == rhs->astOperand2()->str())
|
||||
return ChildrenToVisit::none;
|
||||
const Variable* rhsmembervar = rhs->astOperand2()->variable();
|
||||
const Scope* varscope1 = lhsmember->variable() ? lhsmember->variable()->typeStartToken()->scope() : nullptr;
|
||||
const Scope* varscope2 = rhsmembervar ? rhsmembervar->typeStartToken()->scope() : nullptr;
|
||||
if (varscope1 && varscope1 == varscope2 && varscope1 != lhsvar->typeScope())
|
||||
// lhsmember and rhsmember are declared in same anonymous scope inside union
|
||||
return ChildrenToVisit::none;
|
||||
errorToken = rhs->astOperand2();
|
||||
return ChildrenToVisit::done;
|
||||
});
|
||||
|
|
143
lib/tokenize.cpp
143
lib/tokenize.cpp
|
@ -8550,10 +8550,6 @@ void Tokenizer::simplifyStructDecl()
|
|||
// A counter that is used when giving unique names for anonymous structs.
|
||||
int count = 0;
|
||||
|
||||
// Skip simplification of unions in class definition
|
||||
std::stack<bool> skip; // true = in function, false = not in function
|
||||
skip.push(false);
|
||||
|
||||
// Add names for anonymous structs
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (!tok->isName())
|
||||
|
@ -8585,15 +8581,26 @@ void Tokenizer::simplifyStructDecl()
|
|||
}
|
||||
}
|
||||
|
||||
// "{" token for current scope
|
||||
std::stack<const Token*> scopeStart;
|
||||
const Token* functionEnd = nullptr;
|
||||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
|
||||
// check for start of scope and determine if it is in a function
|
||||
if (tok->str() == "{")
|
||||
skip.push(Token::Match(tok->previous(), "const|)"));
|
||||
if (tok->str() == "{") {
|
||||
scopeStart.push(tok);
|
||||
if (!functionEnd && Token::Match(tok->previous(), "const|)"))
|
||||
functionEnd = tok->link();
|
||||
}
|
||||
|
||||
// end of scope
|
||||
else if (tok->str() == "}" && !skip.empty())
|
||||
skip.pop();
|
||||
else if (tok->str() == "}") {
|
||||
if (!scopeStart.empty())
|
||||
scopeStart.pop();
|
||||
if (tok == functionEnd)
|
||||
functionEnd = nullptr;
|
||||
}
|
||||
|
||||
// check for named struct/union
|
||||
else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
|
||||
|
@ -8607,120 +8614,82 @@ void Tokenizer::simplifyStructDecl()
|
|||
next = next->next();
|
||||
if (!next)
|
||||
continue;
|
||||
skip.push(false);
|
||||
tok = next->link();
|
||||
if (!tok)
|
||||
Token* after = next->link();
|
||||
if (!after)
|
||||
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
||||
Token *restart = next;
|
||||
|
||||
// check for named type
|
||||
if (Token::Match(tok->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
|
||||
tok->insertToken(";");
|
||||
tok = tok->next();
|
||||
if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
|
||||
after->insertToken(";");
|
||||
after = after->next();
|
||||
while (!Token::Match(start, "struct|class|union|enum")) {
|
||||
tok->insertToken(start->str());
|
||||
tok = tok->next();
|
||||
after->insertToken(start->str());
|
||||
after = after->next();
|
||||
start->deleteThis();
|
||||
}
|
||||
if (!tok)
|
||||
tok = start;
|
||||
if (!after)
|
||||
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
||||
tok->insertToken(type->str());
|
||||
after->insertToken(type->str());
|
||||
if (start->str() != "class") {
|
||||
tok->insertToken(start->str());
|
||||
tok = tok->next();
|
||||
after->insertToken(start->str());
|
||||
after = after->next();
|
||||
}
|
||||
|
||||
tok = tok->tokAt(2);
|
||||
after = after->tokAt(2);
|
||||
|
||||
if (Token::Match(tok, "( %type% )")) {
|
||||
tok->link()->deleteThis();
|
||||
tok->deleteThis();
|
||||
if (Token::Match(after, "( %type% )")) {
|
||||
after->link()->deleteThis();
|
||||
after->deleteThis();
|
||||
}
|
||||
|
||||
// check for initialization
|
||||
if (tok && (tok->next()->str() == "(" || tok->next()->str() == "{")) {
|
||||
tok->insertToken("=");
|
||||
tok = tok->next();
|
||||
if (Token::Match(after, "%any% (|{")) {
|
||||
after->insertToken("=");
|
||||
after = after->next();
|
||||
const bool isEnum = start->str() == "enum";
|
||||
if (!isEnum && cpp) {
|
||||
tok->insertToken(type->str());
|
||||
tok = tok->next();
|
||||
after->insertToken(type->str());
|
||||
after = after->next();
|
||||
}
|
||||
|
||||
if (isEnum) {
|
||||
if (tok->next()->str() == "{" && tok->next()->link() != tok->tokAt(2)) {
|
||||
tok->next()->str("(");
|
||||
tok->linkAt(1)->str(")");
|
||||
if (Token::Match(after->next(), "{ !!}")) {
|
||||
after->next()->str("(");
|
||||
after->linkAt(1)->str(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tok = restart;
|
||||
}
|
||||
|
||||
// check for anonymous struct/union
|
||||
else if (Token::Match(tok, "struct|union {")) {
|
||||
const bool inFunction = skip.top();
|
||||
skip.push(false);
|
||||
Token *tok1 = tok;
|
||||
|
||||
Token *restart = tok->next();
|
||||
tok = tok->next()->link();
|
||||
|
||||
else {
|
||||
// unnamed anonymous struct/union so possibly remove it
|
||||
if (tok && tok->next() && tok->next()->str() == ";") {
|
||||
if (inFunction && tok1->str() == "union") {
|
||||
// Try to create references in the union..
|
||||
Token *tok2 = tok1->tokAt(2);
|
||||
while (tok2) {
|
||||
if (Token::Match(tok2, "%type% %name% ;"))
|
||||
tok2 = tok2->tokAt(3);
|
||||
else
|
||||
bool done = false;
|
||||
while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
|
||||
done = true;
|
||||
|
||||
// is this a class/struct/union scope?
|
||||
bool isClassStructUnionScope = false;
|
||||
if (!scopeStart.empty()) {
|
||||
for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
|
||||
if (Token::Match(tok2, "class|struct|union")) {
|
||||
isClassStructUnionScope = true;
|
||||
break;
|
||||
}
|
||||
if (!Token::simpleMatch(tok2, "} ;"))
|
||||
continue;
|
||||
Token *vartok = nullptr;
|
||||
tok2 = tok1->tokAt(2);
|
||||
while (Token::Match(tok2, "%type% %name% ;")) {
|
||||
if (!vartok) {
|
||||
vartok = tok2->next();
|
||||
tok2 = tok2->tokAt(3);
|
||||
} else {
|
||||
tok2->insertToken("&");
|
||||
tok2 = tok2->tokAt(2);
|
||||
tok2->insertToken(vartok->str());
|
||||
tok2->next()->varId(vartok->varId());
|
||||
tok2->insertToken("=");
|
||||
tok2 = tok2->tokAt(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't remove unnamed anonymous unions from a class, struct or union
|
||||
if (!(!inFunction && tok1->str() == "union") && !Token::Match(tok1->tokAt(-3), "using %name% =")) {
|
||||
skip.pop();
|
||||
tok1->deleteThis();
|
||||
if (tok1->next() == tok) {
|
||||
tok1->deleteThis();
|
||||
tok = tok1;
|
||||
} else
|
||||
tok1->deleteThis();
|
||||
restart = tok1->previous();
|
||||
// remove unnamed anonymous struct/union
|
||||
// * not in class/struct/union scopes
|
||||
if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
|
||||
tok->linkAt(1)->previous()->deleteNext(2);
|
||||
tok->deleteNext();
|
||||
tok->deleteThis();
|
||||
if (tok->next())
|
||||
tok->deleteThis();
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!restart) {
|
||||
simplifyStructDecl();
|
||||
return;
|
||||
} else if (!restart->next())
|
||||
return;
|
||||
|
||||
tok = restart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1473,6 +1473,22 @@ private:
|
|||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct S {\n"
|
||||
" union {\n"
|
||||
" unsigned short all;\n"
|
||||
" struct {\n"
|
||||
" unsigned char flag1;\n"
|
||||
" unsigned char flag2;\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"class C : public S {\n"
|
||||
"public:\n"
|
||||
" C() { flag1 = flag2 = 0; tick = 0; }\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct S {\n"
|
||||
" union {\n"
|
||||
" unsigned short all;\n"
|
||||
|
|
|
@ -11059,6 +11059,12 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Overlapping read/write of union is undefined behavior\n", errout.str());
|
||||
|
||||
check("void foo() {\n" // #11013
|
||||
" union { struct { uint8_t a; uint8_t b; }; uint16_t c; } u;\n"
|
||||
" u.a = u.b = 0;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
// memcpy
|
||||
check("void foo() {\n"
|
||||
" char a[10];\n"
|
||||
|
|
|
@ -1200,12 +1200,6 @@ private:
|
|||
const char expected[] = "class { } ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "class { struct { struct { } ; } ; };";
|
||||
const char expected[] = "class { } ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyStructDecl4() {
|
||||
|
@ -1224,8 +1218,7 @@ private:
|
|||
"} abc;\n";
|
||||
const char expected[] = "class ABC { "
|
||||
"void foo ( ) { "
|
||||
"int i ; "
|
||||
"float & f = i ; "
|
||||
"union { int i ; float f ; } ; "
|
||||
"struct Fee { } ; struct Fee fee ; "
|
||||
"} "
|
||||
"union { "
|
||||
|
|
|
@ -1973,6 +1973,11 @@ private:
|
|||
const char code3[] = "struct a { int b; } static e[1];";
|
||||
const char expected3[] = "struct a { int b ; } ; struct a static e [ 1 ] ;";
|
||||
ASSERT_EQUALS(expected3, tokenizeAndStringify(code3));
|
||||
|
||||
// #11013 - Do not remove unnamed struct in union
|
||||
const char code4[] = "union U { struct { int a; int b; }; int ab[2]; };";
|
||||
const char expected4[] = "union U { struct { int a ; int b ; } ; int ab [ 2 ] ; } ;";
|
||||
ASSERT_EQUALS(expected4, tokenizeAndStringify(code4));
|
||||
}
|
||||
|
||||
void vardecl1() {
|
||||
|
@ -2090,7 +2095,7 @@ private:
|
|||
" long y;\n"
|
||||
" };\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( ) {\n\nint x ;\nlong & y = x ;\n\n}", tokenizeAndStringify(code2));
|
||||
ASSERT_EQUALS("void f ( ) {\nunion {\nint x ;\nlong y ;\n} ;\n}", tokenizeAndStringify(code2));
|
||||
|
||||
// ticket #3927
|
||||
const char code3[] = "union xy *p = NULL;";
|
||||
|
@ -4539,7 +4544,7 @@ private:
|
|||
}
|
||||
|
||||
void bitfields13() { // ticket #3502 (segmentation fault)
|
||||
ASSERT_EQUALS("x y ;", tokenizeAndStringify("struct{x y:};\n"));
|
||||
ASSERT_NO_THROW(tokenizeAndStringify("struct{x y:};\n"));
|
||||
}
|
||||
|
||||
void bitfields15() { // #7747 - enum Foo {A,B}:4;
|
||||
|
|
Loading…
Reference in New Issue