diff --git a/tcc.h b/tcc.h
index 9955839b..dda2fc14 100644
--- a/tcc.h
+++ b/tcc.h
@@ -836,6 +836,7 @@ struct TCCState {
 /* <-- */
 
 #define TOK_TWOSHARPS 0xc0 /* ## preprocessing token */
+#define TOK_PLCHLDR  0xc1 /* placeholder token as defined in C99 */
 #define TOK_UMULL    0xc2 /* unsigned 32x32 -> 64 mul */
 #define TOK_ADDC1    0xc3 /* add with carry generation */
 #define TOK_ADDC2    0xc4 /* add with carry use */
diff --git a/tccpp.c b/tccpp.c
index c8beec59..dfdee50c 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -2565,7 +2565,8 @@ ST_FUNC void next_nomacro(void)
     } while (is_space(tok));
 }
  
-/* substitute args in macro_str and return allocated string */
+/* substitute arguments in replacement lists in macro_str by the values in
+   args (field d) and return allocated string */
 static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
 {
     int last_tok, t, spc;
@@ -2622,7 +2623,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
                     if (gnu_ext && s->type.t &&
                         last_tok == TOK_TWOSHARPS && 
                         str.len >= 2 && str.str[str.len - 2] == ',') {
-                        if (*st == 0) {
+                        if (*st == TOK_PLCHLDR) {
                             /* suppress ',' '##' */
                             str.len -= 2;
                         } else {
@@ -2793,6 +2794,8 @@ static int macro_subst_tok(TokenString *tok_str,
                         tok_str_add2(&str, tok, &tokc);
                     next_nomacro_spc();
                 }
+                if (!str.len)
+                    tok_str_add(&str, TOK_PLCHLDR);
                 str.len -= spc;
                 tok_str_add(&str, 0);
                 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
@@ -2885,9 +2888,11 @@ static inline int *macro_twosharps(const int *macro_str)
                 TOK_GET(&t, &ptr, &cval);
                 /* We concatenate the two tokens */
                 cstr_new(&cstr);
-                cstr_cat(&cstr, get_tok_str(tok, &tokc));
+                if (tok != TOK_PLCHLDR)
+                    cstr_cat(&cstr, get_tok_str(tok, &tokc));
                 n = cstr.size;
-                cstr_cat(&cstr, get_tok_str(t, &cval));
+                if (t != TOK_PLCHLDR || tok == TOK_PLCHLDR)
+                    cstr_cat(&cstr, get_tok_str(t, &cval));
                 cstr_ccat(&cstr, '\0');
 
                 tcc_open_bf(tcc_state, ":paste:", cstr.size);
@@ -2904,8 +2909,35 @@ static inline int *macro_twosharps(const int *macro_str)
                 cstr_free(&cstr);
             }
         }
-        if (tok != TOK_NOSUBST) 
+        if (tok != TOK_NOSUBST) {
+            const int *oldptr;
+            CValue cval;
+
+            /* Check if a space need to be added after ## concatenation in
+               order to avoid misinterpreting the newly formed token
+               followed by the next token as being a single token (see
+               macro_concat test) */
+            cstr_new(&cstr);
+            cstr_cat(&cstr, get_tok_str(tok, &tokc));
+            oldptr = ptr;
+            TOK_GET(&t, &ptr, &cval);
+            ptr = oldptr;
+            cstr_cat(&cstr, get_tok_str(t, &cval));
+            cstr_ccat(&cstr, '\0');
+            t = tok;
+            cval = tokc;
+            tcc_open_bf(tcc_state, ":paste:", cstr.size);
+            memcpy(file->buffer, cstr.data, cstr.size);
+            next_nomacro1();
+            if (!*file->buf_ptr) {
+                tok_str_add2(&macro_str1, t, &cval);
+                tok = ' ';
+            }
+            tcc_close();
+            cstr_free(&cstr);
+
             start_of_nosubsts = -1;
+        }
         tok_str_add2(&macro_str1, tok, &tokc);
     }
     tok_str_add(&macro_str1, 0);
diff --git a/tests/tests2/67_macro_concat.c b/tests/tests2/67_macro_concat.c
new file mode 100644
index 00000000..c580d3a6
--- /dev/null
+++ b/tests/tests2/67_macro_concat.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+#define P(A,B) A ## B ; bob
+#define Q(A,B) A ## B+
+
+int main(void)
+{
+    int bob, jim = 21;
+    bob = P(jim,) *= 2;
+    printf("jim: %d, bob: %d\n", jim, bob);
+    jim = 60 Q(+,)3;
+    printf("jim: %d\n", jim);
+    return 0;
+}
diff --git a/tests/tests2/67_macro_concat.expect b/tests/tests2/67_macro_concat.expect
new file mode 100644
index 00000000..8386c2d6
--- /dev/null
+++ b/tests/tests2/67_macro_concat.expect
@@ -0,0 +1,2 @@
+jim: 21, bob: 42
+jim: 63
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 41adb2de..a7c8a2f3 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -81,7 +81,8 @@ TESTS =	\
  63_local_enumerator_redefinition.test \
  64_macro_nesting.test \
  65_macro_concat_start.test \
- 66_macro_concat_end.test
+ 66_macro_concat_end.test \
+ 67_macro_concat.test
 
 # 30_hanoi.test -- seg fault in the code, gcc as well
 # 34_array_assignment.test -- array assignment is not in C standard