From: Randy Dunlap <rdunlap@xenotime.net>
with help from Linus.

sparse additions to:
- check for C/C++ keywords: usage: -keywords
- print all global data symbols and their sizes: usage: -list-symbols
  Example of -list-symbols:
  make C=2 CF="-list-symbols" arch/x86_64/kernel/smpboot.o
  arch/x86_64/kernel/smpboot.c:90:20: struct cpuinfo_x86 [addressable] [toplevel] [assigned] cpu_data[8]: compound size 1344, alignment 64

Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
---
 lib.c    |   31 +++++++++++++++++++++++++++++++
 sparse.c |   47 ++++++++++++++++++++++++++++++++++++++++++++++-
 symbol.c |   33 ++++++++++++++++++++++++++++++---
 3 files changed, 107 insertions(+), 4 deletions(-)

--- sparse-2007-07-24.orig/sparse.c
+++ sparse-2007-07-24/sparse.c
@@ -20,6 +20,7 @@
 #include "allocate.h"
 #include "token.h"
 #include "parse.h"
+#include "scope.h"
 #include "symbol.h"
 #include "expression.h"
 #include "linearize.h"
@@ -273,6 +274,42 @@ static void check_symbols(struct symbol_
 	} END_FOR_EACH_PTR(sym);
 }
 
+extern int list_symbols;
+
+static void list_all_symbols(struct symbol_list *list)
+{
+	struct symbol *sym;
+
+	FOR_EACH_PTR(list, sym) {
+		/* Only show arrays, structures, unions, enums, & typedefs */
+		if (!(sym->namespace & (NS_STRUCT | NS_TYPEDEF | NS_SYMBOL)))
+			continue;
+		/* Only show types we actually examined (ie used) */
+		if (!sym->bit_size)
+			continue;
+		if (sym->type == SYM_FN || sym->type == SYM_ENUM)
+			continue;
+		if (!sym->ctype.base_type)
+			continue;
+		if (sym->ctype.base_type->type == SYM_FN)
+			continue;
+		if (sym->ctype.base_type->type == SYM_ENUM)
+			continue;
+		if (sym->ctype.base_type->type == SYM_BASETYPE)
+			continue;
+		/* Don't show unnamed types */
+		if (!sym->ident)
+			continue;
+		///printf("%s: size %u, alignment %lu\n",
+		///info(sym->pos, "%s (0x%x:base 0x%x): compound size %u, alignment %lu",
+		info(sym->pos, "%s: compound size %u, alignment %lu",
+			show_typename(sym), ///sym->type,
+			///sym->ctype.base_type->type,
+			sym->bit_size >> 3,
+			sym->ctype.alignment);
+	} END_FOR_EACH_PTR(sym);
+}
+
 int main(int argc, char **argv)
 {
 	struct string_list *filelist = NULL;
@@ -281,7 +318,15 @@ int main(int argc, char **argv)
 	// Expand, linearize and show it.
 	check_symbols(sparse_initialize(argc, argv, &filelist));
 	FOR_EACH_PTR_NOTAG(filelist, file) {
-		check_symbols(sparse(file));
+		struct symbol_list *res = sparse(file);
+
+		check_symbols(res);
+
+		// List all symbols...
+		if (list_symbols)
+			///list_all_symbols(block_scope->symbols);
+			list_all_symbols(res);
 	} END_FOR_EACH_PTR_NOTAG(file);
+
 	return 0;
 }
--- sparse-2007-07-24.orig/lib.c
+++ sparse-2007-07-24/lib.c
@@ -213,6 +213,8 @@ int dbg_entry = 0;
 int dbg_dead = 0;
 
 int preprocess_only;
+int list_symbols = 0;
+int keywords_all = 0;
 
 #define CMDLINE_INCLUDE 20
 int cmdline_include_nr = 0;
@@ -308,6 +310,31 @@ static char **handle_switch_i(char *arg,
 	return next;
 }
 
