This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: generalized lvalues -- patch outline
Ziemowit Laski writes:
> Indeed, I now appear to have a mainline mod for C and C++ which allows
> assignment to lvalue casts for pointer types. What follows is a
> high-level synopsis of what I did; if there is interest, I can whip up
> a full-fledged patch, complete with docs. Please let me know.
It occurs to me -- can't "lvalue casts" be done in standard GNU C and C++?
Source code changes would be required, but they can probably be done largely
mechanically.
Here are the examples I've got -- they can maybe be cleaned up a bit, but
both of these compile your test cases -Wall-cleanly with GCC 3.4. (They
take advantage of the GCC extension that type-punning through a union is
defined behavior.)
First, the C++ example, since it's cleaner code:
/* lvalue_cast<> code by Jonathan Lennox <lennox at cs dot columbia dot edu>,
* placed in the public domain. */
template<class Targ, class Src>
Targ& lvalue_cast(Src& s)
{
union { Src * s; Targ * t; } u;
u.s = &s;
return *u.t; /* GNU Extension */
}
/* Test case by Ziemowit Laski <zlaski at apple dot com> */
#include <stdlib.h>
#define CHECK_IF(expr) if (!(expr)) abort ()
static int global;
void f(int &) { global = 35; }
void f(const int &) { global = 78; }
long long_arr[2];
int main(void) {
char *p;
lvalue_cast<long *>(p) = long_arr;
lvalue_cast<long *>(p)++;
*(long *)p = -1;
*p = -2;
CHECK_IF(p[-1] == 0 && p[0] == -2 && p[1] == -1);
long x = 0;
f((int)x);
CHECK_IF(global == 78);
return 0;
}
And then the C example:
/* LVALUE_CAST code by Jonathan Lennox <lennox at cs dot columbia dot edu>,
* placed in the public domain. */
#define LVALUE_CAST(TYPE, OBJ) (*({ \
union { __typeof__(OBJ) * s; TYPE * t; } u; \
\
u.s = &OBJ; \
u.t; /* GNU Extension */\
}))
/* Test case by Ziemowit Laski <zlaski at apple dot com> */
#include <stdlib.h>
#define CHECK_IF(expr) if (!(expr)) abort ()
int main(void) {
char *p;
long l;
short s;
LVALUE_CAST(long *, p) = &l; /* ok */
LVALUE_CAST(long *, p)++; /* ok */
LVALUE_CAST(short, l) = 2; /* Result depends on endianness. */
LVALUE_CAST(long, s) = 3; /* Stack clobber; run-time undefined behavior. */
return 0;
}
You'd have to do a global replace of lvalue casts with the new construct,
but I imagine that's a lot easier to explain to programmers than the strict
details of the new rules.
--
Jonathan Lennox
lennox at cs dot columbia dot edu