[PATCH 2/2] builtin: add support for __has_builtin()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sparse has support for a subset of GCC's large collection of builtin
functions. As for GCC, it's not easy to know which builtins are
supported in which versions.

clang has a good solution to this problem: it adds the checking macro
__has_builtin(<name>) which evaluates to 1 if <name> is a builtin
function supported by the compiler and 0 otherwise.
It can be used like:
	#if __has_builtin(__builtin_clz)
	#define clz(x)	__builtin_clz(x)
	#else
	...
	#endif

It's possible or probable that GCC will have this soon too:
	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970

Add support for this __has_builtin() macro by extending
the evaluation of preprocessor expressions very much like
it is done to support defined().

Note: Some function-like builtin features, like __builtin_offset(), are
      considered as a kind of keyword/operator and processed as such.
      These are *not* considered as builtins by __has_builtin().

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
---
 builtin.c                             |  2 ++
 ident-list.h                          |  1 +
 lib.c                                 |  1 +
 pre-process.c                         | 37 +++++++++++++++++++++++
 symbol.h                              |  1 +
 validation/preprocessor/has-builtin.c | 43 +++++++++++++++++++++++++++
 6 files changed, 85 insertions(+)
 create mode 100644 validation/preprocessor/has-builtin.c

diff --git a/builtin.c b/builtin.c
index 0114c4ca9..b3460847b 100644
--- a/builtin.c
+++ b/builtin.c
@@ -360,6 +360,7 @@ void init_builtins(int stream)
 		sym->ctype.base_type = ptr->base_type;
 		sym->ctype.modifiers = ptr->modifiers;
 		sym->op = ptr->op;
+		sym->builtin = 1;
 	}
 }
 
@@ -373,6 +374,7 @@ static void declare_builtin(const char *name, struct symbol *rtype, int variadic
 
 	sym->ctype.base_type = fun;
 	sym->ctype.modifiers = MOD_TOPLEVEL;
+	sym->builtin = 1;
 
 	fun->ctype.base_type = rtype;
 	fun->variadic = variadic;
diff --git a/ident-list.h b/ident-list.h
index 2f1fecb48..9abb2e5a7 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -59,6 +59,7 @@ IDENT_RESERVED(__label__);
  * sparse. */
 IDENT(defined);
 IDENT(once);
+IDENT(__has_builtin);
 __IDENT(pragma_ident, "__pragma__", 0);
 __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
 __IDENT(__LINE___ident, "__LINE__", 0);
diff --git a/lib.c b/lib.c
index c451a88ce..b33e5b946 100644
--- a/lib.c
+++ b/lib.c
@@ -1244,6 +1244,7 @@ static void create_builtin_stream(void)
 			assert (0);
 	}
 
+	add_pre_buffer("#define __has_builtin(x) 0\n");
 	add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
 	add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
 	add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
diff --git a/pre-process.c b/pre-process.c
index 7bc4a00fd..783ce6987 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -158,6 +158,12 @@ static void replace_with_defined(struct token *token)
 	replace_with_bool(token, token_defined(token));
 }
 
+static void replace_with_has_builtin(struct token *token)
+{
+	struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
+	replace_with_bool(token, sym && sym->builtin);
+}
+
 static int expand_one_symbol(struct token **list)
 {
 	struct token *token = *list;
@@ -1509,6 +1515,10 @@ static int expression_value(struct token **where)
 				state = 1;
 				beginning = list;
 				break;
+			} else if (p->ident == &__has_builtin_ident) {
+				state = 4;
+				beginning = list;
+				break;
 			}
 			if (!expand_one_symbol(list))
 				continue;
@@ -1539,6 +1549,33 @@ static int expression_value(struct token **where)
 				sparse_error(p->pos, "missing ')' after \"defined\"");
 			*list = p->next;
 			continue;
+
+		// __has_builtin(xyz)
+		case 4:
+			if (match_op(p, '(')) {
+				state = 5;
+			} else {
+				sparse_error(p->pos, "missing '(' after \"__has_builtin\"");
+				state = 0;
+			}
+			*beginning = p;
+			break;
+		case 5:
+			if (token_type(p) != TOKEN_IDENT) {
+				sparse_error(p->pos, "identifier expected");
+				state = 0;
+				break;
+			}
+			if (!match_op(p->next, ')'))
+				sparse_error(p->pos, "missing ')' after \"__has_builtin\"");
+			state = 6;
+			replace_with_has_builtin(p);
+			*beginning = p;
+			break;
+		case 6:
+			state = 0;
+			*list = p->next;
+			continue;
 		}
 		list = &p->next;
 	}
diff --git a/symbol.h b/symbol.h
index 2792df24f..2527584e2 100644
--- a/symbol.h
+++ b/symbol.h
@@ -173,6 +173,7 @@ struct symbol {
 					designated_init:1,
 					forced_arg:1,
 					accessed:1,
+					builtin:1,
 					transparent_union:1;
 			struct expression *array_size;
 			struct ctype ctype;
diff --git a/validation/preprocessor/has-builtin.c b/validation/preprocessor/has-builtin.c
new file mode 100644
index 000000000..03272fc95
--- /dev/null
+++ b/validation/preprocessor/has-builtin.c
@@ -0,0 +1,43 @@
+#ifndef __has_builtin
+__has_builtin()??? Quesako?
+#define __has_builtin(x) 0
+#else
+"has __has_builtin(), yeah!"
+#endif
+
+#if __has_builtin(nothing)
+#error "not a builtin!"
+#endif
+
+#if __has_builtin(__builtin_offsetof)		\
+ || __has_builtin(__builtin_types_compatible_p)
+#error "builtin ops are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_va_list)		\
+ || __has_builtin(__builtin_ms_va_list)
+#error "builtin types are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_abs)
+abs
+#endif
+
+#if __has_builtin(__builtin_constant_p)
+constant_p
+#endif
+
+123 __has_builtin(abc) def
+
+/*
+ * check-name: has-builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_builtin(), yeah!"
+abs
+constant_p
+123 0 def
+ * check-output-end
+ */
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux