Hello,
I've been playing around a bit with cproc and decided to try to implement the "missing operand in conditional expression" extension:
In condexpr
, if it finds a TCOLON
it uses the first operand as the middle
operand, otherwise will parse an expression,
As this would cause a double free, on delexpr
I check if they are the same
reference and only delete if they differ.
This may not be the best approach, I didn't test this too much ...
Here's the patch/git diff
diff --git a/doc/extensions.md b/doc/extensions.md
index 9d07972..b74b4f5 100644
--- a/doc/extensions.md
+++ b/doc/extensions.md
@@ -82,11 +82,5 @@ struct {
This behaves exactly the same as `{0}`.
-### Missing operand in conditional expression
-
-GNU C allows you to omit the second operand in conditional expressions,
-in which case the first operand is used. So `E1 ? : E2` behaves the same
-as `E1 ? E1 : E2`, except that `E1` is evaluated only once.
-
[GNU extensions]: https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
[`__builtin_offsetof`]: https://gcc.gnu.org/onlinedocs/gcc/Offsetof.html
diff --git a/expr.c b/expr.c
index 04c7325..5c6092d 100644
--- a/expr.c
+++ b/expr.c
@@ -51,7 +51,8 @@ delexpr(struct expr *e)
break;
case EXPRCOND:
delexpr(e->base);
- delexpr(e->u.cond.t);
+ if(e->base != e->u.cond.t)
+ delexpr(e->u.cond.t);
delexpr(e->u.cond.f);
break;
/*
@@ -1186,7 +1187,10 @@ condexpr(struct scope *s)
e = binaryexpr(s, NULL, 0);
if (!consume(TQUESTION))
return e;
- l = expr(s);
+ if(tok.kind == TCOLON)
+ l = e;
+ else
+ l = expr(s);
expect(TCOLON, "in conditional expression");
r = condexpr(s);
Regards, Tiago
I don't think this will work as-is, since funcexpr() in qbe.c will double-evaluate the argument.
Here's an example:
int f(void); int g(void) { return f() ?: 0; }Here's the generated code:
export function w $g() { @start.1 @body.2 %.1 =w call $f() jnz %.1, @cond_true.3, @cond_false.4 @cond_true.3 %.2 =w call $f() jmp @cond_join.5 @cond_false.4 @cond_join.5 %.3 =w phi @cond_true.3 %.2, @cond_false.4 0 ret %.3 }
Anyway, I'm not sure if I want this extension implemented in cproc or not. So far my criteria for extensions has been something like "widely used and difficult or intrusive to patch to be portable C", but this is one that is trivial to write as portable C (though it is used fairly often in the wild). I encourage you to send patches to projects that use this instead.
My suggestion would be to just create an
EXPRCOND
withu.conf.t == NULL
, and then handle that possibility infuncexpr
.