Skip to content

Commit

Permalink
Fix elaboration of function definitions with nested function types
Browse files Browse the repository at this point in the history
Since commit ea3a41b, `elab_type_declarator` has a special case for function definitions, causing it to include the function parameters in the returned updated typing environment.  However, this special case was wrong for nested function types such as
```
int (*f(int y))(int x) { ... }
```
`f` is a function taking an `y` parameter and returning a function `(x: int) -> int`.  The special case causes both `x` and `y` to be included in the returned environment, while only `y` should be.

This commit makes sure that the special case for function definitions applies only to the outermost function type, i.e. the innermost `Cabs.PROTO` declarator.

A similar issue was handled correctly in the `Cabs.PROTO_OLD` case, so this commit tries to use the same code structure in the `PROTO` and `PROTO_OLD` cases.
  • Loading branch information
xavierleroy committed Dec 13, 2024
1 parent 3f217e3 commit ec033c3
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 18 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Code generation and optimization:
Bug fixes:
- More robust determination of symbols that may be defined in a shared object. (#538)
- Escape `$NNN` identifiers in generated x86 and ARM assembly code (#541).
- Wrong parameter scoping in function definitions such as `int (*f(int y))(int x) { ... }` (a function returning a pointer to a prototyped function).

Usability:
- Mark stack as non-executable in binaries produced by `ccomp`.
Expand Down
40 changes: 23 additions & 17 deletions cparser/Elab.ml
Original file line number Diff line number Diff line change
Expand Up @@ -924,28 +924,34 @@ and elab_type_declarator ?(fundef = false) loc env ty = function
elab_return_type loc env ty;
let (ty, a) = get_nontype_attrs env ty in
let (params', env') = elab_parameters loc env params in
(* For a function declaration (fundef = false), the scope introduced
to treat parameters ends here, so we discard the extended
environment env' returned by elab_parameters.
For a function definition (fundef = true) we return the
extended environment env' so that it can serve as the basis
to elaborating the function body. *)
let env'' = if fundef then env' else env in
elab_type_declarator ~fundef loc env'' (TFun(ty, Some params', vararg, a)) d
let funty = TFun(ty, Some params', vararg, a) in
(* For a function declaration (fundef = false or d <> JUSTBASE),
the scope introduced to treat parameters ends here, so we
discard the extended environment env' returned by
elab_parameters.
For a function definition (fundef = true and d = JUSTBASE),
we return the extended environment env' so that it can serve
as the basis to elaborating the function body. *)
if fundef && d = Cabs.JUSTBASE then
((funty, None), env')
else
elab_type_declarator ~fundef loc env funty d
| Cabs.PROTO_OLD(d, params) ->
elab_return_type loc env ty;
let (ty, a) = get_nontype_attrs env ty in
let funty = TFun(ty, None, false, a) in
(* For consistency with the PROTO case above, for a function definition
(fundef = true) we open a new scope, even though we do not
add any bindings for the parameters. *)
let env'' = if fundef then Env.new_scope env else env in
match params with
| [] ->
elab_type_declarator ~fundef loc env'' (TFun(ty, None, false, a)) d
| _ ->
if not fundef || d <> Cabs.JUSTBASE then
(fundef = true and d = JUSTBASE) we open a new scope, even
though we do not add any bindings for the parameters. *)
if fundef && d = Cabs.JUSTBASE then begin
let env' = Env.new_scope env in
let opt_params = if params = [] then None else Some params in
((funty, opt_params), env')
end else begin
if params <> [] then
fatal_error loc "illegal old-style K&R function definition";
((TFun(ty, None, false, a), Some params), env'')
elab_type_declarator ~fundef loc env funty d
end

(* Elaboration of parameters in a prototype *)

Expand Down
2 changes: 1 addition & 1 deletion test

0 comments on commit ec033c3

Please sign in to comment.