Skip to content

Commit 6cfe724

Browse files
committed
Handle casts to function pointers
1 parent 6414ce2 commit 6cfe724

5 files changed

Lines changed: 89 additions & 31 deletions

File tree

README.md.in

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,6 @@ macro | description | default
8686

8787
## Limitations
8888

89-
- Casting to a function pointer:
90-
```c
91-
uprintf("%S\n", (void (*)(void)) whatever);
92-
```
93-
9489
- Incorrect type deduction when printing variables that get shadowed *later* in the same scope.
9590
```c
9691
char var = 'c';

test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ if [ $ret -ne 0 ]; then
135135
exit 1
136136
fi
137137

138-
if [ ! -r $baseline ]; then
138+
if [ ! -r $baseline ] || [ ! -s $baseline ]; then
139139
echo -e "$YELLOW[WARNING]$RESET There is no $test baseline."
140140
echo -e "$GREEN[TEST PASSED]$RESET $test_id: ?";
141141
exit 0

tests/baselines/function_casts.out

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
1
2+
2
3+
3
4+
4
5+
5
6+
6
7+
7
8+
8

tests/function_casts.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "uprintf.h"
2+
3+
int *i_fun(int i) {
4+
static int j;
5+
j = i;
6+
return &j;
7+
}
8+
9+
int *(*j_fun(char c))(int i) {
10+
(void) c;
11+
return i_fun;
12+
}
13+
14+
int *(*(**k_fun(void))(char c))(int i) {
15+
static int *(*(*t)(char) )(int) = j_fun;
16+
return &t;
17+
}
18+
19+
int main(void) {
20+
uprintf("%s\n", ((int *(*) (int) ) i_fun)(1));
21+
uprintf("%s\n", ((int *((*) )(int) ) i_fun)(2));
22+
uprintf("%s\n", ((int *((*) (int) )) i_fun)(3));
23+
24+
uprintf("%s\n", (((int *((*(*) (char) )(int) )) j_fun)('a')(4)));
25+
uprintf("%s\n", (((int *((*((*) (char) ))(int) )) j_fun)('b')(5)));
26+
uprintf("%s\n", (((int *((*(((*) (char) )))(int) )) j_fun)('c')(6)));
27+
28+
uprintf("%s\n", (*((int *(*(**(*) (void) )(char) )(int) ) k_fun)())('d')(7));
29+
uprintf("%s\n", (*((int *(*((**(*) (void) )(char) ))(int) ) k_fun)())('e')(8));
30+
31+
return _upf_test_status;
32+
}

uprintf.h

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,6 +2516,44 @@ static _upf_type *_upf_parse(_upf_parse_precedence precedence);
25162516

25172517
static _upf_type *_upf_parse_expression(void) { return _upf_parse(_UPF_PREC_ASSIGNMENT); }
25182518

2519+
static int _upf_parse_abstract_declarator(_upf_type **function_type, _upf_type ***function_return_type) {
2520+
_UPF_ASSERT(function_type != NULL && function_return_type != NULL);
2521+
2522+
int pointers = 0;
2523+
while (_upf_match_token(_UPF_TOK_STAR)) {
2524+
pointers++;
2525+
while (_upf_match_token(_UPF_TOK_TYPE_QUALIFIER)) continue;
2526+
}
2527+
2528+
if (!_upf_match_token(_UPF_TOK_OPEN_PAREN)) return pointers;
2529+
int sub_pointers = _upf_parse_abstract_declarator(function_type, function_return_type);
2530+
_upf_expect_token(_UPF_TOK_CLOSE_PAREN);
2531+
2532+
if (!_upf_match_token(_UPF_TOK_OPEN_PAREN)) return pointers + sub_pointers;
2533+
_upf_consume_parens(_UPF_TOK_OPEN_PAREN, _UPF_TOK_CLOSE_PAREN);
2534+
2535+
_UPF_ASSERT(sub_pointers > 0);
2536+
sub_pointers--;
2537+
2538+
_upf_type *current_function_type = _upf_add_type(NULL, (_upf_type) {
2539+
.kind = _UPF_TK_FUNCTION,
2540+
.size = sizeof(void *),
2541+
});
2542+
_upf_type **current_function_return_type = &current_function_type->as.function.return_type;
2543+
2544+
while (sub_pointers-- > 0) current_function_type = _upf_get_pointer_to_type(current_function_type);
2545+
2546+
if (*function_type == NULL) {
2547+
*function_type = current_function_type;
2548+
} else {
2549+
_UPF_ASSERT(*function_return_type != NULL);
2550+
**function_return_type = current_function_type;
2551+
}
2552+
2553+
*function_return_type = current_function_return_type;
2554+
return pointers;
2555+
}
2556+
25192557
static _upf_type *_upf_parse_typename(void) {
25202558
const char *type_specifiers[4];
25212559
size_t type_specifiers_idx = 0;
@@ -2560,29 +2598,9 @@ static _upf_type *_upf_parse_typename(void) {
25602598
}
25612599
}
25622600

2563-
int pointer = 0;
2564-
while (_upf_match_token(_UPF_TOK_STAR)) {
2565-
pointer++;
2566-
while (_upf_match_token(_UPF_TOK_TYPE_QUALIFIER)) continue;
2567-
}
2568-
2569-
bool parsed_declarator = false;
2570-
while (!parsed_declarator) {
2571-
switch (_upf_peek_token().kind) {
2572-
case _UPF_TOK_OPEN_PAREN:
2573-
// TODO:
2574-
_UPF_ERROR("TODO");
2575-
break;
2576-
case _UPF_TOK_OPEN_BRACKET:
2577-
_upf_consume_token();
2578-
while (!_upf_match_token(_UPF_TOK_CLOSE_BRACKET)) _upf_consume_token();
2579-
pointer++;
2580-
break;
2581-
default:
2582-
parsed_declarator = true;
2583-
break;
2584-
}
2585-
}
2601+
_upf_type *function_type = NULL;
2602+
_upf_type **function_return_type = NULL;
2603+
int pointers = _upf_parse_abstract_declarator(&function_type, &function_return_type);
25862604

25872605
_upf_type *type_ptr;
25882606
if (identifier != NULL) {
@@ -2670,9 +2688,14 @@ static _upf_type *_upf_parse_typename(void) {
26702688
}
26712689

26722690
_UPF_ASSERT(type_ptr != NULL);
2673-
while (pointer > 0) {
2691+
while (pointers > 0) {
26742692
type_ptr = _upf_get_pointer_to_type(type_ptr);
2675-
pointer--;
2693+
pointers--;
2694+
}
2695+
2696+
if (function_type != NULL) {
2697+
*function_return_type = type_ptr;
2698+
type_ptr = function_type;
26762699
}
26772700

26782701
return type_ptr;

0 commit comments

Comments
 (0)