diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index eb3bf241e..2b6cdc956 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9295,18 +9295,26 @@ void Tokenizer::simplifyAsm() void Tokenizer::simplifyAsm2() { + // Block declarations: ^{} + // A C extension used to create lambda like closures. + // Put ^{} statements in asm() for (Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "^ {")) { + if (tok->str() != "^") + continue; + + if (Token::simpleMatch(tok, "^ {") || Token::simpleMatch(tok->linkAt(1), ") {")) { Token * start = tok; while (start && !Token::Match(start, "[;{}=]")) { - if (start->link() && start->str() == ")") + if (start->link() && Token::Match(start, ")|]|>")) start = start->link(); start = start->previous(); } if (start) start = start->next(); const Token *last = tok->next()->link(); + if (Token::simpleMatch(last, ") {")) + last = last->linkAt(1); if (start != tok) { last = last->next(); while (last && !Token::Match(last, "[;{})]")) { @@ -9337,9 +9345,9 @@ void Tokenizer::simplifyAsm2() } } } + // When the assembly code has been cleaned up, no @ is allowed for (const Token *tok = list.front(); tok; tok = tok->next()) { - assert(list.validateToken(tok)); // see #7185 "crash: Tokenizer::simplifyAsm2 on invalid code" if (tok->str() == "(") { tok = tok->link(); if (!tok) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 3d7c82887..079c8e9c8 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -63,7 +63,6 @@ private: TEST_CASE(tokenize25); // #4239 (segmentation fault) TEST_CASE(tokenize26); // #4245 (segmentation fault) TEST_CASE(tokenize27); // #4525 (segmentation fault) - TEST_CASE(tokenize28); // #4725 (writing asm() around "^{}") TEST_CASE(tokenize31); // #3503 (Wrong handling of member function taking function pointer as argument) TEST_CASE(tokenize32); // #5884 (fsanitize=undefined: left shift of negative value -10000 in lib/templatesimplifier.cpp:852:46) TEST_CASE(tokenize33); // #5780 Various crashes on valid template code @@ -97,6 +96,7 @@ private: TEST_CASE(removeCast17); // #6110 - don't remove any parentheses in 'a(b)(c)' TEST_CASE(inlineasm); + TEST_CASE(simplifyAsm2); // #4725 (writing asm() around "^{}") TEST_CASE(ifAddBraces1); TEST_CASE(ifAddBraces2); @@ -769,31 +769,6 @@ private: tokenizeAndStringify("static unsigned int re_string_context_at (const re_string_t *input, int idx, int eflags) internal_function __attribute__ ((pure));"); } - // #4725 - ^{} - void tokenize28() { - ASSERT_EQUALS("void f ( ) { asm ( \"^{}\" ) ; }", tokenizeAndStringify("void f() { ^{} }")); - ASSERT_EQUALS("void f ( ) { asm ( \"x(^{});\" ) ; }", tokenizeAndStringify("void f() { x(^{}); }")); - ASSERT_EQUALS("void f ( ) { asm ( \"foo(A(),^{bar();});\" ) ; }", tokenizeAndStringify("void f() { foo(A(), ^{ bar(); }); }")); - ASSERT_EQUALS("int f0 ( Args args ) {\n" - "asm ( \"return^{returnsizeof...(Args);}()+\" ) ;\n" - "\n" - "asm ( \"^{returnsizeof...(args);}\" ) ;\n" - "\n" - "\n" - "} ;", tokenizeAndStringify("int f0(Args args) {\n" - " return ^{\n" - " return sizeof...(Args);\n" - " }() + ^ {\n" - " return sizeof...(args);\n" - " }();\n" - "};")); - ASSERT_EQUALS("int ( ^ block ) ( void ) = asm ( \"^{staticinttest=0;returntest;}\" ) ;", - tokenizeAndStringify("int(^block)(void) = ^{\n" - " static int test = 0;\n" - " return test;\n" - "};")); - } - // #3503 - don't "simplify" SetFunction member function to a variable void tokenize31() { ASSERT_EQUALS("struct TTestClass { TTestClass ( ) { }\n" @@ -1021,6 +996,36 @@ private: ASSERT_EQUALS(";\n\nasm ( \"\"mov ax,bx\"\" ) ;", tokenizeAndStringify(";\n\n__asm__ volatile ( \"mov ax,bx\" );", true)); } + // #4725 - ^{} + void simplifyAsm2() { + ASSERT_EQUALS("void f ( ) { asm ( \"^{}\" ) ; }", tokenizeAndStringify("void f() { ^{} }")); + ASSERT_EQUALS("void f ( ) { asm ( \"x(^{});\" ) ; }", tokenizeAndStringify("void f() { x(^{}); }")); + ASSERT_EQUALS("void f ( ) { asm ( \"foo(A(),^{bar();});\" ) ; }", tokenizeAndStringify("void f() { foo(A(), ^{ bar(); }); }")); + ASSERT_EQUALS("int f0 ( Args args ) {\n" + "asm ( \"return^{returnsizeof...(Args);}()+\" ) ;\n" + "\n" + "asm ( \"^{returnsizeof...(args);}\" ) ;\n" + "\n" + "\n" + "} ;", tokenizeAndStringify("int f0(Args args) {\n" + " return ^{\n" + " return sizeof...(Args);\n" + " }() + ^ {\n" + " return sizeof...(args);\n" + " }();\n" + "};")); + ASSERT_EQUALS("int ( ^ block ) ( void ) = asm ( \"^{staticinttest=0;returntest;}\" ) ;", + tokenizeAndStringify("int(^block)(void) = ^{\n" + " static int test = 0;\n" + " return test;\n" + "};")); + + ASSERT_EQUALS("; asm ( \"returnf([=]().int^{});\" ) ;", + tokenizeAndStringify("; return f([=]() -> int^{});")); // #7185 - garbage + ASSERT_EQUALS("; asm ( \"returnf(^(void){somecode});\" ) ;", + tokenizeAndStringify("; return f(^(void){somecode});")); + } + void ifAddBraces1() { const char code[] = "void f()\n" "{\n"