L ## 'a' is valid; so's L ## "a"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/pre-process.c b/pre-process.c
index 9e5df5c..e5f56b4 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -407,6 +407,8 @@
* Possibly valid combinations:
* - ident + ident -> ident
* - ident + number -> ident unless number contains '.', '+' or '-'.
+ * - 'L' + char constant -> wide char constant
+ * - 'L' + string literal -> wide string literal
* - number + number -> number
* - number + ident -> number
* - number + '.' -> number
@@ -422,6 +424,13 @@
if (t1 != TOKEN_IDENT && t1 != TOKEN_NUMBER && t1 != TOKEN_SPECIAL)
return TOKEN_ERROR;
+ if (t1 == TOKEN_IDENT && left->ident == &L_ident) {
+ if (t2 >= TOKEN_CHAR && t2 < TOKEN_WIDE_CHAR)
+ return t2 + TOKEN_WIDE_CHAR - TOKEN_CHAR;
+ if (t2 == TOKEN_STRING)
+ return TOKEN_WIDE_STRING;
+ }
+
if (t2 != TOKEN_IDENT && t2 != TOKEN_NUMBER && t2 != TOKEN_SPECIAL)
return TOKEN_ERROR;
@@ -464,9 +473,10 @@
static int merge(struct token *left, struct token *right)
{
static char buffer[512];
+ enum token_type res = combine(left, right, buffer);
int n;
- switch (combine(left, right, buffer)) {
+ switch (res) {
case TOKEN_IDENT:
left->ident = built_in_ident(buffer);
left->pos.noexpand = 0;
@@ -489,6 +499,21 @@
return 1;
}
}
+ break;
+
+ case TOKEN_WIDE_CHAR:
+ case TOKEN_WIDE_STRING:
+ token_type(left) = res;
+ left->pos.noexpand = 0;
+ left->string = right->string;
+ return 1;
+
+ case TOKEN_WIDE_CHAR + 1 ... TOKEN_WIDE_CHAR + 4:
+ token_type(left) = res;
+ left->pos.noexpand = 0;
+ memcpy(left->embedded, right->embedded, 4);
+ return 1;
+
default:
;
}
diff --git a/validation/preprocessor/wide.c b/validation/preprocessor/wide.c
new file mode 100644
index 0000000..21b643c
--- /dev/null
+++ b/validation/preprocessor/wide.c
@@ -0,0 +1,15 @@
+#define A(x) L##x
+A('a')
+A("bc")
+/*
+ * check-name: wide char token-pasting
+ * check-description: Used to cause infinite recursion.
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+L'a'
+L"bc"
+ * check-output-end
+ */
+