diff mbox

[4/5] add a method to external_declaration()

Message ID 20170218203048.22276-5-luc.vanoostenryck@gmail.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Luc Van Oostenryck Feb. 18, 2017, 8:30 p.m. UTC
After parsing and validation, the symbols in the declaration
are added to the list given in argument, *if* they are not extern
symbols. The symbols that are extern are them not added to the list.

This is what is needed for usual declarations but ignoring extern
symbols make it impossible to emit a diagnostic in less usual
situation.

This is motivated by the validation of variable declaration inside
a for-loop initializer, which valid in C99 but only for variable
with local storage.

The changes consist in moving the part 'add the symbol to the list if
the symbol is not extern' to a separate function which will be called
by default.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 lib.c   |  2 +-
 parse.c | 22 +++++++++++++++-------
 parse.h |  3 ++-
 3 files changed, 18 insertions(+), 9 deletions(-)

Comments

Christopher Li Feb. 27, 2017, 3:37 p.m. UTC | #1
On Sun, Feb 19, 2017 at 4:30 AM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> After parsing and validation, the symbols in the declaration
> are added to the list given in argument, *if* they are not extern
> symbols. The symbols that are extern are them not added to the list.
>
> This is what is needed for usual declarations but ignoring extern
> symbols make it impossible to emit a diagnostic in less usual
> situation.

I have other situation want to use this as well.

> --- a/parse.h
> +++ b/parse.h
> @@ -129,7 +129,8 @@ extern int show_statement(struct statement *);
>  extern void show_statement_list(struct statement_list *, const char *);
>  extern int show_expression(struct expression *);
>
> -extern struct token *external_declaration(struct token *token, struct symbol_list **list);
> +typedef void (*add_decl_t)(struct symbol_list **list, struct symbol *decl);
> +extern struct token *external_declaration(struct token *token, add_decl_t add_decl, struct symbol_list **list);
>

I think the logic should be, "external_declaration" accept token as input.
For each newly declared symbol, it call to the callbacks function
to receive the symbol. The receive behavior is depend on the callback
function. The default function can be adding the symbol to a list.

So the struct symbol_list **list should turn into transparent argument as
context for the call back.

> --- a/lib.c
> +++ b/lib.c
> @@ -1080,7 +1080,7 @@ static struct symbol_list *sparse_tokenstream(struct token *token)
>
>         // Parse the resulting C code
>         while (!eof_token(token))
> -               token = external_declaration(token, &translation_unit_used_list);
> +               token = external_declaration(token, NULL, &translation_unit_used_list);

I prefer here just provide the default call back which is
add_stmt_decl in your case.

