cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[expr.const] Reading an `unsigned char` of an erroneous value in constant evaluation #558

Open frederick-vs-ja opened 2 weeks ago

frederick-vs-ja commented 2 weeks ago

Full name of submitter (unless configured in github; will be published with the issue): Jiang An

Reference (section label): [expr.const]

Link to reflector thread (if any):

Issue description:

Split from https://github.com/cplusplus/CWG/issues/550#issuecomment-2167114295. It seems that the following example should still be rejected after P2795R5.

Originally posted wrong example

```C++ static_assert([]{ unsigned char c; // the value is indeterminate until C++26, erroneous since C++26 +c; return true; }()); ```

Corrected example:

static_assert([]{
  unsigned char c; // the value is indeterminate until C++26, erroneous since C++26
  static_cast<unsigned char>(c);
  return true;
}());

However, [expr.const] p5.8 and [expr.const] p5.11 are insufficient to reject this, because reading an erroneous unsigned char value is not erroneous behavior, and [expr.const] p5.11 only talks about indeterminate values.

Or alternatively, if it's fine to propagate erroneous byte values until EB happens in constant evaluation, it would be more consistent to allow propagation of indeterminate byte values (until UB happens), given [expr.const] p14.2 has already forbidden an indeterminate or erroneous value in the final result of constant evaluation. This approach seems undesired per P1331R2, but I wonder whether it can simplify implementation of constant evaluator.

Suggested resolution:

Change [expr.const] p5.11 as indicated:

an lvalue-to-rvalue conversion that is applied to an object with an indeterminate or erroneous value;

jensmaurer commented 2 weeks ago

[expr.unary.op] p7 says "Integral promotion is performed on integral or enumeration operands."

So, we're promoting (erroneous) char to (erroneous) int. That latter part triggers erroneous behavior per [basic.indet] p2. And that, in turn, triggers [expr.const] p5.8. Your example is not a constant expression.

I'm not seeing a defect.

frederick-vs-ja commented 2 weeks ago

Oops, the original example was wrong.

A corrected example might be:

static_assert([]{
  unsigned char c; // the value is indeterminate until C++26, erroneous since C++26
  static_cast<unsigned char>(c);
  return true;
}());