Why "I = ++I" instead of "++I" in COFFDump.cpp ?

tools/llvm-objdump/COFFDump.cpp has two loops that advance the loop iterator using "I = ++I" instead of the usual "++I". For example:

  import_directory_iterator I = Obj->import_directory_begin();
  import_directory_iterator E = Obj->import_directory_end();
  if (I == E)
    return;
  outs() << "The Import Tables:\n";
  for (; I != E; I = ++I) {
      ...
  }

Is there a reason for writing "I = ++I" instead of "++I" ?

- Arch D. Robison

Not that I know of - and if there is... we've got issues. So change it
& find out? :slight_smile:

Looks like a bug. This can probably be simplified with C++11.

Oops, meant to send this to the mailing list instead of to Reid
privately. (Why cc the mailing list instead of just sending to the
mailing list?)

In article <CACs=tyJ6zaHeiS0eNhBkdcZE--JY4k7yH9_P1yFbGqod6uymMw@mail.gmail.com>,
    Reid Kleckner <rnk@google.com> writes:

Looks like a bug. This can probably be simplified with C++11.

> for (; I != E; I = ++I) {
> ...
> }
>
> Is there a reason for writing "I = ++I" instead of "++I" ?

I don't see how it's a bug because functionality isn't impacted by
this. It's simply a redundant assignment.

I also don't see what C++11 has to do with this.

    i = i;

has always been legal since the very first implementation of C and has
always been a pointless expression.

Had the code been:

    i = i++;

then we would have had a real problem since i++ returns the old value
of i before it was incremented and the loop would be infinite.

It is a bug as it violates the sequence point rule. One memory location
shall not be modified twice.

Joerg

In article <20140407190957.GA11923@britannica.bec.de>,
    Joerg Sonnenberger <joerg@britannica.bec.de> writes:

> In article <CACs=tyJ6zaHeiS0eNhBkdcZE--JY4k7yH9_P1yFbGqod6uymMw@mail.gmail.com>,
> Reid Kleckner <rnk@google.com> writes:
>
> > Looks like a bug. This can probably be simplified with C++11.
> >
> > > Is there a reason for writing "I = ++I" instead of "++I" ?
>
> I don't see how it's a bug because functionality isn't impacted by
> this. It's simply a redundant assignment.

It is a bug as it violates the sequence point rule. One memory location
shall not be modified twice.

Hrm. Then it's really two bugs?

1) the code violates the sequence point rule.
2) gcc/clang/MSVC didn't complain when compiling this code

If you could point me to the appropriate section of the Nov. 2012 Draft
Standard where I could read about the sequence point rule, I would be very
appreciative as I would like to understand this better.

Thanks!

OK, of course I found it after I asked for the section reference :slight_smile:

In article <E1WXHz7-0004mT-NQ@shell.xmission.com>,
    Richard <legalize@xmission.com> writes:

If you could point me to the appropriate section of the Nov. 2012 Draft
Standard where I could read about the sequence point rule, I would be very
appreciative as I would like to understand this better.

Is it here?

1.9.15

    "Except where noted, evaluations of operands of individual
    operators and of subexpressions of individual expressions are
    unsequenced. [...] The value computations of the operands of
    an operator are sequenced before the value computation of the
    result of the operator. If a side effect on a scalar object is
    unsequenced relative to either another side effect on the same
    scalar object or a value computation using the value of the same
    scalar object, the behavior is undefined.

    Example:

    void f(int, int);
    void g(int i, int* v) {
      i = v[i++]; // the behavior is undefined
      i = 7, i++, i++; // i becomes 9

      i = i++ + 1; // the behavior is undefined
      i = i + 1; // the value of i is incremented

      f(i = -1, i = -1); // the behavior is undefined
    }"

The middle group of statements seems to be the one that applies here,
although they use i++ and not ++i, the point seems to be the same.

