From 92c59818b538ae7ca4973b5e0bafa8b7efadcb78 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Fri, 22 Mar 2024 01:50:07 -0700 Subject: Implement C23 nullptr constant --- cc.h | 4 +++- expr.c | 15 +++++++++++++-- test/nullptr.c | 4 ++++ test/nullptr.qbe | 3 +++ type.c | 2 ++ 5 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test/nullptr.c create mode 100644 test/nullptr.qbe diff --git a/cc.h b/cc.h index 51b7cdc..bd05deb 100644 --- a/cc.h +++ b/cc.h @@ -166,7 +166,8 @@ enum typekind { TYPEARRAY, TYPEFUNC, TYPESTRUCT, - TYPEUNION + TYPEUNION, + TYPENULLPTR, }; enum typeprop { @@ -446,6 +447,7 @@ extern struct type typeint, typeuint; extern struct type typelong, typeulong; extern struct type typellong, typeullong; extern struct type typefloat, typedouble, typeldouble; +extern struct type typenullptr; extern struct type *typeadjvalist; /* targ */ diff --git a/expr.c b/expr.c index 1e94f68..20b943e 100644 --- a/expr.c +++ b/expr.c @@ -175,6 +175,8 @@ nullpointer(struct expr *e) { if (e->kind != EXPRCONST) return false; + if (e->type->kind == TYPENULLPTR) + return true; if (!(e->type->prop & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid)) return false; return e->u.constant.u == 0; @@ -188,8 +190,8 @@ exprassign(struct expr *e, struct type *t) et = e->type; switch (t->kind) { case TYPEBOOL: - if (!(et->prop & PROPARITH) && et->kind != TYPEPOINTER) - error(&tok.loc, "assignment to bool must be from arithmetic or pointer type"); + if (!(et->prop & PROPARITH) && et->kind != TYPEPOINTER && et->kind != TYPENULLPTR) + error(&tok.loc, "assignment to bool must be from arithmetic, pointer, or nullptr_t type"); break; case TYPEPOINTER: if (nullpointer(e)) @@ -201,6 +203,10 @@ exprassign(struct expr *e, struct type *t) if ((et->qual & t->qual) != et->qual) error(&tok.loc, "assignment to pointer discards qualifiers"); break; + case TYPENULLPTR: + if (!nullpointer(e)) + error(&tok.loc, "assignment to nullptr_t must be from null pointer constant or expression with type nullptr_t"); + break; case TYPESTRUCT: case TYPEUNION: if (!typecompatible(t, et)) @@ -699,6 +705,11 @@ primaryexpr(struct scope *s) e->u.constant.u = tok.kind == TTRUE; next(); break; + case TNULLPTR: + e = mkexpr(EXPRCONST, &typenullptr, NULL); + e->u.constant.u = 0; + next(); + break; case TLPAREN: next(); e = expr(s); diff --git a/test/nullptr.c b/test/nullptr.c new file mode 100644 index 0000000..8f5b436 --- /dev/null +++ b/test/nullptr.c @@ -0,0 +1,4 @@ +typeof(nullptr) x = 0; +_Static_assert(sizeof x == sizeof(char *)); +int *y = nullptr; +bool z = nullptr; diff --git a/test/nullptr.qbe b/test/nullptr.qbe new file mode 100644 index 0000000..c805942 --- /dev/null +++ b/test/nullptr.qbe @@ -0,0 +1,3 @@ +export data $x = align 8 { l 0, } +export data $y = align 8 { l 0, } +export data $z = align 1 { b 0, } diff --git a/type.c b/type.c index 02e9a82..5f6e417 100644 --- a/type.c +++ b/type.c @@ -39,6 +39,8 @@ struct type typefloat = FLTTYPE(TYPEFLOAT, 4); struct type typedouble = FLTTYPE(TYPEDOUBLE, 8); struct type typeldouble = FLTTYPE(TYPELDOUBLE, 16); +struct type typenullptr = {.kind = TYPENULLPTR, .size = 8, .align = 8, .prop = PROPSCALAR}; + struct type *typeadjvalist; struct type * -- cgit v1.2.3