-
Notifications
You must be signed in to change notification settings - Fork 24
Fix typedef/variable name conflict parsing error #219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
3494d12
98004a6
f9a7b12
d8822cc
160543c
d977be5
363114d
5960536
aa40855
66f8d59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,18 +115,18 @@ let applyPointer (ptspecs: attribute list list) (dt: decl_type) | |
| loop ptspecs | ||
|
|
||
| let doDeclaration (loc: cabsloc) (specs: spec_elem list) (nl: init_name list) : definition = | ||
| if isTypedef specs then begin | ||
| (* Tell the lexer about the new type names *) | ||
| List.iter (fun ((n, _, _, _), _) -> !Lexerhack.add_type n) nl; | ||
| Lexerhack.is_typedef_decl := false; | ||
| (* Lexer registrations (add_type / add_identifier) are done per-declarator in | ||
| declarator_no_init / declarator_init_start as each declarator is parsed | ||
| (C11 6.2.1.7: scope begins just after the completion of the declarator), so | ||
| nothing to do here. *) | ||
| if isTypedef specs then | ||
| TYPEDEF ((specs, List.map (fun (n, _) -> n) nl), loc) | ||
| end else | ||
| else | ||
| if nl = [] then | ||
| ONLYTYPEDEF (specs, loc) | ||
| else begin | ||
| (* Tell the lexer about the new variable names *) | ||
| List.iter (fun ((n, _, _, _), _) -> !Lexerhack.add_identifier n) nl; | ||
| else | ||
| DECDEF ((specs, nl), loc) | ||
| end | ||
|
|
||
|
|
||
| let doFunctionDef (loc: cabsloc) | ||
|
|
@@ -388,7 +388,7 @@ let transformOffsetOf (speclist, dtype) member = | |
|
|
||
| %type <Cabs.init_name> init_declarator | ||
| %type <Cabs.init_name list> init_declarator_list | ||
| %type <Cabs.name> declarator | ||
| %type <Cabs.name> declarator declarator_no_init declarator_init_start | ||
| %type <Cabs.name * expression option> field_decl | ||
| %type <(Cabs.name * expression option) list> field_decl_list | ||
| %type <string * Cabs.decl_type> direct_decl | ||
|
|
@@ -1036,14 +1036,38 @@ init_declarator_attr: | |
|
|
||
| ; | ||
| init_declarator: /* ISO 6.7 */ | ||
| declarator { ($1, NO_INIT) } | ||
| | declarator EQ init_expression location | ||
| { let (n, d, a, l) = $1 in ((n, d, a, joinLoc l $4), $3) } | ||
| declarator_no_init { ($1, NO_INIT) } | ||
| | declarator_init_start init_expression location | ||
| { let (n, d, a, l) = $1 in ((n, d, a, joinLoc l $3), $2) } | ||
| ; | ||
|
|
||
| /* (* Parses "declarator" (without initializer) and immediately registers the | ||
| declared name in the lexer hack, per C11 6.2.1.7 (scope begins just after | ||
| the completion of its declarator). | ||
| - For non-typedef declarations: calls add_identifier so subsequent | ||
| declarators in the same list see the name as a variable (not a type). | ||
| - For typedef declarations (Lexerhack.is_typedef_decl = true): calls add_type so | ||
| subsequent declarators see the name as a type. | ||
| In both cases every declarator is registered at the right time without | ||
| going through doDeclaration. *) */ | ||
| declarator_no_init: | ||
| declarator { let (n, _, _, _) = $1 in | ||
| if !Lexerhack.is_typedef_decl then !Lexerhack.add_type n | ||
| else !Lexerhack.add_identifier n; | ||
| $1 } | ||
| ; | ||
|
|
||
| /* (* Parses "declarator =" and adds the declared name as a variable identifier | ||
| in the lexer hack, so that in the initializer the name shadows any typedef | ||
| with the same name (C11 6.2.1.7: scope begins just after the completion of the | ||
| declarator). *) */ | ||
| declarator_init_start: | ||
| declarator EQ { let (n, _, _, _) = $1 in !Lexerhack.add_identifier n; $1 } | ||
|
Comment on lines
+1053
to
+1065
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not do the lexer hack in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving the registration into
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An interesting question here is: where exactly in the C standard is it stated that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apparently, the grammar doesn't explicitly ban it, but one can get some kind of semantic ban out of
C11 draft as typedefs do not define objects.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still, there's no need for two new grammar rules. The Having Instead, I would expect
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what exactly you suggest here. If you're happy with the rest of it feel free to push directly to this branch. I'll have a look at it and then we can merge. |
||
| ; | ||
|
|
||
| decl_spec_list_common: /* ISO 6.7 */ | ||
| /* ISO 6.7.1 */ | ||
| | TYPEDEF decl_spec_list_opt { SpecTypedef :: $2, $1 } | ||
| | TYPEDEF decl_spec_list_opt { Lexerhack.is_typedef_decl := true; SpecTypedef :: $2, $1 } | ||
| | EXTERN decl_spec_list_opt { SpecStorage EXTERN :: $2, $1 } | ||
| | STATIC decl_spec_list_opt { SpecStorage STATIC :: $2, $1 } | ||
| | AUTO decl_spec_list_opt { SpecStorage AUTO :: $2, $1 } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /* Test for typedef and variable name conflict (issue #114). | ||
| A variable with the same name as a typedef should shadow it in its initializer, | ||
| per C11 6.2.1.7: "Any other identifier has scope that begins just after the | ||
| completion of its declarator." */ | ||
| #include "testharness.h" | ||
| #include <stdint.h> | ||
| #include <stdlib.h> | ||
|
|
||
| typedef struct raxNode { | ||
| uint32_t iskey:1; | ||
| uint32_t isnull:1; | ||
| uint32_t iscompr:1; | ||
| uint32_t size:29; | ||
| unsigned char data[]; | ||
| } raxNode; | ||
|
|
||
| typedef struct rax { | ||
| raxNode *head; | ||
| uint64_t numele; | ||
| uint64_t numnodes; | ||
| } rax; | ||
|
|
||
| typedef int mytype; | ||
| typedef int T; | ||
|
|
||
| int main() { | ||
| rax *rax = malloc(sizeof(*rax)); /* variable rax shadows typedef rax in initializer */ | ||
| if (rax == 0) E(1); | ||
| free(rax); | ||
|
|
||
| /* NO_INIT variable in the middle of a declaration list shadows a typedef. | ||
| After "mytype a = 1, mytype", the name "mytype" is an identifier (variable). | ||
| So "b = sizeof mytype" (without parens) is only valid when mytype is a variable | ||
| (types require parens: "sizeof(type)"). This fails to parse without the fix. */ | ||
| { | ||
| mytype a = 1, mytype, b = sizeof mytype; | ||
| mytype = 5; | ||
| if (a != 1) E(2); | ||
| if (mytype != 5) E(3); | ||
| if (b != sizeof(int)) E(4); | ||
| } | ||
|
|
||
| /* Chain initialization: after "T T = 1", T is registered as a variable by the | ||
| lexer hack, so the subsequent initializer "U = T + 1" sees T as a variable | ||
| (value 1), not as a type name. This fails to parse without the fix because | ||
| "T + 1" would be a syntax error when T is a NAMED_TYPE. */ | ||
| { | ||
| T T = 1, U = T + 1; | ||
| if (T != 1) E(5); | ||
| if (U != 2) E(6); | ||
| } | ||
|
|
||
| SUCCESS; | ||
| } | ||
|
michael-schwarz marked this conversation as resolved.
|
||
Uh oh!
There was an error while loading. Please reload this page.