On 7/31/19 3:26 PM, Marek Polacek wrote:
One of the features of constexpr is that it doesn't allow UB; and such UB must
be detected at compile-time. So running your code in a context that requires
a constant expression should ensure that the code in question is free of UB.
In effect, constexpr can serve as a sanitizer. E.g. this article describes in
in more detail:
<https://shafik.github.io/c++/undefined%20behavior/2019/05/11/explporing_undefined_behavior_using_constexpr.html>
[dcl.type.cv]p4 says "Any attempt to modify a const object during its lifetime
results in undefined behavior." However, as the article above points out, we
aren't detecting that case in constexpr evaluation.
This patch fixes that. It's not that easy, though, because we have to keep in
mind [class.ctor]p5:
"A constructor can be invoked for a const, volatile or const volatile object.
const and volatile semantics are not applied on an object under construction.
They come into effect when the constructor for the most derived object ends."
I handled this by keeping a hash set which tracks objects under construction.
I considered other options, such as going up call_stack, but that wouldn't
work with trivial constructor/op=. It was also interesting to find out that
the definition of TREE_HAS_CONSTRUCTOR says "When appearing in a FIELD_DECL,
it means that this field has been duly initialized in its constructor" though
nowhere in the codebase do we set TREE_HAS_CONSTRUCTOR on a FIELD_DECL as far
as I can see. Unfortunately, using this bit proved useless for my needs here.
Also, be mindful of mutable subobjects.
Does this approach look like an appropriate strategy for tracking objects'
construction?
For scalar objects, we should be able to rely on INIT_EXPR vs.
MODIFY_EXPR to distinguish between initialization and modification; for
class objects, I wonder about setting a flag on the CONSTRUCTOR after
initialization is complete to indicate that the value is now constant.
Jason