genksyms: Track changes to enum constants
Enum constants can be used as array sizes; if the enum itself does not appear in the symbol expansion, a change in the enum constant will go unnoticed. Example patch that changes the ABI but does not change the checksum with current genksyms: | enum e { | E1, | E2, |+ E3, | E_MAX | }; | | struct s { | int a[E_MAX]; | } | | int f(struct s *s) { ... } | EXPORT_SYMBOL(f) Therefore, remember the value of each enum constant and expand each occurence to <constant> <value>. The value is not actually computed, but instead an expression in the form (last explicitly assigned value) + N is used. This avoids having to parse and semantically understand whole of C. Note: The changes won't take effect until the lexer and parser are rebuilt by the next patch. Signed-off-by: Michal Marek <mmarek@suse.cz> Acked-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "genksyms.h"
|
||||
|
||||
static int is_typedef;
|
||||
@@ -227,16 +228,19 @@ type_specifier:
|
||||
add_symbol(i->string, SYM_UNION, s, is_extern);
|
||||
$$ = $3;
|
||||
}
|
||||
| ENUM_KEYW IDENT BRACE_PHRASE
|
||||
| ENUM_KEYW IDENT enum_body
|
||||
{ struct string_list *s = *$3, *i = *$2, *r;
|
||||
r = copy_node(i); r->tag = SYM_ENUM;
|
||||
r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
|
||||
add_symbol(i->string, SYM_ENUM, s, is_extern);
|
||||
$$ = $3;
|
||||
}
|
||||
|
||||
/* Anonymous s/u/e definitions. Nothing needs doing. */
|
||||
| ENUM_KEYW BRACE_PHRASE { $$ = $2; }
|
||||
/*
|
||||
* Anonymous enum definition. Tell add_symbol() to restart its counter.
|
||||
*/
|
||||
| ENUM_KEYW enum_body
|
||||
{ add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
|
||||
/* Anonymous s/u definitions. Nothing needs doing. */
|
||||
| STRUCT_KEYW class_body { $$ = $2; }
|
||||
| UNION_KEYW class_body { $$ = $2; }
|
||||
;
|
||||
@@ -449,6 +453,28 @@ attribute_opt:
|
||||
| attribute_opt ATTRIBUTE_PHRASE
|
||||
;
|
||||
|
||||
enum_body:
|
||||
'{' enumerator_list '}' { $$ = $3; }
|
||||
| '{' enumerator_list ',' '}' { $$ = $4; }
|
||||
;
|
||||
|
||||
enumerator_list:
|
||||
enumerator
|
||||
| enumerator_list ',' enumerator
|
||||
|
||||
enumerator:
|
||||
IDENT
|
||||
{
|
||||
const char *name = strdup((*$1)->string);
|
||||
add_symbol(name, SYM_ENUM_CONST, NULL, 0);
|
||||
}
|
||||
| IDENT '=' EXPRESSION_PHRASE
|
||||
{
|
||||
const char *name = strdup((*$1)->string);
|
||||
struct string_list *expr = copy_list_range(*$3, *$2);
|
||||
add_symbol(name, SYM_ENUM_CONST, expr, 0);
|
||||
}
|
||||
|
||||
asm_definition:
|
||||
ASM_PHRASE ';' { $$ = $2; }
|
||||
;
|
||||
|
Reference in New Issue
Block a user