~mcf/cproc#87: 
[Patch] missing operand in conditional expression

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

Status
REPORTED
Submitter
tiago.t@sapo.pt
Assigned to
No-one
Submitted
1 year, 24 days ago
Updated
a year ago
Labels
No labels applied.

~mcf 1 year, 1 day ago

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.

~mcf a year ago

My suggestion would be to just create an EXPRCOND with u.conf.t == NULL, and then handle that possibility in funcexpr.

Register here or Log in to comment, or comment via email.