aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cc.h4
-rw-r--r--expr.c15
-rw-r--r--test/nullptr.c4
-rw-r--r--test/nullptr.qbe3
-rw-r--r--type.c2
5 files changed, 25 insertions, 3 deletions
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 *