Volatile MEMs in statement expressions and functions inlined astrees

Alexandre Oliva aoliva@redhat.com
Fri Dec 14 16:42:00 GMT 2001


On Dec 14, 2001, Linus Torvalds <torvalds@transmeta.com> wrote:

> Whee. I like the chain of logic, and it would be irrefutable (I think) if
> it wasn't for the fact that I suspect Gabriel may object to one of your
> steps, namely the basic

> 	"lvalue = rvalue".

> assumption.

> Gabriels claim hinges on the assignment of

> 	lvalue = lvalue

Actually, I think the basic `lvalue = rvalue' is exactly the right
thing to do according to the Standard, with lvalues decaying to
rvalues in the right-hand operand, again, as dictated by the C++
Standard.  The decaying does involve dereferencing, and that's where
the issue of whether the stored value of the expression is used or
not, and used as an lvalue or an rvalue, comes into play.  The more I
read [expr.ass]/1, the more I think the intent was that the result
should be considered as a de-referenced lvalue, i.e., an lvalue whose
value had already been loaded, such that it doesn't have to be
reloaded in case the lvalue decays to an rvalue.  But I don't see
anything in the Standard that supports this point any further.
Besides, there are the incoherences I've pointed out regarding binding
of temporary references.


Clearly, the standard doesn't say that:

lvalue = rvalue :: lvalue = (temp = rvalue, temp)

instead, it says:

lvalue = rvalue :: ,lvalue <- rvalue, ???

By ,lvalue I mean a dereferenced lvalue; by 'lvalue I mean the lvalue
as a reference.  <- stands for a store.  

??? may be one of:

'lvalue, meaning that, if you need to convert the lvalue to rvalue,
you have to load from it.  It would imply that the phrase `The result
of the assignment operation is the value stored in the left operand
after the assignment has taken place' was an oversight, for it failed
to consider the case of a volatile lvalue, whose value could be
different next time it was read.  An lvalue would be modeled as:

template <typename T> class lvalue {
 private:
  T *const addr;
 public:
  lvalue(T *addr_) : addr(addr_) {}
  lvalue& operator=(T newval) { *addr = newval; return *this; }

  // used to decay from lvalue to rvalue:
  operator T() const { return *addr; }
  // used for reference binding:
  operator T*() const { return addr; } 
};



{'lvalue,rvalue}, meaning a duple whose first element is the
addressable lvalue, and the second element is the value to be used
should the lvalue decay to rvalue.  In this sense, an lvalue could be
modeled as:

template <typename T> class lvalue {
 private:
  T *const addr;

 public:
  lvalue(T *addr_) : addr(addr_) {}

  virtual operator T() const { return *addr; }
  operator T*() const { return addr; }

  struct assigned_lvalue : lvalue {
    T const val;
    assigned_lvalue(T *addr, T val_) : lvalue(addr), val(val_) {}
    operator T() const { return val; }
  };

  lvalue& operator=(T newval) {
    // pretend this temporary survives until the end of the full
    // enclosing expression, which is where lvalues either are
    // bound to references (that have type lvalue, never
    // assigned_lvalue), decay to rvalues through operator T or
    // simply die
    return assigned_lvalue(addr, newval);
  }
};


An alternate modeling for similar behavior would be:

template <typename T> struct lvalue {
 private:
  T *const addr;
  mutable T val;
  mutable bool valid;

 public:
  lvalue(T *addr_) : addr(addr_), valid (false) {}

  lvalue& operator=(T newval) {
    valid = true;
    *addr = newval;
    val = newval; // or val = *addr; ? :-)
    return *this;
  }

  operator T() const {
    if (!valid) { val = *addr; valid = true; }
    return val;
  }

  // used to make sure it's dereferenced at least once?
  ~lvalue() { operator T(); }
};



While I like the first interpretation, I find it hard to believe it
was the intended meaning.  Consider, for example:

(x ? (a = b) : (c = d)) += e;

Which of the approaches above would you prefer to see used to
implement it?  Which one most closely matches the description of the
Standard, in your opinion?

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me



More information about the Gcc-patches mailing list