mirror of https://github.com/rui314/chibicc
[GNU] Add __builtin_types_compatible_p
This commit is contained in:
parent
7d80a5136d
commit
1433b404d6
|
@ -284,6 +284,7 @@ struct Type {
|
|||
int size; // sizeof() value
|
||||
int align; // alignment
|
||||
bool is_unsigned; // unsigned or signed
|
||||
Type *origin; // for type compatibility check
|
||||
|
||||
// Pointer-to or array-of type. We intentionally use the same member
|
||||
// to represent pointer/array duality in C.
|
||||
|
@ -348,6 +349,7 @@ extern Type *ty_double;
|
|||
bool is_integer(Type *ty);
|
||||
bool is_flonum(Type *ty);
|
||||
bool is_numeric(Type *ty);
|
||||
bool is_compatible(Type *t1, Type *t2);
|
||||
Type *copy_type(Type *ty);
|
||||
Type *pointer_to(Type *base);
|
||||
Type *func_type(Type *return_ty);
|
||||
|
|
10
parse.c
10
parse.c
|
@ -2611,6 +2611,7 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
|
|||
// | "sizeof" unary
|
||||
// | "_Alignof" "(" type-name ")"
|
||||
// | "_Alignof" unary
|
||||
// | "__builtin_types_compatible_p" "(" type-name, type-name, ")"
|
||||
// | "__builtin_reg_class" "(" type-name ")"
|
||||
// | ident
|
||||
// | str
|
||||
|
@ -2656,6 +2657,15 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_ulong(node->ty->align, tok);
|
||||
}
|
||||
|
||||
if (equal(tok, "__builtin_types_compatible_p")) {
|
||||
tok = skip(tok->next, "(");
|
||||
Type *t1 = typename(&tok, tok);
|
||||
tok = skip(tok, ",");
|
||||
Type *t2 = typename(&tok, tok);
|
||||
*rest = skip(tok, ")");
|
||||
return new_num(is_compatible(t1, t2), start);
|
||||
}
|
||||
|
||||
if (equal(tok, "__builtin_reg_class")) {
|
||||
tok = skip(tok->next, "(");
|
||||
Type *ty = typename(&tok, tok);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#include "test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(1, __builtin_types_compatible_p(int, int));
|
||||
ASSERT(1, __builtin_types_compatible_p(double, double));
|
||||
ASSERT(0, __builtin_types_compatible_p(int, long));
|
||||
ASSERT(0, __builtin_types_compatible_p(long, float));
|
||||
ASSERT(1, __builtin_types_compatible_p(int *, int *));
|
||||
ASSERT(0, __builtin_types_compatible_p(short *, int *));
|
||||
ASSERT(0, __builtin_types_compatible_p(int **, int *));
|
||||
ASSERT(1, __builtin_types_compatible_p(const int, int));
|
||||
ASSERT(0, __builtin_types_compatible_p(unsigned, int));
|
||||
ASSERT(1, __builtin_types_compatible_p(signed, int));
|
||||
ASSERT(0, __builtin_types_compatible_p(struct {int a;}, struct {int a;}));
|
||||
|
||||
ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void)));
|
||||
ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int)));
|
||||
ASSERT(1, __builtin_types_compatible_p(void (*)(int, double), void (*)(int, double)));
|
||||
ASSERT(1, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double)));
|
||||
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int));
|
||||
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float)));
|
||||
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double, int)));
|
||||
ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...)));
|
||||
ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void)));
|
||||
|
||||
ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, T); }));
|
||||
ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, const T); }));
|
||||
|
||||
ASSERT(1, ({ struct {int a; int b;} x; __builtin_types_compatible_p(typeof(x.a), typeof(x.b)); }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
47
type.c
47
type.c
|
@ -38,9 +38,56 @@ bool is_numeric(Type *ty) {
|
|||
return is_integer(ty) || is_flonum(ty);
|
||||
}
|
||||
|
||||
bool is_compatible(Type *t1, Type *t2) {
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
|
||||
if (t1->origin)
|
||||
return is_compatible(t1->origin, t2);
|
||||
|
||||
if (t2->origin)
|
||||
return is_compatible(t1, t2->origin);
|
||||
|
||||
if (t1->kind != t2->kind)
|
||||
return false;
|
||||
|
||||
switch (t1->kind) {
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
case TY_INT:
|
||||
case TY_LONG:
|
||||
return t1->is_unsigned == t2->is_unsigned;
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
return true;
|
||||
case TY_PTR:
|
||||
return is_compatible(t1->base, t2->base);
|
||||
case TY_FUNC: {
|
||||
if (!is_compatible(t1->return_ty, t2->return_ty))
|
||||
return false;
|
||||
if (t1->is_variadic != t2->is_variadic)
|
||||
return false;
|
||||
|
||||
Type *p1 = t1->params;
|
||||
Type *p2 = t2->params;
|
||||
for (; p1 && p2; p1 = p1->next, p2 = p2->next)
|
||||
if (!is_compatible(p1, p2))
|
||||
return false;
|
||||
return p1 == NULL && p2 == NULL;
|
||||
}
|
||||
case TY_ARRAY:
|
||||
if (!is_compatible(t1->base, t2->base))
|
||||
return false;
|
||||
return t1->array_len < 0 && t2->array_len < 0 &&
|
||||
t1->array_len == t2->array_len;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *copy_type(Type *ty) {
|
||||
Type *ret = calloc(1, sizeof(Type));
|
||||
*ret = *ty;
|
||||
ret->origin = ty;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue