aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--expr.c49
-rw-r--r--test/generic.c6
-rw-r--r--test/generic.qbe1
4 files changed, 55 insertions, 2 deletions
diff --git a/README.md b/README.md
index 38549cd..693d13f 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,6 @@ specified in `config.h`.
- Preprocessor ([#6]).
- Generation of position independent code (i.e. shared libraries,
modules, PIEs).
-- `_Generic` selection ([#44]).
- Currently only `x86_64` is supported and tested, though QBE also
supports `aarch64`, so it is possible that it works as well.
diff --git a/expr.c b/expr.c
index 0526b93..46d0fcd 100644
--- a/expr.c
+++ b/expr.c
@@ -322,6 +322,52 @@ unescape(char **p)
return c;
}
+static struct expr *
+generic(struct scope *s)
+{
+ struct expr *e, *match = NULL, *def = NULL;
+ struct type *t, *want;
+ enum typequal qual;
+
+ next();
+ expect(TLPAREN, "after '_Generic'");
+ e = assignexpr(s);
+ expect(TCOMMA, "after generic selector expression");
+ want = e->type;
+ delexpr(e);
+ do {
+ if (consume(TDEFAULT)) {
+ if (def)
+ error(&tok.loc, "multiple default expressions in generic association list");
+ expect(TCOLON, "after 'default'");
+ def = assignexpr(s);
+ } else {
+ qual = QUALNONE;
+ t = typename(s, &qual);
+ if (!t)
+ error(&tok.loc, "expected typename for generic association");
+ expect(TCOLON, "after type name");
+ e = assignexpr(s);
+ if (typecompatible(t, want) && qual == QUALNONE) {
+ if (match)
+ error(&tok.loc, "generic selector matches multiple associations");
+ match = e;
+ } else {
+ delexpr(e);
+ }
+ }
+ } while (consume(TCOMMA));
+ expect(TRPAREN, "after generic assocation list");
+ if (!match) {
+ if (!def)
+ error(&tok.loc, "generic selector matches no associations and no default was specified");
+ match = def;
+ } else if (def) {
+ delexpr(def);
+ }
+ return match;
+}
+
/* 6.5 Expressions */
static struct expr *
primaryexpr(struct scope *s)
@@ -407,7 +453,8 @@ primaryexpr(struct scope *s)
expect(TRPAREN, "after expression");
break;
case T_GENERIC:
- error(&tok.loc, "generic selection is not yet supported");
+ e = generic(s);
+ break;
default:
error(&tok.loc, "expected primary expression");
}
diff --git a/test/generic.c b/test/generic.c
new file mode 100644
index 0000000..d04bc90
--- /dev/null
+++ b/test/generic.c
@@ -0,0 +1,6 @@
+int x = _Generic(123,
+ const int: 1,
+ unsigned: 2,
+ int: 3,
+ int *: 4
+);
diff --git a/test/generic.qbe b/test/generic.qbe
new file mode 100644
index 0000000..6b57b3e
--- /dev/null
+++ b/test/generic.qbe
@@ -0,0 +1 @@
+export data $x = align 4 { w 3, }