>         return translation_unit_used_list;
>  }
>
> diff --git a/parse.c b/parse.c
> index a4a126720..866186fd2 100644
> --- a/parse.c
> +++ b/parse.c
> @@ -2230,7 +2230,7 @@ static struct token *parse_for_statement(struct token *token, struct statement *
>         e1 = NULL;
>         /* C99 variable declaration? */
>         if (lookup_type(token)) {
> -               token = external_declaration(token, &syms);
> +               token = external_declaration(token, NULL, &syms);

Same here.


>         } else {
>                 token = parse_expression(token, &e1);
>                 token = expect(token, ';', "in 'for'");
> @@ -2457,7 +2457,7 @@ static struct token * statement_list(struct token *token, struct statement_list
>                                 seen_statement = 0;
>                         }
>                         stmt = alloc_statement(token->pos, STMT_DECLARATION);
> -                       token = external_declaration(token, &stmt->declaration);
> +                       token = external_declaration(token, NULL, &stmt->declaration);

And here.

> +       if (!add_decl)
> +               add_decl = add_stmt_decl;
> +

We don't need this if we ask the caller to provide the call back.


>         for (;;) {
>                 if (!is_typedef && match_op(token, '=')) {
>                         if (decl->ctype.modifiers & MOD_EXTERN) {
> @@ -2873,10 +2884,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
>                         token = initializer(&decl->initializer, token->next);
>                 }
>                 if (!is_typedef) {
> -                       if (!(decl->ctype.modifiers & (MOD_EXTERN | MOD_INLINE))) {
> -                               add_symbol(list, decl);
> -                               fn_local_symbol(decl);
> -                       }
> +                       add_decl(list, decl);
change this to some thing like:

if (add_decl)
                   add_decl(decl, decl_args);


>                 }
>                 check_declaration(decl);
>                 if (decl->same_symbol) {


Chris
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck Feb. 27, 2017, 9:34 p.m. UTC | #2
On Mon, Feb 27, 2017 at 4:37 PM, Christopher Li <sparse@chrisli.org> wrote:
> On Sun, Feb 19, 2017 at 4:30 AM, Luc Van Oostenryck
> <luc.vanoostenryck@gmail.com> wrote:
>> After parsing and validation, the symbols in the declaration
>> are added to the list given in argument, *if* they are not extern
>> symbols. The symbols that are extern are them not added to the list.
>>
>> This is what is needed for usual declarations but ignoring extern
>> symbols make it impossible to emit a diagnostic in less usual
>> situation.
>
> I have other situation want to use this as well.
>
>> --- a/parse.h
>> +++ b/parse.h
>> @@ -129,7 +129,8 @@ extern int show_statement(struct statement *);
>>  extern void show_statement_list(struct statement_list *, const char *);
>>  extern int show_expression(struct expression *);
>>
>> -extern struct token *external_declaration(struct token *token, struct symbol_list **list);
>> +typedef void (*add_decl_t)(struct symbol_list **list, struct symbol *decl);
>> +extern struct token *external_declaration(struct token *token, add_decl_t add_decl, struct symbol_list **list);
>>
>
> I think the logic should be, "external_declaration" accept token as input.
> For each newly declared symbol, it call to the callbacks function
> to receive the symbol. The receive behavior is depend on the callback
> function. The default function can be adding the symbol to a list.
>
> So the struct symbol_list **list should turn into transparent argument as
> context for the call back.

Yes, it can certainly be more general.

By 'transparent' you mean a void pointer?

For the two case currently concerned the callback argument can be a
statement pointer
because the two symbol list belong to a statement and I fact I
hesitated to use it or the list.
I choose the smallest change.

If for the other situation you talked here above, we can also use a
statement pointer,
I would prefrer to do so instead than using a void pointer but well it
doesn't matter much
anyway.


>> --- a/lib.c
>> +++ b/lib.c
>> @@ -1080,7 +1080,7 @@ static struct symbol_list *sparse_tokenstream(struct token *token)
>>
>>         // Parse the resulting C code
>>         while (!eof_token(token))
>> -               token = external_declaration(token, &translation_unit_used_list);
>> +               token = external_declaration(token, NULL, &translation_unit_used_list);
>
> I prefer here just provide the default call back which is
> add_stmt_decl in your case.

Sure, I can do this.


Luc
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck Feb. 28, 2017, 9:46 a.m. UTC | #3
On Mon, Feb 27, 2017 at 11:37:09PM +0800, Christopher Li wrote:
> On Sun, Feb 19, 2017 at 4:30 AM, Luc Van Oostenryck wrote:
> >
> > This is what is needed for usual declarations but ignoring extern
> > symbols make it impossible to emit a diagnostic in less usual
> > situation.
> 
> I have other situation want to use this as well.

...

> So the struct symbol_list **list should turn into transparent argument as
> context for the call back.
> 

...

> I prefer here just provide the default call back which is
> add_stmt_decl in your case.

OK. I've made the changes related to this and also prepared
for something more generic (like the name of the method).

I've left the arg type as 'symbol_list **' for the moment though,
it will be easy enough to change when/if needed.

Luc 
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck Feb. 28, 2017, 10:03 a.m. UTC | #4
This serie adds scope & storage validations of C99-style for-loop
initializers.

Patch 1 replaces the current indirect test by a direct one
Patch 2-3 add test cases for the scope & storage
Patch 4-5 add missing storage validation
Patch 6-7 move some checks into default_process_decl().

Changes since v1:
- better log message for patch 1, thanks to Ramsay Jones

Changes since v2:
- patches 1-3 are unchanged.
- do not use 'NULL' for the default method
- limit changes to parse.c, leaving external_declaration() untouched
- use a more generic and exact name for the method
- move a check to default_process_decl()


Luc Van Oostenryck (7):
  replace test for c99 for-loop initializers
  add test case for scope of C99 for-loop declarations
  add test cases for storage of c99 for-loop declarations
  add a method to external_declaration()
  check the storage of C99 for-loop initializers
  make process_decl() aware of the presence of an initializer
  move check extern with initializer to default_process_decl()

 parse.c                        | 54 ++++++++++++++++++++++++++++++++----------
 validation/c99-for-loop-decl.c | 40 +++++++++++++++++++++++++++++++
 validation/c99-for-loop.c      | 36 ++++++++++------------------
 3 files changed, 94 insertions(+), 36 deletions(-)
 create mode 100644 validation/c99-for-loop-decl.c
Christopher Li Feb. 28, 2017, 4:34 p.m. UTC | #5
On Tue, Feb 28, 2017 at 6:03 PM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> This serie adds scope & storage validations of C99-style for-loop
> initializers.

Just a heads up I am traveling in the next few days. My time and internet access
is unpredictable. I will try to apply them if I got a chance.  In the
worse case, I will
work on it on Sunday.

Chris
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck Feb. 28, 2017, 4:40 p.m. UTC | #6
On Tue, Feb 28, 2017 at 5:34 PM, Christopher Li <sparse@chrisli.org> wrote:
> On Tue, Feb 28, 2017 at 6:03 PM, Luc Van Oostenryck
> <luc.vanoostenryck@gmail.com> wrote:
>> This serie adds scope & storage validations of C99-style for-loop
>> initializers.
>
> Just a heads up I am traveling in the next few days. My time and internet access
> is unpredictable. I will try to apply them if I got a chance.  In the
> worse case, I will
> work on it on Sunday.
>
> Chris

OK. There is no urgency anyway but thanks for letting known.
Have a nice travel.
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/lib.c b/lib.c
index d47325243..9badc09b3 100644
--- a/lib.c
+++ b/lib.c
@@ -1080,7 +1080,7 @@  static struct symbol_list *sparse_tokenstream(struct token *token)
 
 	// Parse the resulting C code
 	while (!eof_token(token))
-		token = external_declaration(token, &translation_unit_used_list);
+		token = external_declaration(token, NULL, &translation_unit_used_list);
 	return translation_unit_used_list;
 }
 
diff --git a/parse.c b/parse.c
index a4a126720..866186fd2 100644
--- a/parse.c
+++ b/parse.c
@@ -2230,7 +2230,7 @@  static struct token *parse_for_statement(struct token *token, struct statement *
 	e1 = NULL;
 	/* C99 variable declaration? */
 	if (lookup_type(token)) {
-		token = external_declaration(token, &syms);
+		token = external_declaration(token, NULL, &syms);
 	} else {
 		token = parse_expression(token, &e1);
 		token = expect(token, ';', "in 'for'");
@@ -2457,7 +2457,7 @@  static struct token * statement_list(struct token *token, struct statement_list
 				seen_statement = 0;
 			}
 			stmt = alloc_statement(token->pos, STMT_DECLARATION);
-			token = external_declaration(token, &stmt->declaration);
+			token = external_declaration(token, NULL, &stmt->declaration);
 		} else {
 			seen_statement = Wdeclarationafterstatement;
 			token = statement(token, &stmt);
@@ -2785,7 +2785,15 @@  static struct token *toplevel_asm_declaration(struct token *token, struct symbol
 	return token;
 }
 
-struct token *external_declaration(struct token *token, struct symbol_list **list)
+static void add_stmt_decl(struct symbol_list **list, struct symbol *decl)
+{
+	if (!(decl->ctype.modifiers & (MOD_EXTERN | MOD_INLINE))) {
+		add_symbol(list, decl);
+		fn_local_symbol(decl);
+	}
+}
+
+struct token *external_declaration(struct token *token, add_decl_t add_decl, struct symbol_list **list)
 {
 	struct ident *ident = NULL;
 	struct symbol *decl;
@@ -2864,6 +2872,9 @@  struct token *external_declaration(struct token *token, struct symbol_list **lis
 		sparse_error(token->pos, "void declaration");
 	}
 
+	if (!add_decl)
+		add_decl = add_stmt_decl;
+
 	for (;;) {
 		if (!is_typedef && match_op(token, '=')) {
 			if (decl->ctype.modifiers & MOD_EXTERN) {
@@ -2873,10 +2884,7 @@  struct token *external_declaration(struct token *token, struct symbol_list **lis
 			token = initializer(&decl->initializer, token->next);
 		}
 		if (!is_typedef) {
-			if (!(decl->ctype.modifiers & (MOD_EXTERN | MOD_INLINE))) {
-				add_symbol(list, decl);
-				fn_local_symbol(decl);
-			}
+			add_decl(list, decl);
 		}
 		check_declaration(decl);
 		if (decl->same_symbol) {
diff --git a/parse.h b/parse.h
index a2b3e3889..d3199727e 100644
--- a/parse.h
+++ b/parse.h
@@ -129,7 +129,8 @@  extern int show_statement(struct statement *);
 extern void show_statement_list(struct statement_list *, const char *);
 extern int show_expression(struct expression *);
 
-extern struct token *external_declaration(struct token *token, struct symbol_list **list);
+typedef void (*add_decl_t)(struct symbol_list **list, struct symbol *decl);
+extern struct token *external_declaration(struct token *token, add_decl_t add_decl, struct symbol_list **list);
 
 extern struct symbol *ctype_integer(int size, int want_unsigned);