lift handling of ->immutable into dup_token()

We need to make sure that any struct string with more than one token
refering to it will have ->immutable set; that's what de1fa7e60 ("Make
macro expanded string immutable") tried to achieve.  Unfortunately, it
was not enough - constructing an example where an unexpanded argument gets
several copies is very easy (see the testcase in this commit).

A better place for dealing with that is dup_token() - that's guaranteed
to catch all such tokens and with sane code generation (== with compiler
made certain that *streampos can't be altered by stores to alloc->pos)
it's quite cheap; we already have alloc->pos in registers and checking
if the lower 6 bits happen to be 001000 or 001001 (TOKEN_STRING and
TOKEN_WIDE_STRING resp.) doesn't take much.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/pre-process.c b/pre-process.c
index be4e9d7..4e32285 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -255,7 +255,7 @@
 
 static void preprocessor_line(struct stream *stream, struct token **line);
 
-static struct token *collect_arg(struct token *prev, int vararg, struct position *pos, int count)
+static struct token *collect_arg(struct token *prev, int vararg, const struct position *pos)
 {
 	struct stream *stream = input_streams + prev->pos.stream;
 	struct token **p = &prev->next;
@@ -275,11 +275,6 @@
 		case TOKEN_STREAMBEGIN:
 			*p = &eof_token_entry;
 			return next;
-		case TOKEN_STRING:
-		case TOKEN_WIDE_STRING:
-			if (count > 1)
-				next->string->immutable = 1;
-			break;
 		}
 		if (false_nesting) {
 			*p = next->next;
@@ -326,7 +321,7 @@
 	arglist = arglist->next;	/* skip counter */
 
 	if (!wanted) {
-		next = collect_arg(start, 0, &what->pos, 0);
+		next = collect_arg(start, 0, &what->pos);
 		if (eof_token(next))
 			goto Eclosing;
 		if (!eof_token(start->next) || !match_op(next, ')')) {
@@ -336,7 +331,7 @@
 	} else {
 		for (count = 0; count < wanted; count++) {
 			struct argcount *p = &arglist->next->count;
-			next = collect_arg(start, p->vararg, &what->pos, p->normal);
+			next = collect_arg(start, p->vararg, &what->pos);
 			if (eof_token(next))
 				goto Eclosing;
 			if (p->vararg && wanted == 1 && eof_token(start->next))
@@ -375,7 +370,7 @@
 	goto out;
 Emany:
 	while (match_op(next, ',')) {
-		next = collect_arg(next, 0, &what->pos, 0);
+		next = collect_arg(next, 0, &what->pos);
 		count++;
 	}
 	if (eof_token(next))
@@ -598,6 +593,8 @@
 	alloc->pos.stream = pos.stream;
 	alloc->pos.line = pos.line;
 	alloc->pos.pos = pos.pos;
+	if (token_type(alloc) == TOKEN_STRING || token_type(alloc) == TOKEN_WIDE_STRING)
+		token->string->immutable = 1;
 	return alloc;	
 }
 
@@ -1315,15 +1312,8 @@
 		} else {
 			try_arg(token, TOKEN_MACRO_ARGUMENT, arglist);
 		}
-		switch (token_type(token)) {
-		case TOKEN_ERROR:
+		if (token_type(token) == TOKEN_ERROR)
 			goto Earg;
-
-		case TOKEN_STRING:
-		case TOKEN_WIDE_STRING:
-			token->string->immutable = 1;
-			break;
-		}
 	}
 	token = alloc_token(&expansion->pos);
 	token_type(token) = TOKEN_UNTAINT;
diff --git a/validation/preprocessor/double-escapes.c b/validation/preprocessor/double-escapes.c
new file mode 100644
index 0000000..9142ad0
--- /dev/null
+++ b/validation/preprocessor/double-escapes.c
@@ -0,0 +1,8 @@
+#define A(x) x, x
+#define B(x,y) x ## y, x ## y
+static char *p[] = {A("\\")};
+static char *q[] = {B("\\", )};
+/*
+ * check-name: double escapes
+ * check-command: sparse $file
+ */