Fix typedef/variable name conflict parsing error#219
Fix typedef/variable name conflict parsing error#219
Conversation
… register identifier before parsing initializer Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
…initialized declarators Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
… its declarator via helper rules Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
…t_start; update test Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
… typedef guard Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
|
@sim642: This looks reasonable now! |
src/frontc/cparser.mly
Outdated
| of its declarator). For typedef declarations (is_typedef_decl = true), the name | ||
| is registered later via add_type in doDeclaration. *) */ |
There was a problem hiding this comment.
I haven't looked at this in detail but introducing even more global state into the parser is a bit worrying.
Is typedef scoping actually defined to work differently like this by the standard? Or maybe it would also be the right thing to do the add_type stuff earlier than at the very end?
Perhaps one typedef could also define multiple types with commas (I haven't looked at the standard grammar) and then it would also matter there (and even be more correct)?
I might be optimistically hoping for more consistency and less special-casing than C actually has...
There was a problem hiding this comment.
@copilot Look up the details of this in the standard and either implement Simmo's suggestion or argue why it is not a good idea.
There was a problem hiding this comment.
Implemented in aa40855.
C11 6.2.1.7: "Any other identifier has scope that begins just after the completion of its declarator." This applies uniformly to all declarations — typedef names included. So moving add_type earlier (per-declarator) is both correct and more standard-conformant.
What changed: declarator_no_init now handles both cases with a single branch:
add_type nwhenis_typedef_decl = true(typedef declarators)add_identifier nwhenis_typedef_decl = false(variable declarators)
doDeclaration now has zero lexer management — it only builds AST nodes (TYPEDEF / ONLYTYPEDEF / DECDEF).
On the is_typedef_decl global flag: it's still necessary. Yacc reductions are bottom-up — by the time declarator_no_init reduces, the TYPEDEF keyword has already been consumed (in decl_spec_list_common). There's no way to pass this context through grammar parameters in standard yacc without a mid-rule side effect, which is what is_typedef_decl provides. The flag is set by the TYPEDEF rule and cleared by doDeclaration, giving it a well-defined lifetime that spans exactly the declarator list of a typedef declaration.
On typedef commas: per the C grammar, typedef int T, *TP; uses the same init_declarator_list → init_declarator path as variables. With this change, T and TP each get add_type called immediately after their declarator — so a hypothetical typedef int T, T_alias; would see T as already registered when T_alias is parsed. This is C11-correct behaviour.
…rator, none in doDeclaration Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> Agent-Logs-Url: https://github.com/goblint/cil/sessions/459679d3-44f6-4f0b-8a30-92252ab7fa0d
test/small1/typedef_varname.cfor the typedef/variable name conflicttest/testcil.plinit_declaratorrule insrc/frontc/cparser.mlyto calladd_identifierviadeclarator_init_starthelper rule between declarator and EQcparser.mlyto use/* (* TEXT *) */as per file conventionsadd_identifier/add_typetiming:declarator_no_initimmediately registers each declarator's name —add_typefor typedef declarators,add_identifierfor non-typedef declarators (C11 6.2.1.7: scope begins just after completion of declarator);declarator_init_startregisters initialized declarators before their=;doDeclarationnow only creates AST nodes with no lexer managementtest/small1/typedef_varname_noinit.cto test multiple initialized declarators: verifies that the second declarator's initializer can reference the first declared variable (which shadows a typedef), exercisingdeclarator_init_starttest/scope2:declarator_no_initcallsadd_type(notadd_identifier) for typedef declarators, so names are never added to the context tracking list andpop_contextcannot remove the wrong bindingtypedef_varname.c:mytype a = 1, mytype, b = sizeof mytype—sizeof mytype(without parens) is only valid whenmytypeis a variable, proving correct C11 6.2.1.7 scoping for NO_INIT declarators in mixed declaration listsOriginal prompt
typedefand variable name conflict parsing error #114🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.