C++ Logo

std-discussion

Advanced search

Re: Is the intent of [class.cdtor] p2 to disallow aliasing, and is the wording strong enough to be useful?

From: Brian Bi <bbi5291_at_[hidden]>
Date: Sat, 5 Aug 2023 23:07:39 -0400
If you wrote some code like this:

pointer = nullptr;
void* tmp = other->pointer;
other->pointer = pointer;
pointer = tmp;

if `this == other`, then the second line gives `tmp` an unspecified value,
which means that an unspecified value will get written back to `pointer` at
the end. So that would make GCC's codegen conforming.

On the other hand, if you wrote it like this:

pointer = nullptr;
void* tmp = pointer;
pointer = other->pointer;
other->pointer = tmp;

then `tmp` would always be a null pointer, meaning that null should get
written back at the very end and [class.cdtor]/2 would not justify some
garbage result at the end.

I think I agree with you in that the committee obviously didn't intend to
make this kind of aliasing UB, because if they had intended to do that,
then they would have just done it. And I don't think we should be
introducing new UB here, at least not unless we have some way to analyze
the impact of that change.

But this order sensitivity seems undesirable and probably not the intent of
[class.cdtor]/2 (and of CWG2271, which extended the rule to non-const
objects; although, weirdly, I can't find *any* discussion minutes about
that issue).

I think the intent might have been to also include a rule that if you
*write* to a subobject of the object under construction through a glvalue
that isn't derived from `this`, then it's unspecified what value is written.


On Sat, Aug 5, 2023 at 7:27 AM Jan Schultke via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> Thank you for the explanation. I'm decreasingly convinced that this is
> meant to disallow aliasing as time goes on.
>
> Whatever the intent is, the wording isn't strong enough for `noalias`
> in GCC at this time, so I've filed a bug report:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110912 (it's worth a
> read. GCC devs actually cite this very paragraph as the reason why
> `noalias` is applied to constructor parameters.
>
> Personally, I would be in favor of removing the paragraph completely.
> It's either not utilized at all (LLVM), or utilized incorrectly (GCC),
> and just introduces more unspecified behavior for seemingly very
> little benefit. Alternatively, it should be strengthened so that
> `noalias` can be applied.
>
> On Sat, Aug 5, 2023 at 4:45 AM Matthew House via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
> >
> > On Fri, Aug 4, 2023 at 7:02 PM Jan Schultke via Std-Discussion
> > <std-discussion_at_[hidden]> wrote:
> > >
> > > The issue starts with the following code gen:
> https://godbolt.org/z/PYTohPTKr
> > >
> > > Here, adding `__restrict` improves the code gen, but it doesn't for
> > > GCC. GCC seems to assume that no aliasing can take place between
> > > `this` and other parameters passed into the function. LLVM does not
> > > add `noalias` without `__restrict`.
> > >
> > > [class.cdtor] p2 says:
> > > > During the construction of an object, if the value of the
> > > > object or any of its subobjects is accessed through a
> > > > glvalue that is not obtained, directly or indirectly,
> > > > from the constructor's this pointer, the value
> > > > of the object or subobject thus obtained is unspecified.
> > >
> > > I believe that this paragraph's intent is to disallow aliasing, e.g.
> > > between `this` and rvalue reference passed into the move constructor.
> > > However, the wording is very difficult to implement.
> > > - GCC simply assumes `noalias`, which also assumes that writing to the
> > > aforementioned glvlaue will make its value unspecified. The paragraph
> > > only talks about the obtained value though.
> > > - clang does not assume anything, and possibly misses optimizations as
> a result.
> > >
> > > Am I interpreting the intent correctly? If so, how can the wording be
> > > improved to fully disallow aliasing, as intended, so that we can just
> > > add `noalias` here, as is already done?
> >
> > I was complaining about this clause a while back; "the value... thus
> > obtained is unspecified" is a remarkably weak criterion compared to
> > the full UB of 'noalias' or '__restrict'. You can find the thread at
> > <https://lists.isocpp.org/std-discussion/2022/12/1952.php>.
> > Originally, the clause only applied to const objects under
> > construction, but it was later changed to apply to all objects. I
> > wasn't able to find any definite rationale of why the original clause
> > was added or why it was expanded; one can speculate that it was to
> > allow compilers to blanket-substitute 'global_const_object.field' with
> > its final computed value, but that doesn't work when the value can
> > also change in the destructor. Unless it's meant to help classes with
> > nontrivial constructors but trivial destructors?
> >
> > Regardless, I don't think applying '__restrict' to every implicit
> > 'this' parameter would even be desirable here. I have an example at
> > <https://github.com/cplusplus/CWG/issues/206> of how it would break
> > classes holding self-referential pointers: suppose that derived
> > classes B and C share a virtual base class A, and A's constructor
> > stores a pointer to one of its fields in another field. When A's
> > constructor is called from B's constructor, it stores a pointer
> > derived from A's 'this' pointer, which is derived from B's 'this'
> > pointer. But if C's constructor then tries to access the field (which
> > is an indirect subobject of C) via the pointer (derived from B's
> > 'this'), then it breaks the rules of the clause. If the constructor
> > also modifies the pointee directly, with an lvalue derived from C's
> > 'this', then it also breaks the rules of '__restrict'.
> >
> > Personally, I'd be in favor of removing the clause entirely, if the
> > compiler writers are misinterpreting it as implying '__restrict'. It
> > can't be strengthened into a full '__restrict' without resulting in
> > the self-referential issue, at least not without a guarantee that the
> > annotation only applies to the outermost constructor and not to
> > subobject constructors.
> > --
> > Std-Discussion mailing list
> > Std-Discussion_at_[hidden]
> > https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>


-- 
*Brian Bi*

Received on 2023-08-06 03:07:53