This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Volatile MEMs in statement expressions and functions inlined as trees



On Thu, 13 Dec 2001, Richard Henderson wrote:

> On Thu, Dec 13, 2001 at 11:41:37PM +0100, Gabriel Dos Reis wrote:
> > The result of the assignment operation is the value stored in
> > the left operand after the assignment has taken place; the result is
> > an lvalue.
>
> Taken at face value, this would seem to require that
>
> 	q = p = 0;
>
> be implemented as
>
> 	q = (tmp = 0, p = tmp, tmp);
>
> where "tmp" is the lvalue.


Well, that would be _a_ lvalue, but it's not the same lvalue as "p".

Which sounds technically legal (from the small context of the quote), but
sounds quote nonsensical in a bigger picture.

What is the "meaning" of a "temporary lvalue"? The whole point of an
lvalue is that you can take its address and assign to it, so a "temp
lvalue" sounds useless and positively dangerous.

Look at the expression

	volatile int p, *pp;

	pp = &(p = 0);

which in your example is truly non-sensical, because we just took the
value of a temporary that only existed in the compilers mind.

At the same time I obviously agree that from a _rvalue_ standpoint,
you're right.

>  Otherwise, how do you guarantee that "p" still contains the value
> stored?

My personal take on it is that you both implicity assume that "lvalue" and
"rvalue" are implicitly related by a dereference. And I don't think that's
true. It certainly doesn't _have_ to be true.

Think about this conceptually for a moment.

What is the _fundamental_ property of an assignment from a hardware
standpoint? You have two things: you have the address to be assigned, and
you have the value.

The _address_ is the "lvalue". Yes, I know, neither C nor C++ really
_speak_ of lvalues in those terms, because both languages try to create a
higher-level abstraction, but down-to-earth, thats' really what it is.

And the "value" is the "rvalue".

And the very act of assignment mixes the two and bring them together. Both
very fundamentally exist at the time of the assignment, yes?

So the question is, what happens _after_ the assignment.

I claim, that in C, the address is "lost". That's what you see in the fact
that an assignment expression in C is no longer an lvalue - the expression
only has the rvalue, and so the "value" of the C assignment expression is
fundamentally the value that we just stored.

And the fundamental difference in assignments - the little subtle single
sentence "the result is a lvalue" - in C++ is the fact that an assignment
_still_ retails both the address and the value.

The "rvalue" of an assignment expression is the value stored.

And the the "lvalue" of an assignment expression is basically the address
stored to (well, an "lvalue" is more than just the pointer - it's really
the access that goes _with_ the pointer).

And I think Gabriel will hate this distinction, because this is a
distinction that does not exist in other expressions. For non-assignment
expressions, there is always a direct "dereference" relationship between
the lvalue and the rvalue - you always _create_ the rvalue by
dereferencing the pointer inherent in the lvalue.

And I'm claiming that assignments are "different" - instead of
dereferencing the lvalue to get the rvalue, we know the rvalue a priori,
and we _set_ the lvalue to the rvalue.

I think this is entirely logical and consistent - assignments really
fundamentally are different in this respect. They don't real old data,
they write new data.

It's just that if you get too used to thinking "rvalue is the 'accessing'
of the lvalue", then you get used to thinking of the "rvalue" as always
being a "derived" entity.

While I'm claiming that the rvalue is _not_ a derived entity, but stands
independently of an lvalue.

If you think of lvalue/rvalue this way, then there is no inherent conflict
between "having the value stored" and "being an lvalue".

Basically, the expression

	p = 0;

really gets split up into tho "threads" - what is the lvalue of the
expression, and what is it's rvalue? The two are _different_.

	expression	lvalue		rvalue		side effect

	p		'p		*&p		-

	p = x		'p		x		store rvalue into p

	&p		-		*&p		-

	p+1		-		*&p+1		-

	p++		-		*&p		store rvalue+1 into p

(I'm using 'p aka "literal p" as the "lvalue" representation of p. It's
not really the same thing as just the "address of p", because it's more
of a "conceptual access to 'p'" - where the "conceptual access" becomes a
_real_ access either through the act of dereferencing it _or_ through the
act of assigning it)

Can anybody buy into this way of thinking?

Notice how in the above, "p = x" is a lvalue by virtue of being
"associated" with the address of 'p'. So the notion of doing

	pp = &(p = 1);

is completely well-defined: "pp" becomes the address of "p", and there is
no temporary lvalues involved anywhere.

But also notice how the _rvalue_ of the expression "p = x" has _nothing_
to do with its lvalue. The rvalue is, exactly like the standard says, "the
value stored into p".

Logical and consistent - but you have to allow rvalues as real citizens
independently of the lvalue in order to do this.

And I think this is where Gabriel and Jason disagree.

		Linus


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]