From b748453b307466280b78e4c951822a700d0933d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= <daniel.marjamaki@gmail.com>
Date: Mon, 4 Jan 2016 09:59:53 +0100
Subject: [PATCH] Tokenizer: Improve handling of block declarations (C
 extension)

---
 lib/tokenize.cpp      | 14 ++++++++---
 test/testtokenize.cpp | 57 +++++++++++++++++++++++--------------------
 2 files changed, 42 insertions(+), 29 deletions(-)

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"