https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110912
Bug ID: 110912 Summary: False assumption that constructors cannot alias any of their parameters Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: janschultke at googlemail dot com Target Milestone: --- It looks like GCC thinks that no aliasing can take place betweeen `this` and any constructor parameters. You get the same output if you use `__restrict` for any pointers passed into constructors, or if you add `noalias` to LLVM IR. There is no wording in the standard that disallows aliasing in constructors completely, and this may cause more serious issues in real code See https://github.com/cplusplus/CWG/issues/206. This bug stems from an over-interpretation of [class.cdtor] p2 (https://eel.is/c++draft/class.cdtor#2), which states that an unspecified value is obtained when not accessing subobjects through the `this` pointer. However, it DOES NOT say that side effects will result in unspecified values, and it DOES NOT say that any undefined behavior is involved, which is the prerequisite to treat this as `noalias`. It seems to have been introduced here, and there is a related LLVM issue: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82899 - https://bugs.llvm.org/show_bug.cgi?id=37329 For reference, [class.cdtor] p2: > 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. THIS WORDING IS NOT STRONG ENOUGH FOR `noalias`! This is an old paragraph which originally applied to const objects only, and has some problems with breaking legitimate code for polymorphic classes. I am not entirely sure about the intention behind it myself, but it would have been very easy for the committee to make access through such a pointer (not obtained from `this`) undefined behavior. That would actually allow `noalias`, NOT the current wording. I have talked to other knowledgeable members of the community, and so far no one believes that the wording is strong enough, or intended to disallow aliasing entirely. Related discussions: - https://lists.isocpp.org/std-discussion/2023/08/2324.php - https://lists.isocpp.org/std-discussion/2022/12/1952.php ## Code to Reproduce (https://godbolt.org/z/K4nTPYK3r) void foo(); struct A { int i = 0; [[gnu::used]] A(int &x) { x = 5; if (i == 0) { foo(); } } }; ## Actual Output (gcc trunk -O3) A::A(int&) [base object constructor]: mov DWORD PTR [rdi], 0 mov DWORD PTR [rsi], 5 jmp foo() ## Expected Output (clang trunk -O3) A::A(int&) [base object constructor]: mov dword ptr [rdi], 0 mov dword ptr [rsi], 5 cmp dword ptr [rdi], 0 je foo()@PLT ret ## Suggested Resolution Do not assume `noalias` for all parameters in a constructor.