aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-03-12 08:07:05 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-03-15 23:52:18 +0100
commit5c2338f694cda83c28a96e198f8de13bc1cde8b4 (patch)
treee57287cb59c7beb2c330d41e65e2f3158a433714
parent0e3729b3edb8d3f384c907127f664e38bd7adab8 (diff)
downloadsparse-5c2338f694cda83c28a96e198f8de13bc1cde8b4.tar.gz
cpp: silently allow conditional directives within a macro
The presence of preprocessor directives within the arguments of a macro invocation is Undefined Behaviour [6.10.3p11]. However, conditional directives are harmless here and are useful (and commonly used in the kernel). So, relax the warning by restricting it to non-conditional directives. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--pre-process.c17
-rw-r--r--validation/preprocessor/directive-within-macro.c40
-rw-r--r--validation/preprocessor/preprocessor22.c2
3 files changed, 55 insertions, 4 deletions
diff --git a/pre-process.c b/pre-process.c
index 82bfa402..a5a3c5fb 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -48,6 +48,7 @@ static struct ident_list *macros; // only needed for -dD
static int false_nesting = 0;
static int counter_macro = 0; // __COUNTER__ expansion
static int include_level = 0;
+static int expanding = 0;
#define INCLUDEPATHS 300
const char *includepath[INCLUDEPATHS+1] = {
@@ -232,8 +233,13 @@ static int expand_one_symbol(struct token **list)
sym->expander(token);
return 1;
} else {
+ int rc;
+
sym->used_in = file_scope;
- return expand(list, sym);
+ expanding = 1;
+ rc = expand(list, sym);
+ expanding = 0;
+ return rc;
}
}
@@ -271,8 +277,6 @@ static struct token *collect_arg(struct token *prev, int vararg, struct position
while (!eof_token(next = scan_next(p))) {
if (next->pos.newline && match_op(next, '#')) {
if (!next->pos.noexpand) {
- warning(next->pos,
- "directive in macro's argument list");
preprocessor_line(stream, p);
__free_token(next); /* Free the '#' token */
continue;
@@ -2073,6 +2077,7 @@ static void handle_preprocessor_line(struct stream *stream, struct token **line,
int (*handler)(struct stream *, struct token **, struct token *);
struct token *token = start->next;
int is_normal = 1;
+ int is_cond = 0; // is one of {is,ifdef,ifndef,elif,else,endif}
if (eof_token(token))
return;
@@ -2082,6 +2087,7 @@ static void handle_preprocessor_line(struct stream *stream, struct token **line,
if (sym) {
handler = sym->handler;
is_normal = sym->normal;
+ is_cond = !sym->normal;
} else {
handler = handle_nondirective;
}
@@ -2096,6 +2102,11 @@ static void handle_preprocessor_line(struct stream *stream, struct token **line,
if (false_nesting)
goto out;
}
+
+ if (expanding) {
+ if (!is_cond || Wpedantic)
+ warning(start->pos, "directive in macro's argument list");
+ }
if (!handler(stream, line, token)) /* all set */
return;
diff --git a/validation/preprocessor/directive-within-macro.c b/validation/preprocessor/directive-within-macro.c
new file mode 100644
index 00000000..5269d4a7
--- /dev/null
+++ b/validation/preprocessor/directive-within-macro.c
@@ -0,0 +1,40 @@
+#define f(x) x
+
+f(1
+#if 1 // OK
+ a
+#elif 2 // OK
+ b
+#else // OK
+ c
+#endif // OK
+#ifdef f // OK
+ d
+#endif // OK
+#ifndef f // OK
+ e
+#endif // OK
+ 3)
+
+f(1
+#define x y // KO
+ 3)
+
+/*
+ * check-name: directive-within-macro
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+1
+a
+d
+3
+1
+3
+ * check-output-end
+ *
+ * check-error-start
+preprocessor/directive-within-macro.c:20:1: warning: directive in macro's argument list
+ * check-error-end
+ */
diff --git a/validation/preprocessor/preprocessor22.c b/validation/preprocessor/preprocessor22.c
index 277334c6..11f625c0 100644
--- a/validation/preprocessor/preprocessor22.c
+++ b/validation/preprocessor/preprocessor22.c
@@ -17,7 +17,7 @@ define_struct(a, {
* check-description: Directives are not allowed within a macro argument list,
* although cpp deals with it to treat macro more like C functions.
*
- * check-command: sparse -E $file
+ * check-command: sparse -pedantic -E $file
*
* check-error-start
preprocessor/preprocessor22.c:6:1: warning: directive in macro's argument list