Not in C++11, and (probably) not in C11. The side-effect of pre-increment
is sequenced before its value computation, and its value computation is
sequenced before the assignment. (C++ doesn't have sequence points any
more, and C only has them as a vestigial remnant of the pre-memory-model
world.)

In article <CAOfiQq=gtrW-qHLLn-5bfmwZ6Qr4wv3mi=NP78AetEOpbTJVqA@mail.gmail.com>,
    Richard Smith <richard@metafoo.co.uk> writes:

> It is a bug as it violates the sequence point rule. One memory location
> shall not be modified twice.

Not in C++11, and (probably) not in C11. The side-effect of pre-increment
is sequenced before its value computation, and its value computation is
sequenced before the assignment. (C++ doesn't have sequence points any
more, and C only has them as a vestigial remnant of the pre-memory-model
world.)

OK, still looking on how to find this in the standard.

Discussion of postfix ++ and --:

5.2 Postfix expressions
5.2.6 Increment and decrement

  "The value computation of the ++ expression is sequenced before
  the modification of the operand object."

Discussion of prefix ++ and --:

5.3 Unary expressions
5.3.2 Increment and decrement

  ...doesn't say anything about sequencing

It seems that with postfix operators the reason the code in 1.9.15
("i = i++ + 1", for example) was yielding undefined behavior was because
although the value computation of postfix++ is sequenced before the
modification of the operand object (5.2.6), the standard doesn't guarantee
anything about the relative sequencing of the postfix++ modification
and the assignment of the computed rvalue to the lvalue.

So a conforming implementation could do either:

    // initially i = 9
    i = i++ + 1;
    // 1. evalute i++ to get 9
    // 2. evalute 1 to get 1
    // 3. add 9 + 1 to get 10
    // 4. assign 10 to i
    // 5. increment i to 11

-or-

    // initially i = 9
    i = i++ + 1;
    // 1. evalute i++ to get 9
    // 2. increment i to 10
    // 3. evalute 1 to get 1
    // 4. add 9 + 1 to get 10
    // 5. assign 10 to i

Am I getting closer?

C99:

6.5 Expressions
1 An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.
2 Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.70)

70) This paragraph renders undefined statement expressions such as
   i = ++i + 1;
   a[i++] = i;
while allowing
   i = i + 1;
   a[i] = i;

C++ 2003:

5 Expressions
[...]
4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.53) Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example:
   i = v[i++]; // the behavior is unspecified
   i = 7, i++, i++; // i becomes 9
   i = ++i + 1; // the behavior is unspecified
   i = i + 1; // the value of i is incremented
—end example]

53) The precedence of operators is not directly specified, but it can be derived from the syntax.

C++ working draft:

1.9 Program execution
[...]
13 Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread (1.10), which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. —end note ] Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [ Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. —end note ]
14 Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.8)
15 Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. —end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is
undefined. [ Note: The next section imposes similar, but more complex restrictions on potentially concurrent computations. —end note ]
[ Example:
   void f(int, int);
   void g(int i, int* v) {
     i = v[i++]; // the behavior is undefined
     i = 7, i++, i++; // i becomes 9
     i = i++ + 1; // the behavior is undefined
     i = i + 1; // the value of i is incremented
     f(i = -1, i = -1); // the behavior is undefined
   }
—end example ]
When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9) Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. [ Example: Evaluation of
a new expression invokes one or more allocation and constructor functions; see 5.3.4. For another example, invocation of a conversion function (12.3.2) can arise in contexts in which no function call syntax appears. —end example ] The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.

8) As specified in 12.2, after a full-expression is evaluated, a sequence of zero or more invocations of destructor functions for
temporary objects takes place, usually in reverse order of the construction of each temporary object.
9) In other words, function executions do not interleave with each other.

HTH,
-Krzysztof

It seems to be simply the unwanted side effect of a scripted patch in 200442:

- for (; I != E; I = I.increment(EC)) {
+ for (; I != E; I = ++I) {