+void handle_switch_pre(int argc, char **argv)
+{
+	char **args = argv;
+
+	for (;;) {
+		char *arg = *++args;
+		if (!arg)
+			break;
+
+		if (arg[0] == '-' && arg[1]) {
+			if (!strcmp(arg + 1, "keywords")) {
+				keywords_all = 1;
+				continue;
+			}
+		}
+	}
+}
+
+char **handle_switch_l(char *arg, char **next)
+{
+	if (!strcmp(arg, "list-symbols"))
+		list_symbols = 1;
+	return next;
+}
+
 static char **handle_switch_M(char *arg, char **next)
 {
 	if (!strcmp(arg, "MF") || !strcmp(arg,"MQ") || !strcmp(arg,"MT")) {
@@ -529,6 +556,7 @@ char **handle_switch(char *arg, char **n
 	case 'E': return handle_switch_E(arg, next);
 	case 'I': return handle_switch_I(arg, next);
 	case 'i': return handle_switch_i(arg, next);
+	case 'l': return handle_switch_l(arg, next);
 	case 'M': return handle_switch_M(arg, next);
 	case 'm': return handle_switch_m(arg, next);
 	case 'o': return handle_switch_o(arg, next);
@@ -710,6 +738,9 @@ struct symbol_list *sparse_initialize(in
 	char **args;
 	struct symbol_list *list;
 
+	// allow some switches (like "keywords") before init_symbols();
+	handle_switch_pre(argc, argv);
+
 	// Initialize symbol stream first, so that we can add defines etc
 	init_symbols();
 
--- sparse-2007-07-24.orig/symbol.c
+++ sparse-2007-07-24/symbol.c
@@ -545,7 +545,7 @@ void bind_symbol(struct symbol *sym, str
 	}
 	if (ident->reserved && (ns & (NS_TYPEDEF | NS_STRUCT | NS_LABEL | NS_SYMBOL))) {
 		sparse_error(sym->pos, "Trying to use reserved word '%s' as identifier", show_ident(ident));
-		return;
+		///return;
 	}
 	sym->namespace = ns;
 	sym->next_id = ident->symbols;
@@ -694,12 +694,13 @@ out:
  *
  * "double" == "long float", "long double" == "long long float"
  */
-static struct sym_init {
+struct sym_init {
 	const char *name;
 	struct symbol *base_type;
 	unsigned int modifiers;
 	struct symbol_op *op;
-} symbol_init_table[] = {
+};
+static struct sym_init symbol_init_table[] = {
 	/* Storage class */
 	{ "auto",	NULL,		MOD_AUTO },
 	{ "register",	NULL,		MOD_REGISTER },
@@ -727,6 +728,24 @@ static struct sym_init {
 	{ NULL,		NULL,		0 }
 };
 
+extern int keywords_all;
+const char * all_keywords[] = {
+/* more c_keywords[] */
+	"_Complex", "_Imaginary", "__thread",
+/* and cpp_keywords[] */
+	"bool", "catch", "class",
+	"complex", "__complex__", "const_cast",
+	"delete", "dynamic_cast",
+	"explicit", "export",
+	"false", "friend",
+	"mutable", "namespace", "new",
+	"operator", "private", "protected", "public",
+	"reinterpret_cast", "static_cast",
+	"template", "this", "throw",
+	"true", "try", "typeid", "typename",
+	"using", "virtual", "wchar_t",
+};
+
 static struct symbol_op constant_p_op = {
 	.evaluate = evaluate_to_integer,
 	.expand = expand_constant_p
@@ -812,6 +831,14 @@ void init_symbols(void)
 		sym->ctype.base_type = ptr->base_type;
 		sym->ctype.modifiers = ptr->modifiers;
 	}
+	if (keywords_all) {
+		int kx;
+
+		for (kx = 0; kx < sizeof(all_keywords) / sizeof(char *); kx++) {
+			struct ident *ident = built_in_ident(all_keywords [kx]);
+			ident->reserved = 1;
+		}
+	}
 
 	builtin_fn_type.variadic = 1;
 	for (ptr = eval_init_table; ptr->name; ptr++) {
