[Bug libstdc++/114817] Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817 --- Comment #3 from Arthur O'Dwyer --- https://github.com/boostorg/container/issues/153 , from 2020, is another similar issue. There, boost::container::vector had assumed that if __has_trivial_copy(T) and is_copy_constructible_v, then T could be relocated via memcpy; but in fact __has_trivial_copy(T) is also true for move-only types. So it was possible to create a type such that (__has_trivial_copy(T) && __is_constructible(T, T&)) and yet not __is_trivially_constructible(T, T&). // https://godbolt.org/z/x5Wda1M6E struct T { template T(U&&); T(T&&); ~T(); }; static_assert(__has_trivial_copy(T) && __is_constructible(T, T&)); // ...and yet... static_assert(not __is_trivially_constructible(T, T&));
[Bug libstdc++/114817] Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817 --- Comment #1 from Arthur O'Dwyer --- Yes, vector reallocation has analogous trouble with types that are "trivial, but not trivially copy constructible." https://godbolt.org/z/Psboqf3MP (libc++ happens to sidestep this pitfall *on Clang 15+,* because libc++ gates their vector reallocation optimization differently depending on whether `__has_builtin(__is_trivially_relocatable)`; but libc++ would have the same bug as libstdc++ when compiled on GCC.)
[Bug libstdc++/114817] New: Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817 Bug ID: 114817 Summary: Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- Jiang An raises an interesting issue over at https://github.com/llvm/llvm-project/pull/89652#discussion_r1575540420 namely: // https://godbolt.org/z/64KGP1avE template struct EvilPair { T& first; U& second; EvilPair(T& t, U& u) : first(t), second(u) {} EvilPair(const EvilPair&) = default; void operator=(const volatile EvilPair&) = delete; template EvilPair& operator=(const EvilPair& rhs) { first = rhs.first; second = rhs.second; return *this; } }; static_assert(std::is_trivially_copyable_v>); int main() { int a[] = {1,2,3}; int b[] = {4,5,6}; int c[] = {0,0,0}; int d[] = {0,0,0}; EvilPair ps[] = { {a[0], b[0]}, {a[1], b[1]}, {a[2], b[2]}, }; EvilPair qs[] = { {c[0], d[0]}, {c[1], d[1]}, {c[2], d[2]}, }; std::copy(ps, ps+3, qs); printf("%d %d %d\n", c[0], c[1], c[2]); } Here, EvilPair is trivially copyable, and also copy-assignable, but it is not trivially copy-assignable. libstdc++'s std::copy assumes that any trivially copyable type can be... well, trivially copied. So it copies the object representation of EvilPair, instead of doing overload resolution to discover that in fact the templated `operator=` should be called instead. Looks like the std::copy optimization was introduced in the GCC 9 release. Allegedly Microsoft STL's `std::pair` is isomorphic to `EvilPair` these days. libc++'s `std::copy` avoids this issue (AFAICT) by gating their optimization on *both* is_trivially_assignable and is_trivially_copyable. I suspect there will be similar issues with `uninitialized_foo` functions and/or vector reallocation, for types that are trivially copyable (or trivially relocatable!) and yet not trivially destructive-movable.
[Bug c++/114479] [14 Regression] std::is_array_v changed from false to true in GCC 14
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114479 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #5 from Arthur O'Dwyer --- IIUC, the logic here goes as follows: (1) Everyone's compiler extension currently makes this assertion fail, not succeed: #include template struct is_array : std::false_type {}; template struct is_array : std::true_type {}; template struct is_array : std::true_type {}; static_assert(is_array::value, "this assert fails"); (2) Everyone's library is expected to implement `std::is_array` as the moral equivalent of the partial specializations in (1). No reasonable library would ever do anything else. (3) Therefore, everyone's library will claim that int[0] is not an array type: static_assert(std::is_array::value, "this assert fails"); (4) The __is_array builtin is provided specifically to speed up std::is_array (and for no other reason). Therefore, it should give the same answer as (3). Therefore, __is_array(int[0]) should also report false: static_assert(__is_array(int[0]), "this assert fails"); This logic doesn't depend on any abstract reasoning about whether int[0] is really "an array type" (I think it certainly *is* an array type, FWIW); it simply depends on observing the extension's behavior in (1) -- and then *not* claiming that that's a bug we need to fix. If the extension's behavior is "correct" (i.e. we're not going to change it), then the behavior of __is_array(T[0]) falls naturally out of that. Personally, if I were designing the extension today, I would certainly make T[0] match the partial specialization for T[N] (with N=0). This seems like it would match users' expectations, and it doesn't seem to break any code that wasn't already trying to use the extension, except for pathological party tricks like being able to obfuscate the condition (N >= 1) as (std::is_array_v). However, *if* the extension's behavior (1) is set in stone, *then* conclusion (4) follows inexorably. And since both (1) and (4) are core-language compiler issues, libstdc++ isn't involved here: it's simply a bug for GCC to provide partial-specialization-matching behavior as in (1) without also providing __is_array behavior as in (4). HOWEVER, here's a big question which I believe Aaron Ballman also raised on llvm-project#54705: If it's not an array type, then where do we get off calling it a compound type ( https://eel.is/c++draft/basic#compound-1 ), a literal type ( https://eel.is/c++draft/basic#types.general-10 ), an aggregate ( https://eel.is/c++draft/dcl.init.aggr#1 ), etc? It certainly would be *simpler* -- if a big upheaval -- for GCC to provide neither (1) nor (4), i.e. change the specialization-matching behavior to match __is_array rather than the other way around. Then all the traits would give consistent answers: int[0] would be a compound type, a literal type, and an aggregate *because* it was an array type.
[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945 --- Comment #31 from Arthur O'Dwyer --- Oops, I guess my reading did disagree with jwakely's in one small point: jwakely writes-- > But since one of the pointers is an invalid pointer, > you can't do anything with its value anyway, including > comparing it to In my interpretation, it was fine to compare `global == `; but the boolean value of that comparison would be unspecified (because `*global` was out-of-lifetime), and even if it *did* happen to come out to `true`, it would still be UB to execute `global->i = 42` (because `*global` would still be a different object from `w`, and `*global` is out-of-lifetime). I think this makes no difference to the ultimate conclusion, i.e. something here ends up being UB either way.
[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945 --- Comment #30 from Arthur O'Dwyer --- I think I understand jwakely's argument at this point, and it's consistent and teachable. https://eel.is/c++draft/class.temporary#3.sentence-1 says: > When an object of class type X is passed to or returned from a function, if X > has at least one eligible copy or move constructor, each such constructor is > trivial, and the destructor of X is either trivial or deleted, > implementations are permitted to create a temporary object to hold the > function parameter or result object. It says "implementations are permitted"; this means that an implementation (GCC) can create such a temporary *whenever* permitted, and then re-optimize the codegen under the As-If Rule to eliminate the trivial move. That still ends the lifetime of the original object. `global` points to that original object, which is out-of-lifetime, so dereferencing `global` is UB. (Yes, even if its value happens to _compare_ equal to some other pointer that's still in-lifetime: this is "pointer provenance" as I see and understand it.) So, in order for me to call this `Widget` example a "bug," I'd have to find a `Widget` that doesn't meet [class.temporary]/3's conditions. That is, it would have to be a type that does NOT have eligible copy or move constructors; or has at least one NON-trivial eligible copy or move constructor; or has a NON-deleted NON-trivial destructor. Then the implementation (GCC) would NOT be permitted to create a temporary and the argument wouldn't hold anymore. And indeed, I cannot find such a `Widget`! Every example I've tried so far matches jwakely's explanation. For example: https://godbolt.org/z/rT6Mv537e struct X { X(); X(X&, int=0); X(const X&) = default; int i = 1; int a[4]; }; This `X` has a non-trivial eligible copy constructor, so it doesn't meet [class.temporary]/3's conditions, and GCC treats it the same at -O1 and -O2. If you delete the characters `=0`, then that constructor is no longer a copy constructor, so `X` DOES meet [class.temporary]/3 and GCC treats it differently at -O1 and -O2 (which is fine because now the program has UB, as jwakely says). GCC is not misbehaving in this example. Here's another example (still matching jwakely's argument perfectly: GCC is not misbehaving) -- this one exploits [special]/6 to play with whether the non-trivial copy ctor is "eligible" -- https://godbolt.org/z/PWT85n5xb I'm satisfied with the explanation -- and GCC seems to be implementing it correctly AFAICT -- so I think it would be reasonable to close this bug as INVALID. On the other hand, if anyone wants to argue that the current behavior is technically correct but super confusing to working programmers, I wouldn't argue against them, either. ;)
[Bug c++/113789] [13 Regression] ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789 --- Comment #10 from Arthur O'Dwyer --- FWIW, I think I agree with your analysis. To reiterate what you already said (and I think GCC already gets the following snippet correct): in X g (X x) try { throw x; } catch (...) { return x; } the `throw x` copies but the `return x` moves. That is, `throw x` treats `x` as an lvalue because it could be used again later (in the function-catch-block), but `return x` treats it as an rvalue because it can't[*] be used again later. [* — except if you sneakily use a captured reference within a destructor, but C++ implicit move doesn't care — has never cared — about such sneaky uses]
[Bug c++/113853] implicit move in throw in trailing return type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113853 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #1 from Arthur O'Dwyer --- (Sorry, not sure where's the best place to put this comment. Maybe nowhere. ;)) You probably know this already, but just in case anyone's not on the same page yet: https://eel.is/c++draft/except.throw#5 > When the thrown object is a class object, the constructor selected for the > copy-initialization *as well as the constructor selected for a > copy-initialization considering the thrown object as an lvalue* shall be > non-deleted and accessible, even if the copy/move operation is elided. That paragraph is lurking in the background every time we talk about GCC's handling of move-only exception objects. However, my impression is that the paragraph is ignorable from the vendor's point of view: - Even on paper, this "shall" is talking only about the runtime behavior "when an exception _is_ thrown," so it doesn't change anything about the well-formedness of _unevaluated_ throw-expressions. - GCC+Clang _probably could_ conformingly decide that it should be ill-formed to `throw x` when `x` is move-only; but that would break a lot of users, so pragmatically they can't do that. GCC+Clang need a consistent theory of what it means to throw a move-only type, and the theory can't possibly be "it's ill-formed" (because that would break users), so the theory must agree with Marek's test case: `throw t` ought to be well-formed in C++20-and-later (by wording introduced to C++20 in P1155 a.k.a. P1825). IOW, this bug and test case are *not* invalidated by [except.throw]/5. That's all. :)
[Bug c++/113789] [13/14 Regression] ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789 --- Comment #6 from Arthur O'Dwyer --- (In reply to Marek Polacek from comment #5) > IOW, this should be accepted in C++23 but isn't (clang++ accepts in C++23): > [...] Correct, at least that's my intended interpretation. But the unexpected ICE was more dramatic. :) I'd be a tiny bit surprised if fixing `decltype(throw p)` actually closes the only pathway to that ICE; but if it does, then awesome, I have no complaints.
[Bug c++/113789] New: ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789 Bug ID: 113789 Summary: ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- P2266 "Simpler Implicit Move", adopted for C++23, intends that a move-eligible `x` should be treated as an xvalue in the context of `throw x`. This means that `throw x` should be ill-formed (SFINAE-friendly) when `x` isn't move-constructible. (This might be complicated by the GCC+Clang extension that permits move-only types to be thrown even though the paper Standard technically prohibits that.) That is, the test program in this blog post is expected to pass after P2266: https://quuxplusone.github.io/blog/2021/03/18/sfinae-on-throw-x/#here-is-a-program-that-uses-sfin Clang passes; GCC fails; MSVC and EDG don't seem to implement P2266 `throw` yet. But the real problem for GCC is that if you then use `throw x` inside the function body after using `decltype(throw x)` in the function's return type, the compiler ICEs! // https://godbolt.org/z/YG16hE7zT struct AutoPtr { AutoPtr() = default; AutoPtr(AutoPtr&) {} }; template auto f(T p, int) -> decltype(throw p, 1) { throw p; } template int f(T p, long) { return 2; } int main() { return f(AutoPtr(), 42); } The expected behavior (and Clang's behavior) is to call `f(T, long)`. GCC 12 generates a call to `f(T, int)`. GCC 13 crashes with this output (including that leading single-quote): ' internal compiler error: error reporting routines re-entered. 0x2648345 diagnostic_context::report_diagnostic(diagnostic_info*) ???:0 0x26494c5 error_at(unsigned int, char const*, ...) ???:0 0xa7d834 build_new_method_call(tree_node*, tree_node*, vec**, tree_node*, int, tree_node**, int) ???:0 0xa7eb5b build_special_member_call(tree_node*, tree_node*, vec**, tree_node*, int, int) ???:0 0xb685e4 build_throw(unsigned int, tree_node*) ???:0 0xc95e47 tsubst(tree_node*, tree_node*, int, tree_node*) ???:0 0x267035c pp_format(pretty_printer*, text_info*, urlifier const*) ???:0 0x2673055 pp_verbatim(pretty_printer*, char const*, ...) ???:0 0x26481ca diagnostic_context::report_diagnostic(diagnostic_info*) ???:0 0x26494c5 error_at(unsigned int, char const*, ...) ???:0 0xa7d834 build_new_method_call(tree_node*, tree_node*, vec**, tree_node*, int, tree_node**, int) ???:0 0xa7eb5b build_special_member_call(tree_node*, tree_node*, vec**, tree_node*, int, int) ???:0 0xb685e4 build_throw(unsigned int, tree_node*) ???:0 0xc8b5c3 instantiate_decl(tree_node*, bool, bool) ???:0 0xcb56cb instantiate_pending_templates(int) ???:0 0xb54d39 c_parse_final_cleanups() ???:0 0xda8358 c_common_parse_file() ???:0
[Bug c++/113563] New: Rejects capture of `this` in C++23 `this auto` lambda
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113563 Bug ID: 113563 Summary: Rejects capture of `this` in C++23 `this auto` lambda Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/KWv8n6zEG struct S { int x_; void f() { [this](this auto) { return this; }; } }; GCC trunk complains: :5:16: error: invalid use of 'this' in non-member function 5 | return this; |^~~~ The error also happens with - [this](this auto&&) { return this; } - [this](this auto) { return x; } - [this](this auto) { f(); } - [&](this auto) { return this; } - [&](this auto) { return x; } - [&](this auto) { f(); } My understanding is that all of these lambdas should be well-formed, just as long as the lambda's call operator is eventually instantiated (if it's ever instantiated at all) with a type that satisfies [expr.prim.lambda.closure]/5, i.e. is either the closure type itself or a class type derived from the closure type. Btw, I do like that GCC eagerly and SFINAE-friendlily rejects `[&](this T) {}`. I hope fixing this bug doesn't require undoing that feature. (By "SFINAE-friendly" I mean https://godbolt.org/z/fK4f13343 ) See also https://quuxplusone.github.io/blog/2024/01/23/capturing-lambda-deducing-this/
[Bug c++/113541] New: Rejects __attribute__((section)) on explicit instantiation declaration of ctor/dtor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113541 Bug ID: 113541 Summary: Rejects __attribute__((section)) on explicit instantiation declaration of ctor/dtor Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/34Wdj1ox8 template struct S { S(int) {} void operator=(int) {} void f(int) {} ~S() {} }; template __attribute__((section("TEST"))) S::S(int); // error template __attribute__((section("TEST"))) void S::f(int); // OK template __attribute__((section("TEST"))) void S::operator=(int); // OK template __attribute__((section("TEST"))) S::~S(); // error === : In instantiation of 'S::S(int) [with T = int]': :9:56: required from here :3:5: error: section of alias 'S::S(int) [with T = int]' must match section of its target 3 | S(int) {} | ^ The problem seems to be only with the constructor and destructor, i.e., the two kinds of functions that codegen two object-code definitions (base object xtor and complete object xtor) for a single C++ declaration. Somehow, giving `S` a virtual base class (`struct S : virtual B`) fixes the problem. Then both codegenned xtors correctly wind up in the "TEST" section. GCC 4.9.4 is happy with the code as written. The bug started happening with GCC 5. (This was noted on Slack in June 2019, but never reported on Bugzilla AFAICT until now: https://cpplang.slack.com/archives/C5GN4SP41/p1560800562026000 )
[Bug c++/113427] New: ICE: tree check: C++23 `this auto` lambda + multiple (ambiguous) inheritance from closure type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113427 Bug ID: 113427 Summary: ICE: tree check: C++23 `this auto` lambda + multiple (ambiguous) inheritance from closure type Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/fd3zzfrTd auto factory(int x) { return [x=x](this auto self) { return x; }; } using Lambda = decltype(factory(0)); struct LeftCat : Lambda { LeftCat() : Lambda(factory(1)) {} }; struct RightCat : Lambda { RightCat() : Lambda(factory(2)) {} }; struct SiameseCat : LeftCat, RightCat { using Lambda::operator(); }; int main() { return SiameseCat()(); } === : In instantiation of 'factory(int):: [with auto:1 = SiameseCat]': :11:24: required from here 11 | return SiameseCat()(); |^~ :3:32: error: 'factory(int)::' is an ambiguous base of 'SiameseCat' 3 | return [x=x](this auto self) { return x; }; |^ :3:32: error: 'factory(int)::' is an ambiguous base of 'SiameseCat' :3:32: internal compiler error: tree check: expected class 'type', have 'exceptional' (error_mark) in tsubst_decl, at cp/pt.cc:15542 0x264113c internal_error(char const*, ...) ???:0 0x9641cf tree_class_check_failed(tree_node const*, tree_code_class, char const*, int, char const*) ???:0 0xa88c8c tree_class_check(tree_node*, tree_code_class, char const*, int, char const*) ???:0 0xc88d63 instantiate_decl(tree_node*, bool, bool) ???:0 0xb4de55 maybe_instantiate_decl(tree_node*) ???:0 0xb4f948 mark_used(tree_node*, int) ???:0 0xa81a04 build_op_call(tree_node*, vec**, int) ???:0 0xcce9e7 finish_call_expr(tree_node*, vec**, bool, bool, int) ???:0 0xc521ea c_parse_file() ???:0 0xda5b99 c_common_parse_file() ???:0 Please submit a full bug report, with preprocessed source (by using -freport-bug). Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. === Found by noodling around with explicit object parameters and corner cases related to https://eel.is/c++draft/expr.prim.lambda#closure-5 . That wording currently demands that the explicit object parameter of a capturing lambda be "a class type derived from the closure type," but it probably ought to say more like "a class type _unambiguously_ derived from the closure type." At least, I don't know what the expected behavior of the above program ought to be, if it's _not_ supposed to be ill-formed. I think GCC's ICE happens because GCC is trying too hard to assign a meaning to an essentially meaningless program.
[Bug c++/112555] New: NTTP of cv-qualified pointer type fails to mangle in those qualifiers
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112555 Bug ID: 112555 Summary: NTTP of cv-qualified pointer type fails to mangle in those qualifiers Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/EGv36xzY6 template struct A; template void foo(); int i; int main() { foo>(); foo>(); foo>(); foo>(); } Clang mangles each call to `foo` differently: callq _Z3fooI1AILPi0EEEvv@PLT callq _Z3fooI1AILPKi0EEEvv@PLT callq _Z3fooI1AIXadL_Z1ivv@PLT callq _Z3fooI1AIXcvPKiadL_Z1ivv@PLT GCC mangles the `int*` and `const int*` versions differently for nullptr, but identically for ``. I think this is a GCC bug. call _Z3fooI1AILPi0EEEvv call _Z3fooI1AILPKi0EEEvv call _Z3fooI1AIXadL_Z1ivv call _Z3fooI1AIXadL_Z1ivv NVC++ (EDG front-end) matches GCC, not Clang. MSVC matches Clang, in that the `int*` and `const int*` versions are mangled distinctly (but using MSVC ABI's mangling conventions of course). Bug #107222 might be related but seems to be the opposite problem, if anything?
[Bug c++/102470] C++20 NTTP causes ICE
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102470 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- Segfaults starting in GCC 9.1 (the first release with class NTTPs) until 12.3, succeeds fine in GCC 13.1 and later. Reduced: https://compiler-explorer.com/z/Kea5ar6MM struct MA { int x; }; template constexpr int mao = 1; template struct AST {}; template using AS = AST; template using ASF = AS>; : In substitution of 'template using AS = AST<((const MA)ma).x> [with MA ma = mao]': :5:39: required from here :4:32: internal compiler error: Segmentation fault 4 | template using AS = AST; |^~ 0x1bbabfe internal_error(char const*, ...) 0x109f844 strip_array_types(tree_node*) 0x8d3f2c cp_type_quals(tree_node const*) 0x88e40f tsubst_template_args(tree_node*, tree_node*, int, tree_node*) 0x87b764 tsubst(tree_node*, tree_node*, int, tree_node*) [...]
[Bug c++/99524] initializer_list storage considered a temporary when accessed through NTTP
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99524 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #1 from Arthur O'Dwyer --- I don't see this as a bug (and indeed Clang/MSVC reject it too). It's okay to use the address of `il` itself as the value of a template parameter, because we know a mangleable name for that; but the address of the first element of the backing array isn't a valid value for a template parameter, because the backing array is anonymous — it hasn't got a mangleable name — in the very-new-like-as-of-last-week Standardese, it's a "potentially non-unique object." The same rejection applies to this example employing a string literal (the other kind of "potentially non-unique object") in the Standard post-CWG2753): constexpr const char *il = "hello world"; template constexpr bool front = true; static_assert(front<>); // OK static_assert(front<[0]>); // Reject So I think this is not-a-bug.
[Bug c++/112471] New: catch handler of type "reference to array" should be unreachable, but is reached
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112471 Bug ID: 112471 Summary: catch handler of type "reference to array" should be unreachable, but is reached Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/W9P6GrG4x #include int main() { try { throw nullptr; } catch (const int(&)[2]) { puts("caught int(&)[2]"); } catch (const int*) { puts("caught int*"); } } The correct output is "caught int*", because nullptr is not an array. Clang and EDG produce the correct output. MSVC is so confident that you can't throw an array (I think they're right!) that it diagnoses the `catch` at -W4: // https://godbolt.org/z/v6M1e5ff5 warning C4843: 'const int (&)[2]': An exception handler of reference to array or function type is unreachable, use 'const int *' instead GCC also mishandles unreachable catch handlers of type "reference to function": again the correct output is "caught int*", Clang/EDG/MSVC all get it right, and MSVC diagnoses. // https://godbolt.org/z/sqoW6cPTn try { throw nullptr; } catch (int(&)()) { puts("caught int(&)()"); } catch (const int*) { puts("caught int*"); }
[Bug c++/112436] New: SFINAE-unfriendly error on throwing pointer to incomplete type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112436 Bug ID: 112436 Summary: SFINAE-unfriendly error on throwing pointer to incomplete type Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- template concept Throwable = requires { throw T(); }; struct Incomplete; static_assert(!Throwable); static_assert(!Throwable); :2:32: error: invalid use of incomplete type 'struct Incomplete' 2 | concept Throwable = requires { throw T(); }; |^ :3:8: note: forward declaration of 'struct Incomplete' 3 | struct Incomplete; |^~ :2:32: error: invalid use of array with unspecified bounds 2 | concept Throwable = requires { throw T(); }; |^ Instead of a hard error in both cases, we expect the concept to be false and the static_assert to succeed. Clang and EDG succeed. MSVC succeeds on `Incomplete*` and incorrectly permits throwing `int(*)[]`. The terse/multi-purpose "invalid use of..." error message seems to come up a lot in Bugzilla, but I didn't see any search hits for that message plus the word "throw". Bug #98388 is probably related.
[Bug c++/94039] conditional operator fails to use proper overload
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94039 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #3 from Arthur O'Dwyer --- You can also hit this with a lambda, which of course is isomorphic to Andre's test case: void (*a)() = true ? []{} : nullptr; Bug #88458 ("GCC rejects (true ? 0 : nullptr)") might be tangentially related.
[Bug libstdc++/111351] constexpr std::string objects permitted to escape constant evaluation when SSO
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111351 --- Comment #6 from Arthur O'Dwyer --- (In reply to James Y Knight from comment #5) > > Does using __builtin_is_constant_p on the union member not work? > > I've created a proof-of-concept patch for libc++ to support SSO strings > during constant evaluation. It works. > > If everyone disagrees with me and believes that this is a really awesome > foot-gun to give to users, I will go ahead and propose that patch to libc++ > maintainers. (As mentioned, that'll cause more code to be compilable under > libc++ than is possible to permit under libstdc++/MSVC implementations). FWIW #1: Personally I would be weakly in favor of that patch, but I would also be pessimistic about its chances of getting accepted in the current libc++ climate. FWIW #2: A worst-of-both-worlds option ;) would be for your patch to `if consteval` the SSO buffer size so that it would be 24 at runtime (matching libc++'s current behavior) but 16 at compile time (matching libstdc++ and Microsoft if I'm not mistaken, so you'd get your cross-vendor portability at compile time). *I* would still consider that an unnecessary-and-thus-bad crippling of libc++ string's cool 24-byte-SSO feature; but I could imagine someone else finding it more palatable than any other alternative. ["Worst-of-both-worlds" in the sense that you're paying to change the code at all, but the end result still has two codepaths that both need to be maintained, and divergence between compile-time and runtime SSO behavior.]
[Bug libstdc++/111351] constexpr std::string objects permitted to escape constant evaluation when SSO
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111351 --- Comment #1 from Arthur O'Dwyer --- (Author of the blog post here.) In contrast to James' view, I think the libstdc++/MSVC behavior is relatively easy to explain; I think libc++'s `if consteval` approach is baroque and confusing. [That is, _both_ behaviors are confusing to the newbie and need expert explanation, but libc++'s choice is confusing even for the experts, who have to maintain its split-brain SSO logic forever because Hyrum's Law. If you have to maintain something forever, you should at least choose to make it _simple_! As I say in the blog post, in hindsight I think libc++ screwed up here.] IMHO it is a feature, not a bug, that I can write these lines: constinit std::string s1; constinit std::vector v1; libstdc++ would be within its rights, paper-Standard-wise, to reject both of these lines; but I don't think libstdc++ _should_ reject either of them. They're both fine code as far as I'm concerned. I think libc++ is the user-hostile/broken implementation here, not libstdc++. Anyone who thinks libstdc++ ought to reject `s1` above should at least be forced to explain what libstdc++ ought to do about `v1`. From the user-programmer's POV, there's no difference between a default-initialized string and a default-initialized vector. Users don't care about these SSO details; they just want the code to work. That's what libstdc++ currently does. Good, IMO.
[Bug c++/86646] Special member function 'cannot be defaulted' if type alias is used
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86646 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #4 from Arthur O'Dwyer --- I just ran into this (it's one of the examples of vendor divergence in P2953R0). https://isocpp.org/files/papers/P2953R0.html#corner-cases // https://godbolt.org/z/sxv5rvn8o template struct C { C& operator=(std::add_lvalue_reference_t) = default; }; C cl; GCC 13 says: error: 'C< >& C< >::operator=(std::add_lvalue_reference_t > >)' cannot be defaulted 5 | C& operator=(std::add_lvalue_reference_t) = default; |^~~ I confirm Andrew's observation that Clang is the odd one out in accepting this code (GCC, MSVC, EDG all reject). But it also seems pretty obvious that it should be accepted. Brian Bi concurs: "I couldn't figure out any reason why this shouldn't be valid." Or again something like this: template struct C { C(std::conditional_t) = default; C(std::conditional_t); }; static_assert(std::is_trivially_copy_constructible_v>); static_assert(std::is_trivially_move_constructible_v>); GCC+EDG+MSVC reject; Clang accepts; and I think Clang is the conforming one. A related situation is // https://godbolt.org/z/1bhEx1Gr1 template struct C { template using A = const C&; C(A...) = default; // this is a default ctor or a copy ctor, depending on sizeof...(Ts) }; static_assert(std::is_trivially_constructible_v>); static_assert(std::is_trivially_copy_constructible_v>); GCC rejects; Clang+EDG+MSVC accept; and I think Clang+EDG+MSVC are conforming.
[Bug libstdc++/106611] std::is_nothrow_copy_constructible returns wrong result
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106611 --- Comment #13 from Arthur O'Dwyer --- (In reply to Andrew Pinski from comment #12) > I suspect this is a dup of bug 100470 then. Yep, I agree. My previous comment was a longwinded version of jwakely's https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100470#c1 :)
[Bug libstdc++/106611] std::is_nothrow_copy_constructible returns wrong result
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106611 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #11 from Arthur O'Dwyer --- Jiang An wrote: > I've mailed the LWG Chair to submit an LWG issue that requests clarification > of "is known not to throw any exceptions". > FYI, there's at least one library implementor holding the same opinion as > yours. > https://quuxplusone.github.io/blog/2023/04/17/noexcept-false-equals-default/ Quuxplusone here. :) I don't think this is LWG jurisdiction at all. This isn't even a bug in libstdc++'s . This is purely a GCC core-language bug. GCC's builtin __is_nothrow_constructible(T, T&&) simply returns the wrong answer when the selected constructor is "trivial, but noexcept(false)." // https://godbolt.org/z/5szW6KeWq struct C { C(C&&) noexcept(false) = default; }; static_assert(!__is_nothrow_constructible(C, C&&)); // GCC+EDG fail; Clang+MSVC succeed Notice that the builtin returns the correct answer when the selected constructor is "non-trivial, noexcept(false), but still defaulted so we know it can't throw." The problem is specifically with *trivial* ctors. @jwakely, I propose that this issue should be recategorized as a compiler bug. (And I'm also voting effectively "NAD" on LWG3967.)
[Bug c++/94162] ICE [neg] bad return type in defaulted <=>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94162 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #15 from Arthur O'Dwyer --- The test case in #c10 seems to be fixed since GCC 12; the rest were fixed since GCC 11. Should this bug be RESOLVED FIXED at this point? https://godbolt.org/z/d16x181xh
[Bug c++/101943] ICE: Segmentation fault (in cat_tag_for)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101943 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #4 from Arthur O'Dwyer --- This seems to be fixed since GCC 11.1; should it be RESOLVED FIXED at this point? https://godbolt.org/z/Tox8f716q
[Bug c++/110948] New: Incorrect -Winvalid-constexpr on virtual defaulted operator==
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110948 Bug ID: 110948 Summary: Incorrect -Winvalid-constexpr on virtual defaulted operator== Product: gcc Version: 14.0 Status: UNCONFIRMED Keywords: diagnostic Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- Bug #98712 seems related. // https://godbolt.org/z/eKKxcovEn struct D; struct B { bool operator==(const B&) const; virtual bool operator==(const D&) const; }; struct D : B { bool operator==(const D&) const override = default; }; GCC alone gives this bogus -Winvalid-constexpr warning: : In member function 'virtual constexpr bool D::operator==(const D&) const': :10:10: warning: call to non-'constexpr' function 'bool B::operator==(const B&) const' [-Winvalid-constexpr] 10 | bool operator==(const D&) const override = default; | ^~~~ :5:10: note: 'bool B::operator==(const B&) const' declared here 5 | bool operator==(const B&) const; | ^~~~ This is obviously contrived code, but the symptom might indicate that GCC is too eager to pretend that the user actually wrote `constexpr`, in situations where the compiler is merely supposed to make an implicitly defined function constexpr-friendly if possible. The AFAICT-analogous situation with `operator=` instead of `operator==` correctly compiles without warning: https://godbolt.org/z/Mof1qaadr
[Bug libstdc++/110917] std::format_to(int*, ...) fails to compile because of _S_make_span
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110917 --- Comment #2 from Arthur O'Dwyer --- > Alternatively, we could replace the contiguous_iterator<_OutIter> constraint > with constructible_from, _OutIter, iter_difference_t<_OutIter>>. I think `is_same` is preferable to `constructible_from<...>` just because it's simpler; I wouldn't recommend the hairier thing unless there was a known reason for it. Doing the hairier thing would immediately trigger a search for the corner case where it would fail. ;) (Suppose the author of _OutIter arranges that sentinel_for — maybe that'd do the trick...) Btw, even though my reduced test case was contrived, it originates from an actually realistic use-case AFAIK: using `format` to format ASCII text automatically into an array of char16_t or char32_t (presumably on a platform with unsigned plain char).
[Bug libstdc++/110917] New: std::format_to(int*, ...) fails to compile because of _S_make_span
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110917 Bug ID: 110917 Summary: std::format_to(int*, ...) fails to compile because of _S_make_span Product: gcc Version: 14.0 Status: UNCONFIRMED Keywords: rejects-valid Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/9onGvqfha #include #include #include void f(std::list::iterator it) { std::format_to(it, ""); // OK } void g(std::vector::iterator it) { std::format_to(it, ""); // boom! } libc++ and Microsoft are both completely happy with this code. libstdc++ is happy with `f` but unhappy with `g`. I suspect that someplace is accepting "contiguous iterators of any old T" when it means to limit itself to "contiguous iterators of char" specifically. In file included from :1: .../include/c++/14.0.0/format:2609:36: error: cannot initialize a parameter of type 'char *' with an rvalue of type 'int *' 2609 | : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n, _M_buf)), |^~ .../include/c++/14.0.0/format:3641:32: note: in instantiation of member function 'std::__format::_Iter_sink>>::_Iter_sink' requested here 3641 | _Iter_sink<_CharT, _Out> __sink(std::move(__out)); |^ .../include/c++/14.0.0/format:3683:24: note: in instantiation of function template specialization 'std::__format::__do_vformat_to<__gnu_cxx::__normal_iterator>, char, std::basic_format_context, char>>' requested here 3683 | { return __format::__do_vformat_to(std::move(__out), __fmt, __args); } |^ .../include/c++/14.0.0/format:3778:19: note: in instantiation of function template specialization 'std::vformat_to<__gnu_cxx::__normal_iterator>>' requested here 3778 | return std::vformat_to(std::move(__out), __fmt.get(), | ^ :9:10: note: in instantiation of function template specialization 'std::format_to<__gnu_cxx::__normal_iterator>>' requested here 9 | std::format_to(it, ""); | ^ .../include/c++/14.0.0/format:2574:28: note: passing argument to parameter '__ptr' here 2574 | _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n, |^ 1 error generated.
[Bug libstdc++/70472] is_copy_constructible>>::value is true
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70472 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #14 from Arthur O'Dwyer --- > The problem is that std::vector does have a copy constructor, so the trait > value is true, but instantiating that constructor produces an error when the > value_type is not copyable. Worse, the value_type can be incomplete, as in struct Node { std::vector children_; }; Askar: see https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/ I suggest closing this bug report as Not A Bug. It certainly shouldn't be tagged `wrong-code`.
[Bug c++/110102] [13 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102 --- Comment #9 from Arthur O'Dwyer --- (In reply to Jason Merrill from comment #8) > (In reply to Arthur O'Dwyer from comment #6) > > I still think it would be nice if GCC stopped supporting > > int f(std::vector v) { return v[0]; } > > , at least silently by default. > > Fixed (to require -fconcepts-ts) on trunk. Nice! Thank you!
[Bug c++/110102] [13/14 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102 --- Comment #6 from Arthur O'Dwyer --- (In reply to Jason Merrill from comment #5) > (In reply to Arthur O'Dwyer from comment #4) > > My first, reduced, example, where `std::list v = {1,2,3}` is accepted for > > move-only type `A`, is 100% a bug and should be fixed. But that is easy to > > fix. > > It's pedantically a bug, but only because of the suboptimal specified > initializer_list semantics. Just looking at that line I expect a list of As > initialized from integers [...] It's also unfortunate that initialization > from a prvalue initializer_list can't use A's move constructor. Yes, but since you just implemented P2752, you know why we can't do *that*. :) I strongly disagree that this is [only] "pedantically" a bug. The behavior of std::initializer_list is super fundamental to "Intro C++". If GCC continues with this behavior, I guarantee there will be tons of newbies asking (me, other instructors, StackOverflow, etc) "If initializer lists are so immutable, then why does this code compile? You told me it wouldn't!" Before C++20, I got tons of the same question for GCC's acceptance of int f(auto x) { return x; } I still think it would be nice if GCC stopped supporting int f(std::vector v) { return v[0]; } , at least silently by default. Similarly here: I wouldn't actually mind if GCC supported std::vector> v = { f, g, h }; with an on-by-default warning. It's that it accepts the extension *silently*, and the extension is *so visible to newbies* and *so critical to their understanding of the actual language*, that has me worried. Here's a sketch of the `vector` example: https://godbolt.org/z/dPnfbnhsf
[Bug c++/110102] [13/14 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102 --- Comment #4 from Arthur O'Dwyer --- I came across the `Widget` bug in the course of writing (and it's now mentioned in) this blog post on value semantics and PMR: https://quuxplusone.github.io/blog/2023/06/03/p1144-pmr-koans/#the-evil-allocator-aware-type FWIW I'm highly sympathetic to the idea that `Widget` is "not a sensible program" and I would love to see CWG or LWG make it UB. ;) It would make what I'm trying to do with value semantics in P1144 so much easier if some more of these "unreasonable programs" were less well-defined. But that seems like a *gigantic* task. My first, reduced, example, where `std::list v = {1,2,3}` is accepted for move-only type `A`, is 100% a bug and should be fixed. But that is easy to fix. Jason, *I* don't know by what heuristic the optimizer decides to do this optimization or not... but are *you* at all worried that it might be a pessimization for some types? For example, suppose we had struct NthPrime { constexpr NthPrime(int); ... }; std::vector primes = {1,2,3,4,5,6}; Here we *want* to make an initializer_list backed by a static array of NthPrime at compile time. If we make an initializer_list, then we'll have to run the NthPrime(int) constructor at runtime, and that's expensive. I tried out this example on Godbolt and the optimizer made the correct choice in this specific case, so that's good. But I figured I should mention the scenario in case it brings something to your mind.
[Bug libstdc++/110102] New: [13 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102 Bug ID: 110102 Summary: [13 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type Product: gcc Version: 13.1.0 Status: UNCONFIRMED Keywords: accepts-invalid Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/4Gq3TWE6M #include struct A { A(int) {} A(const A&) = delete; A(A&&) {} }; int main() { std::list v = {1,2,3}; } This should be ill-formed, but GCC 13.1 accepts it! GCC 12.3 and earlier correctly reject it. This is supposed to be constructing a std::initializer_list and calling `list::list(initializer_list)`, which should then complain because `A(const A&)` is deleted. My guess as to what's happening here: - We're definitely calling list(initializer_list) - It's calling _M_range_initialize(il.begin(), il.end()) - That's calling __uninitialized_copy_a - That's probably somehow deciding that because `A` is trivially copyable, we can just memcpy it. I.e. bug #89164 redux. Even if it were copyable, we still wouldn't be allowed to bypass `allocator_traits::construct`. The above snippet uses std::allocator, but I originally found a more complicated case with pmr::polymorphic_allocator: // https://godbolt.org/z/ToT6dW5dM #include #include #include struct Widget { using allocator_type = std::pmr::polymorphic_allocator; Widget(int i) : i_(i) {} explicit Widget(int i, allocator_type) : i_(i) {} explicit Widget(const Widget& rhs, allocator_type) : i_(rhs.i_ + 100) {} int i_; }; static_assert(std::is_trivially_copyable_v); int main() { std::pmr::vector v = {1,2,3}; printf("%d %d %d\n", v[0].i_, v[1].i_, v[2].i_); } My understanding is that this should print "101 102 103", as GCC 12 does. But GCC 13.1 prints "1 2 3" instead.
[Bug c++/110005] New: Writable strings seem too greedy in overload resolution
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110005 Bug ID: 110005 Summary: Writable strings seem too greedy in overload resolution Product: gcc Version: unknown Status: UNCONFIRMED Keywords: diagnostic Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- I'm not clear on the entire behavior of -Wwrite-strings; bug 61579 seems relevant. So there's probably an iceberg lurking below the surface. But here's the tip, anyway. // https://godbolt.org/z/Y5saPdozT struct Evil { Evil(const char*, const void*) { puts("1"); } Evil(const char*, std::string) { puts("2"); } Evil(const char*, char*) { puts("3"); } }; int main() { Evil e = {"", ""}; } MSVC considers the only viable candidates #1 and #2. Clang considers #1 and #2 preferable to #3, but will pick #3 if it's the only candidate. GCC considers #3 the *best* candidate, even better than #1. Or again, something like this: void f(const char *, std::string) { puts("4"); } template void f(T *, std::remove_const_t *) { puts("5"); int main() { f("", ""); } MSVC considers #4 the only viable candidate. Clang considers #4 preferable to #5, but will pick #5 if it's the only candidate. GCC considers #5 the *best* candidate, even better than #4. Obviously MSVC's behavior is the conforming one; but I understand GCC isn't likely to go all the way *there*. Still, Clang's behavior strikes me as a better compromise than GCC's. As a consolation prize, assuming there's some way to turn off GCC's writable-strings extension, could the text of -Wwrite-strings' warning message be updated to provide that option? E.g. instead of the current > warning: ISO C++ forbids converting a string constant to > 'std::remove_const_t*' {aka 'char*'} [-Wwrite-strings] it could say, like, > warning: ISO C++ forbids converting a string constant to > 'std::remove_const_t*' {aka 'char*'}; pass -fno-writable-strings > to disable this extension [-Wwrite-strings] or however the extension can actually be disabled.
[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945 --- Comment #11 from Arthur O'Dwyer --- (In reply to Andrew Pinski from comment #8) > (In reply to Arthur O'Dwyer from comment #7) > > // https://godbolt.org/z/Ea43Y65z4 > > struct Widget { > > int i = 1; > ... > > In this case, Widget has no constructors, > > No, it has a constructor because of the NSDMI. NSDMI causes a non-trivial > constexpr constructor to be created. Fair. I meant Widget has no _program-defined_ constructors (such as would have unknown effects and might invisibly-to-the-compiler escape a copy of ``). I might still be using the wrong term. But you found a better example without that wrinkle, anyway. :)
[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945 --- Comment #7 from Arthur O'Dwyer --- Richard Biener wrote: > Are we using the wrong check or is escaping 'this' > for these kind of classes invoking undefined behavior? Wow, this got a lot of traffic quickly! Sounds like you (Richard, Andrew) are on top of the issue here, where a constructor is involved; but once you start talking about heuristics and checks, I think it would be productive for you two to make sure you're both on the same page with *this* example: // https://godbolt.org/z/Ea43Y65z4 struct Widget { int i = 1; int a[4]; }; Widget *global = nullptr; Widget make2() { Widget w; global = return w; } void g() { global->i = 42; } int main() { Widget w = make2(); int i = w.i; g(); return (i == w.i); // Does this need to be reloaded and // compared? or is it obviously true? } In this case, Widget has no constructors, and I think it would be perfectly defensible for the compiler to say that "global = " is not a valid way to escape the address of that prvalue result (even though copy elision will make the w in make() and the w in main() the same object). But do both of *you* have the same answer to that paradox? If you don't, then you might also not agree about what the appropriate heuristic should be in the original case and might end up talking past each other.
[Bug c++/109945] New: Escape analysis hates copy elision: different result with -O1 vs -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945 Bug ID: 109945 Summary: Escape analysis hates copy elision: different result with -O1 vs -O2 Product: gcc Version: unknown Status: UNCONFIRMED Keywords: wrong-code Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- Background: https://quuxplusone.github.io/blog/2021/03/07/copy-elision-borks-escape-analysis/ The background paradox here is, "When class Widget is subject to copy elision, then any unseen function can return a prvalue Widget whose address has already escaped!" Aaron Puchert and I were discussing this, with examples. (He thinks the resolution of the paradox is "you *must* treat a lot more things as escaped"; I think an acceptable resolution would be "you may treat copy-elision itself as a magic that invalidates pointers and references even though the object is still in the same place.") But then I came up with an example that didn't rely on copy elision at all. We both agree this code is perfectly well-defined — yet GCC miscompiles it at -O1! // https://godbolt.org/z/bTnv68nhG struct Widget { Widget(); int i = 1; int a[4]; }; Widget *global = nullptr; Widget::Widget() { global = this; } Widget make() { return Widget(); } void g() { global->i = 42; } int main() { Widget w = make(); int i = w.i; g(); return (i == w.i); // Does this need to be reloaded and // compared? or is it obviously true? } gcc -O0 and gcc -O2 both correctly return 0 from main. gcc -O1 wrongly returns 1 from main. *At least* since C++17, I think the -O1 result is flat-out wrong codegen. We have `global == `, and so the call to `g()` can definitely modify `w.i`. (Clang always treats Widgets' addresses as escaped, no matter what Widget looks like. MSVC's escape analysis is more complicated and I have not yet been able to trick it into wrong codegen.)
[Bug c++/93106] [c++2a] Deleted move constructor is not selected when returning an automatic variable
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93106 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #7 from Arthur O'Dwyer --- According to godbolt.org, Bug 93929, Bug 108594, and this Bug 93106 all appear to be fixed now (failed in GCC 12, correct behavior in GCC 13.1).
[Bug c++/108759] "mandatory copy elision" not implemented during constant evaluation redux
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108759 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- I believe what I'm going to say is simply a duplicate of Davis's report, but just in case it's different, I'll add mine here. This is a slightly modified version of the example from [class.copy.elision], merely modified so that g() returns a C++17 prvalue instead of relying on NRVO/copy-elision. Original example: https://eel.is/c++draft/class.copy.elision#2 Modified example: // https://godbolt.org/z/n43jPs1Kj struct A { void *p; constexpr A(): p(this) {} }; constexpr A g() { return A(); } constexpr A b = g();// well-formed, b.p points to b static_assert(b.p == ); MSVC and Clang accept. GCC incorrectly rejects: :11:19: error: 'A{((void*)(&))}' is not a constant expression 11 | constexpr A b = g();// well-formed, b.p points to b | ^ :12:19: error: non-constant condition for static assertion 12 | static_assert(b.p == ); | ^
[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #23 from Arthur O'Dwyer --- (In reply to Jonathan Wakely from comment #22) > > Richi suggested that we could avoid these runtime branches (which hurt > optimization, see PR 109445) if we knew how many bytes of tail padding there > are in _Tp [...] > We don't have a built-in to tell us the number of [trailing] padding bytes, > but we > might be able to use something like this Three thoughts that might be helpful: - There may be padding in the middle of an object, and I'm not confident that the Standard actually forbids it from being used. Of course your approach works fine on the Itanium ABI, and probably works everywhere that actually exists. If you've got chapter+verse proving that it must work *everywhere*, I'd appreciate seeing it, just for my own information. - If GCC were ever to add a builtin for this notion, IMO the proper name would be `__datasizeof(T)`. See https://danakj.github.io/2023/01/15/trivially-relocatable.html#data-size - You can implement your library trait like this; see https://quuxplusone.github.io/blog/2023/03/04/trivial-swap-prize-update/#step-1.-std-swap-can-t-assume-it template struct __libcpp_datasizeof { struct _Up { [[__no_unique_address__]] _Tp __t_; char __c_; }; static const size_t value = __builtin_offsetof(_Up, __c_); }; Unfortunately it looks like GCC doesn't support `__attribute__((__no_unique_address__))` in C++03 mode. (Neither does Clang. What is up with that!) Your suggested trait implementation is slightly wrong for `is_final` types: you return 0 but really a final type _can_ have usable tail padding. See https://godbolt.org/z/P6x459MEq
[Bug c++/109381] New: Ambiguous member lookup with this-> accepted when it should be rejected
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109381 Bug ID: 109381 Summary: Ambiguous member lookup with this-> accepted when it should be rejected Product: gcc Version: unknown Status: UNCONFIRMED Keywords: accepts-invalid Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/ex97db8cT template struct B { int f() { return 1; } }; struct C { int f() { return 2; } }; template struct D : B, C { int test() { return this->f(); // GCC calls C::f; Clang and MSVC reject } }; int main() { D d; return d.test(); } This can't possibly be unreported yet, but a quick search failed to find any bug filed on the subject. Sorry if this is a duplicate. GCC correctly thinks that `return f();` should call `C::f` because `B::f` is not considered because `B` is a dependent base class and we didn't say `this->`. But, GCC wrongly thinks that `return this->f();` should ALSO call `C::f`. Clang and MSVC agree that it should be ambiguous, because now it IS looked up in both phase 1 and phase 2, and an `f` is found in both base classes, so the lookup should be considered ambiguous. According to Godbolt, the issue was introduced somewhere between GCC 7.5 (OK) and GCC 8.1 (buggy).
[Bug c++/100248] ICE with global "default" keyword
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100248 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #3 from Arthur O'Dwyer --- Bug 107321 and bug 105202 are duplicates. In bug 107321, Martin Liška writes: "Started with r10-4397-gb7689b962dd6536b."
[Bug c++/109017] New: ICE on unexpanded pack from C++20 explicit-template-parameter lambda syntax
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109017 Bug ID: 109017 Summary: ICE on unexpanded pack from C++20 explicit-template-parameter lambda syntax Product: gcc Version: unknown Status: UNCONFIRMED Keywords: ice-on-invalid-code Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/bdT84P318 template struct A { static void g() { int dummy[] = { [](Ts... ts){ int i = Ts(); } ... }; } }; int main() { A::g(); } : In instantiation of 'static void A< >::g() [with = {int}]': :12:14: required from here :4:13: internal compiler error: in tsubst_pack_expansion, at cp/pt.cc:13388 4 | int dummy[] = { | ^ 0x247a53e internal_error(char const*, ...) ???:0 0xae95dc fancy_abort(char const*, int, char const*) ???:0 0xd09f45 instantiate_decl(tree_node*, bool, bool) ???:0 0xd362db instantiate_pending_templates(int) ???:0 0xbe4555 c_parse_final_cleanups() ???:0 0xe21948 c_common_parse_file() ???:0 Please submit a full bug report, with preprocessed source (by using -freport-bug). Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. Compiler returned: 1 Apparently GCC fails to recognize the `class... Ts` in the angle brackets (new syntax in C++20) as pertaining to the lambda itself, and not to the outer scope. So when GCC sees an unexpanded `Ts` in the inner scope, GCC happily accepts it (and then ICEs). Notice that if you change `Ts()` to `ts` in the inner scope, GCC correctly rejects the code with the usual "parameter packs not expanded" error. The ICE is triggered specifically by misuse of `Ts`-from-the-new-in-C++20-syntax.
[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 --- Comment #11 from Arthur O'Dwyer --- (In reply to Jonathan Wakely from comment #10) > std::move(x,y,z) and std::copy(z,y,z) use the same underlying > implementation, so it does have the same issue, but will be fixed by the > same change. Right; also std::rotate, std::set_union, etc., I'd expect would all be fixed by the same change to std::copy. You might want to peek at std::swap_ranges, though. Microsoft's STL has trouble there; I don't *think* libstdc++ does, but you might as well check me.
[Bug libstdc++/108846] New: std::copy, std::copy_n on potentially overlapping subobjects
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846 Bug ID: 108846 Summary: std::copy, std::copy_n on potentially overlapping subobjects Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://gcc.godbolt.org/z/EfdG4nzv9 #include #include struct B { B(int i, short j) : i(i), j(j) {} int i; short j; /* 2 byte padding */ }; struct D : B { D(int i, short j, short x) : B(i, j), x(x) {} short x; }; int main() { D ddst(1, 2, 3); D dsrc(4, 5, 6); B *dst = B *src = std::copy_n(src, 1, dst); // should do `*dst = *src` assert(ddst.x == 3); // FAILS } Similarly if you use `std::copy(src, src+1, dst)`. The problem here is that `std::copy` and `std::copy_n` (and presumably some other algorithms too, like `std::move`) believe that if a type is trivially copyable, then it's safe to use `memcpy` or `memmove` on it. But in fact that's safe only if either - the type's "sizeof" is equal to its "data size, without trailing padding"; or - you happen to have external information proving that the object being copied is not a potentially overlapping subobject. I think it's safe for `std::copy` and `std::copy_n` to use memcpy/memmove if they are given a destination range of 2-or-more elements; but if it's just a single object, then (by the letter of the law) they must assume the destination object might be a potentially overlapping subobject, and not memcpy into it. (Full disclosure: I will be THRILLED if you close this as "not a bug," because that will be ammunition to go to LWG and say "look, vendors think this behavior is fine, we should actually standardize this behavior and remove the expectation that STL algorithms can ever handle potentially overlapping subobjects.")
[Bug c++/108257] New: Incorrect (non-unique) mangling of structured binding's backing variable
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108257 Bug ID: 108257 Summary: Incorrect (non-unique) mangling of structured binding's backing variable Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- C++20 permits structured bindings (decomposition declarations) to be `static`. This means we can use them in inline functions, where they need to be mangled in the context of that inline function. Clang seems to get this right; GCC forgets to include the context. // https://godbolt.org/z/aKanscav3 struct A { int x,y; }; inline int f() { static auto [a,b] = A{1,2}; return a; } inline int g() { static auto [a,b] = A{3,4}; return a; } int (*pf)() = f; int (*pg)() = g; int main() { printf("%d %d\n", f(), g()); printf("%d %d\n", pf(), pg()); } This program should print "1 3" twice. On GCC, it fails to assemble, because the symbol name `_ZNDC1a1bEE` is used for both backing variables. On Clang, the symbol names are `_ZZ1fvEDC1a1bE` and `_ZZ1gvEDC1a1bE` instead. (Totally off-topic, it is awful that the name of the backing variable includes all of the names of the individual bindings, concatenated. That can easily produce humongous symbol names, and interacts unusually poorly with (UB) macro-expansion. If anyone wants to go talk to the Itanium ABI folks and get everyone to switch to a simple "mangling number" scheme like we have already built for lambda closure types, that would be awesome. Notice that you already need a "mangling number" scheme *on top* of the current design, because of https://godbolt.org/z/cYqxzxfxe — so I'm just proposing to make the scheme simpler, if the Itanium ABI folks are willing to change it.)
[Bug c++/108216] Wrong offset for (already-constructed) virtual base during construction of full object
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108216 --- Comment #1 from Arthur O'Dwyer --- Possibly tangentially related: #70644, #81051
[Bug c++/108216] New: Wrong offset for (already-constructed) virtual base during construction of full object
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108216 Bug ID: 108216 Summary: Wrong offset for (already-constructed) virtual base during construction of full object Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/6qMTY6bGn #include struct A *ga = nullptr; struct B *gb = nullptr; struct C *gc = nullptr; struct D *gd = nullptr; struct A { explicit A() { printf("Constructing A at %p\n", (void*)this); ga = this; printf(" A is %p\n", (void*)ga); } virtual void f() {} void *a() { return this; } }; struct B : virtual A { explicit B() { printf("Constructing B at %p\n", (void*)this); gb = this; printf(" B.A is %p\n", (void*)(A*)gb); } void *b() { return this; } }; struct C : virtual A { explicit C() { printf("Constructing C at %p\n", (void*)this); gc = this; printf(" B.A is %p -- look here!\n", (void*)(A*)gb); printf(" C.A is %p\n", (void*)(A*)gc); } // void f() override {} // give Clang trouble, too void *c() { return this; } }; struct D : B, C { explicit D(): B(), C() { printf("Constructing D at %p\n", (void*)this); gd = this; printf(" D.B.A is %p\n", (void*)(A*)(B*)gd); printf(" D.C.A is %p\n", (void*)(A*)(C*)gd); } }; int main() { D d; printf(" is %p\n", (void*)); printf(" is %p\n", d.c()); printf(" is %p\n", d.b()); printf(" is %p\n", d.a()); } == Constructing A at 0x7ffd2ef4db10 A is 0x7ffd2ef4db10 Constructing B at 0x7ffd2ef4db10 B.A is 0x7ffd2ef4db10 Constructing C at 0x7ffd2ef4db18 B.A is 0x7ffd2f34ed1c -- look here! C.A is 0x7ffd2ef4db10 Constructing D at 0x7ffd2ef4db10 D.B.A is 0x7ffd2ef4db10 D.C.A is 0x7ffd2ef4db10 is 0x7ffd2ef4db10 is 0x7ffd2ef4db18 is 0x7ffd2ef4db10 is 0x7ffd2ef4db10 == Before the line marked "look here": - The `A` object was constructed at 0x7ffd2ef4db10. - The `B` object pointed to by `gb` has been completely constructed. - So `gb->a()` ought to return the address of that `A` object, 0x7ffd2ef4db10. But instead it returns 0x7ffd2f34ed1c, which is 0x40120c bytes away from the correct value! I wonder if this is caused by the B-in-D and C-in-D vptrs having the same offset, so that when we think we're access the B vtable of `*gb`, we're actually accessing the C vtable of that empty C object...? But then, still, the offset from the beginning of the B object or the beginning of the C object, to the A virtual base, ought to be exactly the same number. I can't figure out a reason for the answer to be off by 0x40120c. == Notice that Clang passes this test case as shown; BUT, if you uncomment the line marked "give Clang trouble, too", then Clang will join GCC in producing wrong results for the line marked "look here". MSVC passes both test cases, but that's not surprising because MSVC has a radically different ABI for struct layout. Originally reported by @caster on Slack, here: https://cpplang.slack.com/archives/CBTFTLR9R/p1671750342552189
[Bug c++/87697] Casting a base class to derived gives no warning
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87697 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #4 from Arthur O'Dwyer --- jynelson: Static-casting from Base& to Derived& is the foundation of the "Curiously Recurring Template Pattern" in C++, and therefore can't be allowed to trigger any diagnostic with -Wall -Wextra. (Many industry codebases build with -Wall -Wextra, and also use the CRTP.) *Aside* from that practical consideration, I don't think there's anything wrong with casting from one type to another. The point of type-cast syntax is to say "Don't worry, compiler, I know what I'm doing." If one doesn't know what one's doing, then one shouldn't use casts at all, and just stick to the implicit conversions. It's already an error to *implicitly convert* from Base& to Derived&, so if you stick to implicit conversions you'll get exactly the behavior you want. Suggest closing this issue as NOTABUG. But see also #96765 (for this kind of cast specifically *inside a constructor*).
[Bug c++/106903] New: Incorrectly accepts call to function template when deduced type doesn't match adjusted type
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106903 Bug ID: 106903 Summary: Incorrectly accepts call to function template when deduced type doesn't match adjusted type Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/T1vPGYash template struct Array { template operator Array() const; }; template void foo(Array x, Array y); int main() { foo(Array(), Array()); } My understanding is that template type deduction on the call to `foo` should fail, because even though we can unambiguously deduce [T=int, U=char], and even though the actual argument's type Array is CONVERTIBLE to the formal parameter's type Array, it's not actually the same type. My understanding is that a parameter that contributes to deduction must have the same type as its corresponding function argument. MSVC correctly rejects with this confusing message-spew: (13): error C2664: 'void foo(Array,Array)': cannot convert argument 2 from 'Array' to 'Array' (13): note: Binding to reference (13): note: followed by (13): note: Call to user-defined-conversion 'Array::operator Array(void) const<4>' (4): note: see declaration of 'Array::operator Array' (13): note: followed by (13): note: Exactly the same type (8): note: see declaration of 'foo' Clang correctly rejects with this message: :13:5: error: no matching function for call to 'foo' foo(Array(), Array()); ^~~ :8:6: note: candidate template ignored: deduced type 'Array<[...], sizeof(int) aka 4>' of 2nd parameter does not match adjusted type 'Array<[...], 6>' of argument [with T = int, U = char] void foo(Array x, ^
[Bug libstdc++/105241] New: std::bitset::reference should have an ADL swap
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105241 Bug ID: 105241 Summary: std::bitset::reference should have an ADL swap Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- (Originally reported by Nicholas Sielicki on the cpplang Slack) // https://godbolt.org/z/138cPv5cn #include #include std::bitset<1> a = {1}; std::bitset<1> b = {0}; int main() { using std::swap; swap(a[0], b[0]); return a[0] == 0 && b[0] == 1; // should be TRUE, right? } :8:9: error: no matching function for call to 'swap(std::bitset<1>::reference, std::bitset<1>::reference)' 8 | swap(a[0], b[0]); | ^~~~ Swapping elements via the std::swap two-step works for `std::vector`; I see no reason it shouldn't also work for `std::bitset`. libc++ and Microsoft STL both support `swap` on `bitset::reference` just fine.
[Bug c++/104792] [g++ and/or libstdc++] Wunused-local-typedefs + C++20 concepts = annoying
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104792 --- Comment #2 from Arthur O'Dwyer --- @Andrew Pinski: Sorry, looks like my description ended up not matching the Godbolt (I said "three lines marked X," but there are only two lines marked X, for example.) Here's the Godbolt with one of the two lines commented out. The annoying warning is present. // https://godbolt.org/z/Ms4sePPfe #include void test() { struct It { using value_type = int; using difference_type = int; int& operator*() const; It& operator++(); // X //It operator++(int); // X }; static_assert(std::is_same_v< std::iter_value_t, int>); static_assert(std::is_same_v< std::iter_rvalue_reference_t, int&&>); } $ g++ -std=c++20 -Wall -Wextra test.cpp test.cpp: In function 'void test()': test.cpp:6:15: warning: typedef 'using difference_type = int' locally defined but not used [-Wunused-local-typedefs] 6 | using difference_type = int; | ^~~
[Bug c++/104792] New: [g++ and/or libstdc++] Wunused-local-typedefs + C++20 concepts = annoying
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104792 Bug ID: 104792 Summary: [g++ and/or libstdc++] Wunused-local-typedefs + C++20 concepts = annoying Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- This might be considered "not a bug", or "duplicate of #61596", or "bug but in a different way from what Arthur suggests," so I'm going to give the non-reduced test case and let one of you (@jwakely perhaps) worry about how to reduce it. // https://godbolt.org/z/v9Wv8vY3G #include void test() { struct It { using value_type = int; using difference_type = int; int& operator*() const; It& operator++(); // X It operator++(int); // X }; static_assert(std::is_same_v, int>); static_assert(std::is_same_v, int&&>); } Compile with "g++ -std=c++20 -W -Wall" and libstdc++. GCC will give a warning: warning: typedef 'using difference_type = int' locally defined but not used [-Wunused-local-typedefs] 6 | using difference_type = int; | ^~~ However, if you then delete any of the three lines marked "X", the warning will go away again. I believe this is because `iter_value_t` relies on a C++20 Concepts constraint where `difference_type` *is* checked when `It` is an `input_iterator`, but is *not* checked when `It` is not an iterator. So, when these precise three operators exist, the typedef isn't unused, but when any one of them doesn't exist, GCC gives the unused-typedef warning. I claim that the user-programmer shouldn't be responsible for tracking the internal implementation details of the constraints of `std::iter_value_t`. I just want to make a local type that has all the pieces of an iterator, without GCC helpfully getting in the way and warning me that *right now* (according to the internal implementation details of libstdc++) some of those pieces aren't being used. I admit that in this case the warning is surfaced only when I *fail* to implement one of those three member functions, so I actually have *not* implemented "all the pieces of an iterator" in this test case. I'm betting that it's possible to reproduce this annoying issue, somewhere in libstdc++, even without that caveat, though. For now, I'll silence the warning by removing my unused typedef `difference_type`, i.e. #include void test() { struct It { using value_type = int; int& operator*() const; }; static_assert(std::is_same_v, int>); static_assert(std::is_same_v, int&&>); } But I'm uncomfortable with that, because I don't know if later revisions/bugfixes to the library will require me to re-add those pieces I've removed.
[Bug libstdc++/68350] std::uninitialized_copy overly restrictive for trivially_copyable types
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68350 --- Comment #12 from Arthur O'Dwyer --- jwakely wrote: > Correction: they need to be the same type. We can't memcpy here: > > struct A { }; > struct B { B() = default; B(A) { do_stuff(); } }; > > void (A* f, A* l, B* out) { > std::uninitialized_copy(f, l, out); > } Right, in your case, the ctor `B(A)` runs user-defined code (it's not "trivial") so obviously we can't do the optimization. But even in general, see my 2018 blog post "Trivially-constructible-from." https://quuxplusone.github.io/blog/2018/07/03/trivially-constructible-from/ using A2 = long long; using B2 = int64_t; // for the sake of argument, this is "long int" void (A* f, A* l, B* out) { std::uninitialized_copy(f, l, out); } The library can't, by itself, determine that memcpy would be safe here. The library needs help from the compiler, e.g. via a new compiler builtin __is_trivially_constructible_from(T, U). (This is *not* the same as the existing `is_trivially_constructible` type trait, because blog post.)
[Bug libstdc++/104559] New: vector v; v.insert(v.begin()); compiles, but it shouldn't
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104559 Bug ID: 104559 Summary: vector v; v.insert(v.begin()); compiles, but it shouldn't Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/3efs3aY67 #include int main() { std::vector v; v.insert(v.begin()); // libstdc++ accepts! } Somehow libstdc++ believes that `vector::insert(_Bit_const_reference)` should work. (I bet it inserts "false" at the given position, but I haven't checked.)
[Bug middle-end/104195] New: Fails to optimize nested array indexing p[i/N].data[i%N]
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104195 Bug ID: 104195 Summary: Fails to optimize nested array indexing p[i/N].data[i%N] Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- GCC seems to be unable to optimize some nested array accesses of the form p[i/N].data[i%N] into a simple ((T*)p)[i]. The C test case is struct CChunk { int data[4]; }; int f(struct CChunk *p, unsigned long long i) { return p[i/4].data[i%4]; } gcc -O2 currently produces: movq %rsi, %rax andl $3, %esi shrq $2, %rax salq $4, %rax addq %rax, %rdi movl (%rdi,%rsi,4), %eax ret but I would prefer it to produce: movl (%rdi,%rsi,4), %eax retq A more exhaustive C++ test follows — GCC can optimize a few of these, but not all. (Clang can't optimize any of these; I've just filed https://github.com/llvm/llvm-project/issues/53367 about that.) https://godbolt.org/z/3E1e6c5e3 template struct Chunk { T data[N]; }; template int f(Chunk *p, IndexType i) { return p[i/N].data[i%N]; } template int f(Chunk*, unsigned long long); // GCC wins template int f(Chunk*, unsigned long long); // GCC wins template int f(Chunk*, unsigned); template int f(Chunk*, unsigned); template int f(Chunk*, unsigned long long); // GCC wins template int f(Chunk*, unsigned long long); template int f(Chunk*, unsigned); template int f(Chunk*, unsigned);
[Bug c++/101421] ICE: in lookup_template_class_1, at cp/pt.c:10005
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101421 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- C++14 reproducer: https://gcc.godbolt.org/z/WafKPneef template void f() { [](auto){}.operator(); } template void f();
[Bug c++/101239] "Internal compiler error: Error reporting routines re-entered." in size_in_bytes_loc
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101239 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #4 from Arthur O'Dwyer --- I believe I just hit this as well. Here's a C++20 reproducer: auto f(auto a) -> decltype(a+1) { return a+1; } struct Incomplete *p; auto b = f(p); The problem seems to be something about over-eager hard-erroring on pointer arithmetic with incomplete types, because GCC also rejects this valid code: auto f(auto a) requires requires { a+1; } { return a+1; } auto f(auto a) { return a; } struct Incomplete *p; auto b = f(p); (Should call the unconstrained overload; but GCC hard-errors instead.)
[Bug c++/96441] ICE in tree check: expected integer_cst, have cond_expr in get_len, at tree.h:5954
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96441 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- Still there in trunk. Here's a very slightly reduced version: // https://godbolt.org/z/8arT4Gn6P enum a : int; template; template<> enum a : int {c}; :2:35: error: expected unqualified-id before ';' token 2 | template; | ^ :3:26: internal compiler error: Segmentation fault 3 | template<> enum a : int {c}; | ^ 0x20037b9 internal_error(char const*, ...) ???:0 0x8c7150 build_enumerator(tree_node*, tree_node*, tree_node*, tree_node*, unsigned int) ???:0 0xa0bea5 c_parse_file() ???:0 0xb92e22 c_common_parse_file() ???:0 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
[Bug c++/102419] [11/12 Regression][concepts] [regression] return-type-requirement of "Y" does not check that T::type actually exists
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102419 --- Comment #4 from Arthur O'Dwyer --- > IMHO Clang/MSVC are clearly misbehaving here -- when evaluating the > concept-id X, they appear to be substituting {int} into X's > constraint-expression instead of into the normal form of X's > constraint-expression. Isn't this situation exactly analogous to `std::void_t`? template using void_t = void; template auto foo(T t) -> void_t; // SFINAEs away template auto foo(T t) -> int; // this is the only viable candidate static_assert(std::same_as); The language has definitely decided that you can't preemptively fold `void_t` down to `void`; I don't think you should be allowed to preemptively fold `Y` down to `true`, either. I don't know for sure that Clang/MSVC have been authoritatively dubbed righteous, but their behavior certainly seems, to me, more consistent and useful than GCC's.
[Bug c++/102419] New: [concepts] [regression] return-type-requirement of "Y" does not check that T::type actually exists
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102419 Bug ID: 102419 Summary: [concepts] [regression] return-type-requirement of "Y" does not check that T::type actually exists Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/GWjYYnrnM template concept Y = true; template concept X = requires { { 1 } -> Y; }; static_assert(!X); :8:15: error: static assertion failed 8 | static_assert(!X); | ^~~ Clang and MSVC both appear to have the correct behavior -- or what I believe to be the consistent/useful/majority behavior, anyway -- which is that since T::type doesn't exist, the concept shouldn't be satisfied. This seems to be a regression; according to Godbolt, GCC 10.3 had the correct behavior but GCC 11.1 lost it. I wonder if #92268 could be related somehow, since it seems to be something like the inverse issue (nonexistent nested type causing a hard error in 10.x), and it was marked fixed presumably somewhere in the 11.x timeframe.
[Bug c++/94673] [concepts] What is the return type of local parameters of requires expressions?
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94673 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- Yes, this is/was a Clang bug; a return-type-requirement should be applied to decltype((expr)), but Clang was incorrectly applying the requirement to decltype(expr). I think this can now be closed as "not a bug" (the bug was in Clang, not GCC).
[Bug c++/81157] If constexpr does not support Short-circuit evaluation
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81157 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #1 from Arthur O'Dwyer --- I'd say neither a bug nor a defect. In `if constexpr (X && Y)`, `X && Y` is an expression and it must be well-formed, even if it's false -- just like if you did `static_assert((X && Y) == false)`. GCC is behaving according to the C++ Standard in this case. Recommend closing as INVALID.
[Bug c++/92505] Using mutable in constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92505 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #4 from Arthur O'Dwyer --- Confirmed; the test case can be as simple as // https://godbolt.org/z/M9rf31qqq struct S { mutable int m; }; static_assert(S{42}.m == 42); (Removing the "mutable" keyword makes GCC happy.)
[Bug libstdc++/81078] dynamic_cast to virtual base produces the wrong answer
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81078 --- Comment #3 from Arthur O'Dwyer --- Yes, this is a libstdc++ issue. I'm not 100% sure that "the RTTI [generated by GCC] is correct," because I don't know how to use GCC with libc++; but yeah, there's definitely at least some problem with libstdc++ here. Observe that Clang-with-libstdc++ fails, Clang-with-libc++ succeeds: https://godbolt.org/z/PMq6rW9cE
[Bug c++/101353] New: [x86-64] missed optimization: missed tail call in placement-new
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101353 Bug ID: 101353 Summary: [x86-64] missed optimization: missed tail call in placement-new Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/9zP5dP3sE #include struct T { int x; T(int) noexcept; ~T(); }; T factory(int) noexcept; alignas(T) char buffer[sizeof(T)]; void placement_new() { ::new ((void*)buffer) T(42); } void placement_call() { ::new ((void*)buffer) T(factory(42)); } g++ -O2 -std=c++20 test.cpp Somehow the compiler is failing to generate an actual `jmp` tail call for `placement_call` the way it's able to for `placement_new`. _Z13placement_newv: movl $42, %esi movl $buffer, %edi jmp _ZN1TC1Ei _Z14placement_callv: subq $8, %rsp movl $42, %esi movl $buffer, %edi call _Z7factoryi addq $8, %rsp ret Note that right now Clang has the same symptom; but ICC and MSVC both get this right and generate tail-calls appropriately in both cases. So this isn't any obscure C++ corner case AFAICT; seems it's truly just a missed optimization. Clang's missed-optimization bug is filed as https://bugs.llvm.org/show_bug.cgi?id=51000
[Bug libstdc++/96416] to_address() is broken by static_assert in pointer_traits
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 --- Comment #13 from Arthur O'Dwyer --- > And are you recommending that everyone who defines their custom contiguous > iterators specializes pointer_traits for them? Call it _quite_ annoying... Definitely not! When you define a contiguous iterator type, you should just give it a sixth nested typedef alongside the other five (or three in C++20): `using element_type = value_type;`. This enables contiguous-iterator machinery. See https://stackoverflow.com/questions/65712091/in-c20-how-do-i-write-a-contiguous-iterator/66050521#66050521 You should never specialize std::pointer_traits for your own type. ("Can" you? Yes. "Should" you? No.)
[Bug c++/76262] list-initialization prefers initializer_list over copy constructor
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=76262 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #5 from Arthur O'Dwyer --- GCC still has the buggy behavior as of 2021. This bug should be reopened. GCC's behavior here disagrees with all of Clang, ICC, MSVC, and common sense. // https://godbolt.org/z/GKxh8P struct A {}; struct B { B(const B&); explicit B(std::initializer_list); operator A() const; }; extern B b; void test() { auto a{b}; // constructs as if by `B a = { static_cast(b) }`, not `B a = b` } I recently observed real teaching materials claiming that brace-initialization didn't work for copies -- if you want to invoke the copy constructor you MUST use parentheses -- and giving essentially this bug as the reason. (They apparently didn't realize that this behavior was unique to GCC, and the subject of a bug report.)
[Bug c++/70816] bogus error __builtin_strcmp is not a constant expression in a constexpr function
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #2 from Arthur O'Dwyer --- Confirmed, I'm also seeing this in C++20 mode. This affects libc++'s `char_traits::length(const char *)`. Example test case: https://godbolt.org/z/MTq1ex
[Bug libstdc++/99417] New: [C++17] std::variant assignment fails to compile
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99417 Bug ID: 99417 Summary: [C++17] std::variant assignment fails to compile Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/b3P6Ta #include struct Original {}; struct C { C(const Original&); C(C&&) noexcept; C& operator=(const Original&); ~C(); }; void testc(std::variant& vc, const Original& original) { vc = original; } In file included from :1:/include/c++/11.0.1/variant:1445:3: error: call to deleted member function 'operator=' operator=(variant(std::forward<_Tp>(__rhs))); ^ :13:8: note: in instantiation of function template specialization 'std::variant::operator=' requested here vc = original; ^ /include/c++/11.0.1/variant:1368:16: note: candidate function has been implicitly deleted variant& operator=(const variant&) = default; ^ /include/c++/11.0.1/variant:1431:2: note: candidate template ignored: requirement '__not_self &&>' was not satisfied [with _Tp = std::variant] operator=(_Tp&& __rhs) ^ 1 error generated. Removing the keyword `noexcept` from the move-constructor makes this compile. It compiles fine (with or without `noexcept`) on libc++ and MSVC STL.
[Bug c++/99093] New: [missed optimization] Missed devirtualization involving internal-linkage class type (but only sometimes)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99093 Bug ID: 99093 Summary: [missed optimization] Missed devirtualization involving internal-linkage class type (but only sometimes) Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/hx7h7v struct Base { virtual int f() { return 1; } }; namespace { struct Derived1 : public Base { int f() override { return 2; } }; struct Derived2 : public Base {}; } int leaf_class1(Base *p) { return ((Derived1*)p)->f(); } // devirtualized by GCC, because PrivateDerived is provably a leaf int leaf_class2(Base *p) { return ((Derived2*)p)->f(); } // not devirtualized by GCC -- this smells like a missed-optimization bug GCC 4.9 started to be able to devirtualize things in the compiler, based on translation-unit-wide (but still compiler-time) information. GCC 4.9.0 is able to devirtualize the call in `leaf_class1`. This is awesome! However, both GCC 4.9 and GCC trunk fail to apply the exact same optimization to `leaf_class2`. The only difference between `Derived1` and `Derived2` is that `Derived1::f` is declared directly in `Derived1` whereas `Derived2::f` is technically a member of `Base`. That shouldn't matter at all to the devirtualization logic. But apparently it does. Barely possibly related missed-devirtualization bugs: #47316, #60674, #89924, #94243.
[Bug c++/98644] New: [concepts] ICE in satisfaction_value, at cp/constraint.cc:2825
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98644 Bug ID: 98644 Summary: [concepts] ICE in satisfaction_value, at cp/constraint.cc:2825 Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/qh1zos template concept Signed = bool(T(1)); static_assert(Signed); Compile with "-std=c++20": :2:28: internal compiler error: in satisfaction_value, at cp/constraint.cc:2825 2 | static_assert(Signed); |^ 0x1cc31d9 internal_error(char const*, ...) ???:0 0x6b25f7 fancy_abort(char const*, int, char const*) ???:0 0x7390d2 evaluate_concept_check(tree_node*, int) ???:0 0x7255f4 maybe_constant_value(tree_node*, tree_node*, bool) ???:0 0x97ffcd finish_static_assert(tree_node*, tree_node*, unsigned int, bool, bool) ???:0 Another very similar ICE, even though the stack trace is different: // https://godbolt.org/z/rPn6vd bool Signed = requires { requires bool((char *)1); }; :1:35: internal compiler error: in satisfaction_value, at cp/constraint.cc:2825 1 | bool Signed = requires { requires bool((char *)1); }; | ~^~~ 0x1cc31d9 internal_error(char const*, ...) ???:0 0x6b25f7 fancy_abort(char const*, int, char const*) ???:0 0x737597 tsubst_requires_expr(tree_node*, tree_node*, int, tree_node*) ???:0
[Bug c++/98639] GCC accepts cast from Base to Derived in C++20 mode
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98639 --- Comment #5 from Arthur O'Dwyer --- Meh, I guess this is just an unintended (but conforming) consequence of the shifting C++17/20 rules. Jonathan links to https://twitter.com/wakomeup/status/1274778577087627267 as another example: // https://godbolt.org/z/WWr9b8 Base b; const Derived& rd = b; // ill-formed forever, I hope const Derived& rd{b}; // ill-formed until '14, OK in '17 and later const Derived& rd(b); // ill-formed until '17, OK in '20 and later It remains _surprising_ that you can make a `Derived` out of a `Base` in the absence of a constructor... but that's just the new aggregate-paren-init rules at work. It remains _surprising_ that you can bind a `const Derived&` to a `Base&` without a cast... but that's just the interaction of lifetime extension with the new aggregate-init rules. I do think it'd be nice for GCC to give some sort of diagnostic here. But I guess it would have to be an opt-in diagnostic switch. And we already have that switch today; it's called `-std=c++17`. ;) So maybe there's really no way to improve the situation here at all, and this can be closed as NOTABUG.
[Bug c++/98639] New: GCC accepts cast from Base to Derived in C++20 mode
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98639 Bug ID: 98639 Summary: GCC accepts cast from Base to Derived in C++20 mode Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/96EEPa struct Base {}; struct Derived : Base {}; Derived t() { Base b; return Derived(b); } // https://godbolt.org/z/G4covG auto lam = [i=42]() { return i; }; struct Derived : decltype(lam) { bool is_derived() const { return true; } }; Derived t() { return Derived(lam); } I actually suspect that this behavior is related to C++20's paren-init for aggregates; it might even be conforming? But there's no way this behavior was *intentional.* A value of type Base shouldn't be castable to Derived. static_cast(b) is also accepted by GCC.
[Bug c++/97034] [11 Regression] ICE on C++20 code: gcc_assert failure in return type deduction (gcc/cp/pt.c:26984 in type_dependent_expression_p(tree_node*))
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97034 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #5 from Arthur O'Dwyer --- Is mine the same bug? Mine is also a regression (trunk crashes where GCC 10.2 had succeeded). // https://godbolt.org/z/Ysh6as struct C { void f(auto) noexcept; }; void C::f(auto) noexcept(C::x) {} Compile with -std=c++20: :3:29: error: 'x' is not a member of 'C' 3 | void C::f(auto) noexcept(C::x) {} | ^ :3:6: error: declaration of 'void C::f(auto:2)' has a different exception specifier 3 | void C::f(auto) noexcept(C::x) {} | ^ :2:17: note: from previous declaration 'void C::f(auto:1) noexcept' 2 | struct C { void f(auto) noexcept; }; | ^ :3:30: internal compiler error: in type_dependent_expression_p, at cp/pt.c:27166 3 | void C::f(auto) noexcept(C::x) {} | ^ 0x1cc31d9 internal_error(char const*, ...) ???:0 0x6b25f7 fancy_abort(char const*, int, char const*) ???:0 0x8ee70a type_dependent_expression_p(tree_node*) ???:0 0x137d4f3 walk_tree_1(tree_node**, tree_node* (*)(tree_node**, int*, void*), void*, hash_set >*, tree_node* (*)(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set >*)) ???:0 0x1381b55 walk_tree_without_duplicates_1(tree_node**, tree_node* (*)(tree_node**, int*, void*), void*, tree_node* (*)(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set >*)) ???:0 0x8ea937 instantiation_dependent_uneval_expression_p(tree_node*) ???:0 0x8f2198 instantiation_dependent_expression_p(tree_node*) ???:0 0x8f2216 uses_template_parms(tree_node*) ???:0 0x78ffe8 duplicate_decls(tree_node*, tree_node*, bool, bool) ???:0 0x79a2b6 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**) ???:0 0x79dda6 start_function(cp_decl_specifier_seq*, cp_declarator const*, tree_node*) ???:0 0x8d803d c_parse_file() ???:0 0xa54072 c_common_parse_file() ???:0
[Bug c++/98249] New: Improper ADL on the `arg` in `new (arg) T`
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98249 Bug ID: 98249 Summary: Improper ADL on the `arg` in `new (arg) T` Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/xavfej #include struct Incomplete; template struct Holder { T t; }; Holder *p; void test() { ::new (p) int; new (p) int; } In an "ADL call," the compiler needs to compute the associated types of `Holder`, which means it needs to complete that type in order to check for friend declarations. In a "non-ADL call" (such as a qualified call), the compiler does NOT need to complete `Holder`. Since completing `Holder` produces a hard error, we can detect the difference between an ADL and a non-ADL call. All other compilers use "non-ADL calls" for both `::new (p) int` and `new (p) int`: they don't attempt to complete the incomplete type. GCC uses "ADL calls" for both, which means it hard-errors on both lines. I'm not sure what the Standard has to say about this, but GCC disagrees with all of Clang/MSVC/ICC, so I think GCC ought to change. (Detected while testing libc++ patch https://reviews.llvm.org/D92884)
[Bug c++/98039] New: Member function template with dependent return type involving class's own name: wrong-mangling, accepts-invalid
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98039 Bug ID: 98039 Summary: Member function template with dependent return type involving class's own name: wrong-mangling, accepts-invalid Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/qq7196 struct S { template static void f(T); template static auto h(T t) -> decltype(S::f(t)); }; void test() { S::h(42); } Here, GCC trunk mangles `S::h` as `_ZN1S1hIiEEDTclsrS_1ffp_EET_`, but both Clang and ICC agree that the mangling should be `_ZN1S1hIiEEDTclsr1SE1ffp_EET_`. I naively assume that this indicates a bug in GCC's mangling. _ZN1S1hIiEEDTclsrS_1ffp_EET_ has "S_" where _ZN1S1hIiEEDTclsr1SE1ffp_EET_ has "1SE". It gets worse: If you make `f` non-static, then GCC accepts this code even though it is invalid. In that case, the mangled name of the `h` that is (wrongly) called is _ZN1S1hIiEEDTcldtdefpTsrS_1ffp_EET_ // https://godbolt.org/z/Kr1baT struct S { template void f(T); template static auto h(T t) -> decltype(S::f(t)); }; void test() { S::h(42); }
[Bug c++/97988] New: [C++20] Forward-declared class type declared inside requires-expression gives weird inconsistencies
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97988 Bug ID: 97988 Summary: [C++20] Forward-declared class type declared inside requires-expression gives weird inconsistencies Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/sxWY1f template concept C = requires (P ptr) { (struct D*)ptr; }; struct D {}; D d; Clang accepts. GCC rejects; GCC's error messages imply that GCC is sometimes treating `D` as a class template `template struct D` and sometimes treating it as a normal class type, as if its internal representation is inconsistent. :6:3: error: class template argument deduction failed: 6 | D d; | ^ :6:3: error: no matching function for call to 'D()' :3:40: note: candidate: 'template D()-> D' 3 | concept C = requires (P ptr) { (struct D*)ptr; }; |^ :3:40: note: template argument deduction/substitution failed: :6:3: note: couldn't deduce template parameter 'P' 6 | D d; | ^ :3:40: note: candidate: 'template D(D)-> D' 3 | concept C = requires (P ptr) { (struct D*)ptr; }; |^ :3:40: note: template argument deduction/substitution failed: :6:3: note: candidate expects 1 argument, 0 provided 6 | D d; | ^ I can also make GCC segfault by trying to use `D` as an NTTP, but I think that's essentially just a duplicate of #95159 #95291 #96123 #97749 etc., not necessarily related to the rejects-invalid bug described here. template concept C = requires (P ptr) { (struct D*)ptr; }; struct D { constexpr D(); }; template struct S {}; S<1> s;
[Bug c++/97883] New: [C++20] Segmentation fault on template with braced initializer list A<{}>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97883 Bug ID: 97883 Summary: [C++20] Segmentation fault on template with braced initializer list A<{}> Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/841ahx template struct A; A<{}> a; In -std=c++17 mode, this gives an error as expected. In -std=c++20 mode, this segfaults: :2:5: error: deducing from brace-enclosed initializer list requires '#include ' +++ |+#include 1 | template struct A; 2 | A<{}> a; | ^ :2:5: internal compiler error: Segmentation fault 0x1bf9b89 internal_error(char const*, ...) ???:0 0x8a5846 do_auto_deduction(tree_node*, tree_node*, tree_node*, int, auto_deduction_context, tree_node*, int) ???:0 0x8c48ac lookup_template_class(tree_node*, tree_node*, tree_node*, tree_node*, int, int) ???:0 0x9197cd finish_template_type(tree_node*, tree_node*, int) ???:0 0x87f57c c_parse_file() ???:0 0x9f7452 c_common_parse_file() ???:0 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. If you "#include ", you successfully suppress the first error message; but the segfault still happens in the same place. Might be related to #95291 or #97749. It's weird that this happens ONLY in C++20 mode, even though it uses nothing but C++17 features.
[Bug c++/97801] New: overload resolution ambiguity isn't detected when rvalue ref qualifier is involved
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97801 Bug ID: 97801 Summary: overload resolution ambiguity isn't detected when rvalue ref qualifier is involved Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/7onfa6 struct G { static int min(int=0) { return 1; } int min() && { return 2; } }; int x = G::min(); GCC accepts; Clang, MSVC, and ICC reject. GCC treats `G::min()` as an unambiguous call to the static member function. However, C++ seems to require that overload resolution reject this code as ambiguous -- it should be ambiguous between the two different G::min()s capable of taking zero arguments, *even though* the non-static one can't actually be called without a "this" argument. Strangely, this bug appears only when the non-static candidate is rvalue-ref-qualified (either "&&" or "const&&" or "volatile&&"). It does not appear with "&" or "const&" or "const", nor if the function is not ref-qualified.
[Bug c++/97716] New: Class's `operator delete`should be implicitly `noexcept`
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97716 Bug ID: 97716 Summary: Class's `operator delete`should be implicitly `noexcept` Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- #include #include struct S { void operator delete(void*); }; static_assert(std::is_same_v< decltype(S::operator delete), void(void*) noexcept >); Clang and ICC and MSVC accept this static_assert; GCC rejects. The wording controlling this is http://eel.is/c++draft/except.spec#10 : > A deallocation function with no explicit noexcept-specifier has a > non-throwing exception specification.
[Bug c++/86769] g++ destroys condition variable in for statement too early
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86769 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #3 from Arthur O'Dwyer --- Confirmed. https://godbolt.org/z/MfbrcG
[Bug c++/68003] Variable declared in condition in for loop is destroyed too soon
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68003 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #1 from Arthur O'Dwyer --- Confirmed. https://godbolt.org/z/MfbrcG https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86769 is a duplicate.
[Bug c++/93085] ICE in get_class_binding_direct and alias_ctad_tweaks, with C++20 NTTP + CTAD + alias template
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93085 --- Comment #3 from Arthur O'Dwyer --- Re comment 2: My original test code was "invalid-code", but here's one I believe to be "valid-code" in C++20. // https://godbolt.org/z/dqcWeq template class A> struct G { template using B = A; template static int foo(); template static int foo(); int x = foo<42>(); // OK }; test.cc:7:21: internal compiler error: in get_class_binding_direct, at cp/name-lookup.c:1238 7 | int x = foo<42>(); // OK | ^ If you change the `` to an ``, the ICE disappears, but GCC still gives a bogus error at template-definition time: // https://godbolt.org/z/Tjrnzv template class A> struct G { template using B = A; template static int foo();// #1 template static int foo(); // #2 int x = foo<42>(); // OK }; test.cc:7:21: error: call of overloaded 'foo()' is ambiguous 7 | int x = foo<42>(); // OK | ^ GCC shouldn't even be trying to resolve `foo<42>()` until `G` has been instantiated; and once `G` has been instantiated with some specific `A`, this call may or may not be ambiguous (depending on whether it's possible to deduce the template arguments to foo #1 or not).
[Bug c++/97096] New: ICE on invalid: in register_constexpr_fundef, on out-of-line-defaulted operator== or operator<=>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97096 Bug ID: 97096 Summary: ICE on invalid: in register_constexpr_fundef, on out-of-line-defaulted operator== or operator<=> Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/neqx1q cat >test.cpp <https://gcc.gnu.org/bugs/> for instructions. The same ICE happens if you replace both instances of `==` with `<=>`.
[Bug c++/95407] [DR 1873] G++ allows access to base class members from a friend of a derived class
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95407 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #1 from Arthur O'Dwyer --- According to Richard's comment on https://bugs.llvm.org/show_bug.cgi?id=46036 , http://cwg-issue-browser.herokuapp.com/cwg1873 indicates that Clang may be correct according to the Standard as written. HOWEVER... The "misbehavior" here isn't really about `friend`; it's about the interaction between `static` and `protected`. If you change your test case to make `value` non-static, then all vendors agree that the non-static `value` is inaccessible. With a static protected member (Clang rejects, GCC and MSVC accept): https://godbolt.org/z/essofs With a non-static protected member (all three correctly reject): https://godbolt.org/z/T1GWTP And here's a test case that doesn't use `friend` at all, but rather uses a private inheritance path, so that `C` is derived from `A`, but `C` itself is not aware of the fact. This case came up on Slack on 2020-08-14: https://cpplang.slack.com/archives/C5GN4SP41/p1597391677014800 With a static protected member (GCC and Clang accept, MSVC rejects): https://godbolt.org/z/6d786M With a non-static protected member (all three correctly reject): https://godbolt.org/z/MeTxeW // https://godbolt.org/z/6d786M struct A { protected: static int sf(); }; struct B : private A {}; struct C : public B { static void test(); }; void C::test() { &::A::sf; }
[Bug c++/96555] New: "template argument involves template parameter(s)" with dot or arrow operator in partial specialization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96555 Bug ID: 96555 Summary: "template argument involves template parameter(s)" with dot or arrow operator in partial specialization Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/Kc98ea struct A { int x; }; extern A a; template struct B {}; template struct B {}; :5:8: error: template argument '(int)sizeof (a.x)' involves template parameter(s) 5 | struct B {}; |^ GCC seems to have a problem only with expressions involving the dot operator (e.g. `sizeof(a.x)`) and the arrow operator (e.g. `sizeof(p->x)`), but not any other operators, which leads me to believe that the root cause here is related to the root cause of bug 96215. Grepbait: template argument involves template parameters Same error message in different situations, all involving partial specializations but none involving dot or arrow specifically: bug 67593, bug 83426, bug 90099
[Bug c++/96515] New: [concepts] Segfault on ill-formed pack expansions in requires-expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96515 Bug ID: 96515 Summary: [concepts] Segfault on ill-formed pack expansions in requires-expression Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/rafY6G template concept PackHasAdd = (requires(Args... args) { (args+1); } && ...); static_assert(PackHasAdd); int main() {} Compile with GCC trunk (11.0.0), "g++ -std=c++20": :7:31: internal compiler error: Segmentation fault 7 | static_assert(PackHasAdd); | ^ Please submit a full bug report, with preprocessed source if appropriate. See <https://gcc.gnu.org/bugs/> for instructions.
[Bug c++/96213] GCC doesn't complain about ill-formed non-dependent template default argument
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213 --- Comment #2 from Arthur O'Dwyer --- Here's a similar situation I just ran into again, somehow! // https://godbolt.org/z/3TKG1z struct S {}; template void f() {} template void g() {} int main() { f(); // correctly errors out g(); // incorrectly accepted by GCC } GCC is happy to treat `S(I)` as well-formed when `I` is a template parameter. Obviously `decltype(S(I), void())` can't be anything because `S(I)` is ill-formed, so I'm not sure what GCC is doing to compile this.
[Bug c++/96215] Wrong mangling for non-dependent return type involving decltype(g.x) or decltype(p->x)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96215 --- Comment #2 from Arthur O'Dwyer --- WG21's commentary on CWG 1273 (which is now http://cwg-issue-browser.herokuapp.com/cwg1172 ) seems completely bizarre to me. Sure, `decltype(g.x)` could theoretically refer to a private member of `g`; but so could `decltype(g+1)` or `decltype(*g)` or any other expression that might involve a private member. (In `g+1`, there might be a private member `S::operator+(int)`.) https://godbolt.org/z/ehd9fr GCC happily accepts template constexpr decltype (a.i) f() { return 1; } template constexpr decltype (b.i) f() { return 2; } as an overload set, but rejects template constexpr decltype (a+1) g() { return 3; } template constexpr decltype (b+1) g() { return 4; } and also rejects template constexpr decltype (::i, 0) h() { return 5; } template constexpr decltype (::i, 0) h() { return 6; } Clang sensibly rejects all three, all for the same reason. Normally I'd be all for GCC injecting some implementation divergence into this poorly specified area of the standard; but since this affects name-mangling and thus causes GCC to be unable to link against (hypothetical) code compiled with Clang and vice versa, I think it might be worth trying to reconcile. To be clear: This name-mangling issue doesn't affect any real-world codebase AFAIK. I discovered it purely by accident while messing around in Godbolt.
[Bug c++/96215] New: Wrong mangling for non-dependent return type involving decltype(g.x) or decltype(p->x)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96215 Bug ID: 96215 Summary: Wrong mangling for non-dependent return type involving decltype(g.x) or decltype(p->x) Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/z4rjjq struct S { int x; int operator*() const; }; extern const S g; extern const S *p; extern int S::*m; template decltype(g.x) foo() { return 0; } template decltype(p->x) bar() { return 0; } template int foo(); template int bar(); Clang mangles these instantiations as _Z3fooIiEiv _Z3barIiEiv GCC mangles them as _Z3fooIiEDtdtL_Z1gE1xEv _Z3barIiEDtptL_Z1pE1xEv Weirdly, GCC doesn't seem to have this issue with any other operators -- decltype(g+1), decltype(g.*m), etc. are all handled as synonyms for `int`. Only dot and arrow are handled as-if-they-were-dependent-even-though-they-aren't.
[Bug c++/39970] gcc accepts the . dot operator in template arguments
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39970 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #9 from Arthur O'Dwyer --- As of C++11, the original code is legitimate-ish: struct blah { int member; }; constexpr blah global = {42}; template class template_blah { }; template_blah<> x; // OK, param is 42 But: (1) GCC still incorrectly accepts the template even when `global` is non-const. So does MSVC. Clang correctly(?) rejects it. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213 might be related. (2) I don't understand Brandon's original concern around mangling operator dot. The value of the default argument here is just "42"; we don't have to mangle the dot at all. An example of name-mangling the dot operator would be like template decltype(T().x) foo() { return 0; } struct S { int x; }; template int foo(); which GCC correctly mangles as `_Z3fooI1SEDtdtcvT__E1xEv`. So I think the only remaining issue here is the incorrect acceptance of a non-const default argument for `int param`, and that part MIGHT duplicate bug #96213 which I just filed.
[Bug c++/87234] GCC should warn if template parameter redefines default argument
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87234 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #3 from Arthur O'Dwyer --- Duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50370
[Bug c++/82850] g++ permits redefinition of default arguments
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82850 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #5 from Arthur O'Dwyer --- Duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50370
[Bug c++/96213] New: GCC doesn't complain about ill-formed non-dependent template default argument
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213 Bug ID: 96213 Summary: GCC doesn't complain about ill-formed non-dependent template default argument Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- Possibly related (although these seem to complain about the opposite of what I'm complaining about): - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=12672 - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58071 // https://godbolt.org/z/EYzxx9 template int g; template(0,1,2)> void h() { } int main() { h<1>(); } MSVC and Clang both reject template `h` as ill-formed, because `g(0,1,2)` is nonsense -- `g` is an `int` and thus cannot be called like a function. GCC accepts template `h` as well-formed, and in fact will treat this as a SFINAE situation: template int g; template(42)> void h() {} // #1 template void h() {} // #2 int main() { h<>(); // unambiguously calls #2, because #1 has a deduction failure } My guess is that MSVC and Clang are closer to correct here.
[Bug c++/93295] ICE in alias_ctad_tweaks
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93295 Arthur O'Dwyer changed: What|Removed |Added CC||arthur.j.odwyer at gmail dot com --- Comment #6 from Arthur O'Dwyer --- Another test case from Peter O'Rourke on cpplang Slack: https://godbolt.org/z/YEw4v9 template struct A {}; template A() -> A<1>; template using B = A<2>; B bar;
[Bug c++/94376] New: When nested inside a lambda body, [=] captures by const value instead of by value
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94376 Bug ID: 94376 Summary: When nested inside a lambda body, [=] captures by const value instead of by value Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- David Blaikie, Richard Smith, and I discovered this GCC bug while tracking down a separate bug in llvm::function_ref whose constructor template was improperly SFINAEd so that construction from `const T&&` was done wrong. A GCC bug caused construction from `const T&&` to happen on GCC but not on Clang or EDG. Here's the reduced test case: // https://godbolt.org/z/oCvLpv #include #include struct I { I() { puts(__PRETTY_FUNCTION__); } I(I&) { puts(__PRETTY_FUNCTION__); } I(const I&) { puts(__PRETTY_FUNCTION__); } I(I&&) { puts(__PRETTY_FUNCTION__); } I(const I&&) { puts(__PRETTY_FUNCTION__); } void operator++() const {} }; int main() { I i; auto one = [=]() { return [=]() { ++i; }; }(); puts("-"); auto two = std::move(one); // !! } On the line marked "!!", one's implicitly generated move-constructor calls `I(const I&&)` rather than `I(I&&)` to move the captured copy of `i`. It does this because it has improperly decided that the type of the captured copy of `i` should be `const I` instead of plain old `I`. Richard Smith writes: > [expr.prim.lambda.capture]p10 is the relevant rule: > "The type of such a data member is the referenced type > if the entity is a reference to an object, an lvalue reference > to the referenced function type if the entity is a reference to a function, > or the type of the corresponding captured entity otherwise." > > Regardless of whether you think the captured entity is > the original variable or the member of the outer closure type, > the type of that entity is not const-qualified. > So the inner capture should not have a const-qualified type. Besides exposing bugs in llvm::function_ref (a good effect!), GCC's implementation divergence here could have the bad effect of causing additional expensive copies when lambdas with improperly const-qualified captures are moved around. Example: https://godbolt.org/z/LWEF47 Bug 86697 might be related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86697
[Bug c++/93503] New: Duplicated warning on pure virtual implicit template in C++2a
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93503 Bug ID: 93503 Summary: Duplicated warning on pure virtual implicit template in C++2a Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: arthur.j.odwyer at gmail dot com Target Milestone: --- // https://godbolt.org/z/FCqkWh template concept A = true; struct S { virtual int foo(A auto) = 0; }; g++ test.cc -std=c++2a test.cc:3:31: error: templates may not be 'virtual' 3 | virtual int foo(A auto) = 0; | ^ test.cc:3:17: error: implicit templates may not be 'virtual' 3 | virtual int foo(A auto) = 0; | ^~~ It is just a tiny bit suboptimal that the same warning appears twice. The issue seems to be something about the "=0"; a virtual function with ";" or "{}" or "=delete" does not give the same duplicated warning.
[Bug libstdc++/87106] Group move and destruction of the source, where possible, for speed
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87106 --- Comment #23 from Arthur O'Dwyer --- @Dan Stahlke: I believe https://stackoverflow.com/questions/47464819/uninitialized-copy-memcpy-memmove-optimization answers your question. Or, if it doesn't, then Marc or someone should consider posting an answer that's better than mine... and tell me whether I should delete my answer. :)