[Bug c++/115445] [15 Regression] [modules] ICE when repeating an export of function declared in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115445 --- Comment #1 from m.cencora at gmail dot com --- Works fine on gcc-14 and clang
[Bug c++/115446] New: [15 Regression] Segfault when exporting operator new
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115446 Bug ID: 115446 Summary: [15 Regression] Segfault when exporting operator new Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat op_new.cpp module; void* operator new(unsigned long, void*); namespace std { template auto construct_at(_Tp*) -> decltype(::new((void*)0) _Tp()) { return new _Tp(); } void use(int*p) { construct_at(p); } } export module std; export { using ::operator new; } $ g++ -Wno-global-module -fmodules-ts -std=c++2b -c op_new.cpp ' Segmentation fault 9 | auto construct_at(_Tp*) -> decltype(::new((void*)0) _Tp()) | ^ 0x26c45cc internal_error(char const*, ...) ???:0 0xc06a7a lookup_qualified_name(tree_node*, tree_node*, LOOK_want, bool) ???:0 0xa93fde build_operator_new_call(tree_node*, vec**, tree_node**, tree_node**, tree_node*, tree_node*, tree_node**, int) ???:0 0xb8c6f0 build_new(unsigned int, vec**, tree_node*, tree_node*, vec**, int, int) ???:0 0xcb2a28 tsubst(tree_node*, tree_node*, int, tree_node*) ???:0 0x26ed6c4 pp_format(pretty_printer*, text_info*, urlifier const*) ???:0 0x26f06a5 pp_verbatim(pretty_printer*, char const*, ...) ???:0 0x26c2e7a diagnostic_context::report_diagnostic(diagnostic_info*) ???:0 0x26c45cc internal_error(char const*, ...) ???:0 0x972a48 tree_check_failed(tree_node const*, char const*, int, char const*, ...) ???:0 0xbf6a6d name_lookup::add_overload(tree_node*) ???:0 0xbf6ce4 name_lookup::process_binding(tree_node*, tree_node*) ???:0 0xc00ce2 name_lookup::search_namespace(tree_node*) ???:0 0xc00de0 name_lookup::search_qualified(tree_node*, bool) ???:0 0xc06a70 lookup_qualified_name(tree_node*, tree_node*, LOOK_want, bool) ???:0 0xa93fde build_operator_new_call(tree_node*, vec**, tree_node**, tree_node**, tree_node*, tree_node*, tree_node**, int) ???:0 0xb8c6f0 build_new(unsigned int, vec**, tree_node*, tree_node*, vec**, int, int) ???:0 0xca6373 instantiate_decl(tree_node*, bool, bool) ???:0 0xcd08eb instantiate_pending_templates(int) ???:0 0xb690f0 c_parse_final_cleanups() ???:0 Works fine on gcc-14. Reduced from an implementation of "std" module: module; #include export module std; export { using ::operator new; }
[Bug c++/115445] New: [15 Regression] ICE when repeating an export of function declared in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115445 Bug ID: 115445 Summary: [15 Regression] ICE when repeating an export of function declared in GMF Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat repeated_using.cpp module; namespace std { void make_error_code(); } export module std; export namespace std { using std::make_error_code; using std::make_error_code; } $ g++ -Wno-global-module -fmodules-ts repeated_using.cpp :13:16: internal compiler error: tree check: expected overload, have function_decl in lookup_maybe_add, at cp/tree.cc:2533 13 | using std::make_error_code; |^~~ 0x26c45cc internal_error(char const*, ...) ???:0 0x972a48 tree_check_failed(tree_node const*, char const*, int, char const*, ...) ???:0 0xbf6a6d name_lookup::add_overload(tree_node*) ???:0 0xbf6ce4 name_lookup::process_binding(tree_node*, tree_node*) ???:0 0xc00ce2 name_lookup::search_namespace(tree_node*) ???:0 0xc00de0 name_lookup::search_qualified(tree_node*, bool) ???:0 0xc0654f finish_nonmember_using_decl(tree_node*, tree_node*) ???:0 0xc6eb8a c_parse_file() ???:0 0xdc51d9 c_common_parse_file() ???:0 This is a recent regression - didn't occur in 20250526 snapshot.
[Bug c++/114867] [modules] name lookup issues when a function overload set is exported from GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114867 --- Comment #1 from m.cencora at gmail dot com --- The unreduced code is actually a regression from gcc-12. @Jonathan Wakely: Could you maybe workaround it in libstdc++ by declaring the std::swap overload for exception_ptr in additional inline namespace in std, like this: namespace std { namespace __exception_ptr { class exception_ptr; void swap(exception_ptr& a, exception_ptr& b); } using __exception_ptr::exception_ptr; inline namespace __exception_ptr_swap { using __exception_ptr::swap; } }
[Bug c++/114685] [modules] ICE when exporting a type through a different alias then one declared in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114685 --- Comment #4 from m.cencora at gmail dot com --- I've stumbled upon a related error when trying to export std::vector after inclusion of in GMF: module; namespace std { class vector; namespace __format { using std::vector; } } export module std; export namespace std { #ifdef WORKAROUND namespace __format {} #endif using std::vector; }
[Bug c++/114868] New: [modules] func declared in GMF and exported via using-decl in module partition is not actually exported
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114868 Bug ID: 114868 Summary: [modules] func declared in GMF and exported via using-decl in module partition is not actually exported Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat mod.cpp export module mod; export import :part; export void foo() { } $ cat mod-part.cpp module; #include "bar.hpp" export module mod:part; export using ::bar; export void bar_non_gmf() { } $ cat usage.cpp import mod; int main() { foo(); bar(); bar_non_gmf(); } $ g++ -std=c++2b -fmodules-ts mod-part.cpp mod.cpp usage.cpp usage.cpp: In function ‘int main()’: usage.cpp:6:5: error: ‘bar’ was not declared in this scope 6 | bar(); | ^~~ When I compile mod-part.cpp on its own, it seems that bar symbol is not emitted in the object file: $ g++ -std=c++2b -fmodules-ts mod-part.cpp -c -o mod-part.o $ readelf -s mod-part.o | c++filt Symbol table '.symtab' contains 5 entries: Num:Value Size TypeBind Vis Ndx Name 0: 0 NOTYPE LOCAL DEFAULT UND 1: 0 FILELOCAL DEFAULT ABS mod-part.cpp 2: 0 SECTION LOCAL DEFAULT1 .text 3: 11 FUNCGLOBAL DEFAULT1 bar_non_gmf@mod() 4: 000b11 FUNCGLOBAL DEFAULT1 initializer for module mod:part
[Bug c++/114867] New: [modules] name lookup issues when a function overload set is exported from GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114867 Bug ID: 114867 Summary: [modules] name lookup issues when a function overload set is exported from GMF Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat future.cpp module; namespace std { template void swap(_Tp& a, _Tp& b); namespace __exception_ptr { class exception_ptr {}; void swap(exception_ptr&, exception_ptr&); } using __exception_ptr::swap; template < typename _Tp> struct shared_ptr { void swap(shared_ptr& other) { std::swap(_M_ptr, other._M_ptr); } _Tp *_M_ptr; }; struct future { shared_ptr< void > _M_state; void operator=(future& other) { _M_state.swap(other._M_state); } }; } // std export module std; namespace std { using std::swap; } $ g++ -std=c++2b -fmodules-ts -Wno-global-module future.cpp : In instantiation of 'void std::shared_ptr<_Tp>::swap(std::shared_ptr<_Tp>&) [with _Tp = void]': :23:48: required from here 23 | void operator=(future& other) { _M_state.swap(other._M_state); } | ~^~~~ :17:44: error: invalid initialization of reference of type 'std::__exception_ptr::exception_ptr&' from expression of type 'void*' 17 | void swap(shared_ptr& other) { std::swap(_M_ptr, other._M_ptr); } |^~ :10:11: note: in passing argument 1 of 'void std::__exception_ptr::swap(exception_ptr&, exception_ptr&)' 10 | void swap(exception_ptr&, exception_ptr&); | ^~ :27:8: warning: not writing module 'std' due to errors 27 | export module std; |^~ This is reduced code from an issue found when creating std module(https://gcc.gnu.org/PR114600#c10) module; #include export module std; export namespace std { using std::swap; } The problem seems to be that using __exception_ptr::swap; hides any other previous declaration of swap function. The workarounds is to move decl of template swap after the using __exception_ptr::swap; Also this compiles fine if we change shared_ptr::_M_ptr to not become a template dependent type.
[Bug c++/114685] [modules] ICE when exporting a type through a different alias then one declared in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114685 --- Comment #1 from m.cencora at gmail dot com --- Oops, the -isystem and -std options are not necessary for reproduction. This is enough: $ g++ -fmodules-ts lldiv_t.cpp
[Bug c++/114600] [14 Regression] [modules] redefinition errors when using certain std headers in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114600 m.cencora at gmail dot com changed: What|Removed |Added Attachment #57921|0 |1 is obsolete|| --- Comment #10 from m.cencora at gmail dot com --- Created attachment 57924 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=57924=edit Full "std' modules with workarounds Here is an improved version of "std" module, with workarounds for: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114683 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114685
[Bug c++/114600] [14 Regression] [modules] redefinition errors when using certain std headers in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114600 --- Comment #9 from m.cencora at gmail dot com --- (In reply to Jonathan Wakely from comment #8) > Thanks. I hope we'll end up auto-generating a file like that from > ../gcc/cp/cxxapi-data.csv Hmm, then that file will have to be extended because we need information about inline namespaces, e.g. std::literals::chrono_literals.
[Bug c++/114685] New: [modules] ICE when exporting a type through a different alias then one declared in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114685 Bug ID: 114685 Summary: [modules] ICE when exporting a type through a different alias then one declared in GMF Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat lldiv_t.cpp module; #include "lldiv_t.h" export module std; export namespace std { using ::__gnu_cxx::lldiv_t; } $ cat lldiv_t.h #pragma once struct lldiv_t{}; namespace __gnu_cxx { using ::lldiv_t; } namespace std { using ::lldiv_t; } $ g++ -std=gnu++2b -isystem $PWD -fmodules-ts lldiv_t.cpp lldiv_t.cpp:5:8: internal compiler error: in add_binding_entity, at cp/module.cc:12992 5 | export module std; |^~ 0x772540 depset::hash::add_binding_entity(tree_node*, WMB_Flags, void*) ../../src/gcc/cp/module.cc:12992 0x1049b77 walk_module_binding(tree_node*, bitmap_head*, bool (*)(tree_node*, WMB_Flags, void*), void*) ../../src/gcc/cp/name-lookup.cc:4224 0x1017341 depset::hash::add_namespace_entities(tree_node*, bitmap_head*) ../../src/gcc/cp/module.cc:13032 0x1031c89 module_state::write_begin(elf_out*, cpp_reader*, module_state_config&, unsigned int&) ../../src/gcc/cp/module.cc:17968 0x1033244 finish_module_processing(cpp_reader*) ../../src/gcc/cp/module.cc:20340 0xfbcbc1 c_parse_final_cleanups() ../../src/gcc/cp/decl2.cc:5354 0x120ef68 c_common_parse_file() ../../src/gcc/c-family/c-opts.cc:1329 Works fine on gcc-13. Reduced from an implementation of "std" module.
[Bug c++/114683] New: [modules] name declared in GMF in inline namespace and exported via using-decl from parent namespace is not visible to importer
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114683 Bug ID: 114683 Summary: [modules] name declared in GMF in inline namespace and exported via using-decl from parent namespace is not visible to importer Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat std.cpp module; #include "std.h" export module std; export namespace std { #ifdef WORKAROUND inline namespace __cxx11 { using std::__cxx11::basic_string; } #else using std::basic_string; #endif } $ cat std.h #pragma once namespace std { inline namespace __cxx11 { template struct basic_string{}; } } $ cat std_user.cpp import std; int main() { using std::basic_string; } $ g++ -std=c++2b -fmodules-ts std.cpp std_user.cpp std_user.cpp: In function ‘int main()’: std_user.cpp:5:12: error: ‘basic_string’ has not been declared in ‘std’ Works fine on clang. Reduced from standard library headers.
[Bug c++/114600] [14 Regression] [modules] redefinition errors when using certain std headers in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114600 --- Comment #7 from m.cencora at gmail dot com --- Created attachment 57921 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=57921=edit Full "std" module FYI if you want to stress test the modules impl w.r.t. similar issues, here is std.cpp for almost whole Standard Library. Some code is disabled (with 'bug' comment). This is based on semi-preprocessed and hand-adjusted 'std' module code from libc++
[Bug c++/114600] [modules] redefinition errors when using certain std headers in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114600 --- Comment #1 from m.cencora at gmail dot com --- gcc version info: g++-14 (Ubuntu 14-20240330-1ubuntu2) 14.0.1 20240330 (experimental) [master r14-9728-g6fc84f680d0] Copyright (C) 2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[Bug c++/114600] New: [modules] redefinition errors when using certain std headers in GMF
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114600 Bug ID: 114600 Summary: [modules] redefinition errors when using certain std headers in GMF Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- $ cat std.cpp module; #include export module std; $ cat main.cpp import std; #include int main() { } $ g++ -std=c++20 -fmodules-ts -c std.cpp $ g++ -std=c++20 -fmodules-ts main.cpp -o main In file included from main.cpp:3: /usr/include/c++/14/type_traits:89:36: error: template definition of non-template ‘constexpr const _Tp std::integral_constant<_Tp, __v>::value’ 89 | static constexpr _Tp value = __v; |^~~ /usr/include/c++/14/type_traits:90:29: error: template definition of non-template ‘using std::integral_constant<_Tp, __v>::value_type = _Tp’ 90 | using value_type = _Tp; | ^ /usr/include/c++/14/type_traits:91:47: error: template definition of non-template ‘using std::integral_constant<_Tp, __v>::type = struct std::integral_constant<_Tp, __v>’ 91 | using type = integral_constant<_Tp, __v>; | ^ /usr/include/c++/14/type_traits:92:45: error: template definition of non-template ‘constexpr std::integral_constant<_Tp, __v>::operator value_type() const’ 92 | constexpr operator value_type() const noexcept { return value; } | ^~~~ /usr/include/c++/14/type_traits:95:47: error: template definition of non-template ‘constexpr std::integral_constant<_Tp, __v>::value_type std::integral_constant<_Tp, __v>::operator()() const’ 95 | constexpr value_type operator()() const noexcept { return value; } | ^~~~ /usr/include/c++/14/type_traits:963:26: error: redefinition of default argument for ‘class _Up’ 963 | template | ^~~~ In file included from std.cpp:3, of module std, imported at main.cpp:1: /usr/include/c++/14/type_traits:963:26: note: original definition appeared here 963 | template | ^~~~ /usr/include/c++/14/type_traits:2470:10: error: redefinition of ‘template decltype (__declval<_Tp>(0)) std::declval()’ 2470 | auto declval() noexcept -> decltype(__declval<_Tp>(0)) | ^~~ /usr/include/c++/14/type_traits:2470:10: note: ‘template decltype (__declval<_Tp>(0)) std::declval@std()’ previously declared here === Seems like merging of GMFs does not work sometimes. Also if I create a preprocessed file for $ g++- -std=c++20 -fmodules-ts -x c++-system-header -E type_traits -o common.hpp and include this "common.hpp" instead of in both cpp files, then compilation succeeds. This works fine on gcc-13 (at least for header)
[Bug c++/113064] assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 --- Comment #11 from m.cencora at gmail dot com --- This is surprising to say the least because apparently for following code (where both conversion operators return same type) the compiler somehow correctly chooses && qualified overload: struct bar { bar() = default; bar(const bar&); bar(bar&&); bar& operator=(const bar&); bar& operator=(bar&&); }; struct foo { operator bar() const &; operator bar() &&; }; void test() { bar a = foo{}; // ok a = foo{}; foo f; a = f; // ok } So why cannot it apply the same overload resolution, when conversion operators return different type as in comment #4? Do you think this qualifies for a defect report?
[Bug c++/113219] Overloaded ref-qualified conversion operator triggers bogus -Wconversion
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113219 --- Comment #2 from m.cencora at gmail dot com --- So I guess this falls into the "confusing overload resolution for user-defined conversion" but I fail to see what can be confusing here. createInt() returns prvalue, so later it binds to xvalue for the purpose of implicit conversion operator invocation. That means that r-value qualified conversion operator is chosen. If your advice is to avoid using "-Wconversion" that it is rather unfortunate because user looses good warnings (e.g. about conversions that may alter the value). Also there is no way to silence the warning for such a code, since gcc warns on each call-site, not on definition-site of the overloads. So it either unfeasible or even impossible if the definitions are in library code, but warnings are enabled in user code. Please consider removing the warning generation in such scenarios.
[Bug c++/113219] New: Overloaded ref-qualified conversion operator triggers bogus -Wconversion
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113219 Bug ID: 113219 Summary: Overloaded ref-qualified conversion operator triggers bogus -Wconversion Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code when compiled on any gcc version (checked all available on godbolt since gcc-7) triggers conversion warnings. I consider it bogus because it tells user that it has chosen a better overload (which is good thing, right?). Clang doesn't print any related warning even with -Weverything g++ -std=c++17 -Wconversion template struct wrapper { operator T() const&; operator T&&() &&; }; wrapper createInt(); int test() { return createInt(); } Output is: :13:21: warning: choosing 'wrapper::operator T&&() && [with T = int]' over 'wrapper::operator T() const & [with T = int]' [-Wconversion] 13 | return createInt(); |~^~ :13:21: warning: for conversion from 'wrapper' to 'int' [-Wconversion] :13:21: note: because conversion sequence for the argument is better
[Bug c++/113064] assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 --- Comment #5 from m.cencora at gmail dot com --- (In reply to m.cencora from comment #4) > This also might be a just another symptom of the same root cause: This one is actually a regression (worked on gcc 8.3 and older)
[Bug c++/113064] assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 --- Comment #4 from m.cencora at gmail dot com --- This also might be a just another symptom of the same root cause: struct bar { bar() = default; bar(const bar&); bar(bar&&); bar& operator=(const bar&); bar& operator=(bar&&); }; struct foo { operator const bar& () const &; operator bar& () &; operator bar&&() &&; }; void test() { bar a = foo{}; // ok a = foo{}; // not ok - ambiguous call, but why? &&-qualified looks like a better match foo f; a = f; // ok a = static_cast(foo{}); // ok }
[Bug c++/113064] assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 --- Comment #2 from m.cencora at gmail dot com --- > When invoking the conversion operator the problem does not occur. When invoking the conversion operator *explicitly* the problem does not occur.
[Bug c++/113064] assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 --- Comment #1 from m.cencora at gmail dot com --- Fixed sample (a typo in else branch of WORKAROUND2): struct no_copy { no_copy() = default; no_copy(const no_copy&) = delete; no_copy(no_copy&&); no_copy& operator=(const no_copy&) = delete; no_copy& operator=(no_copy&&); }; struct foo { operator no_copy() & { return no_copy(); } #ifndef WORKAROUND1 operator no_copy&&() && = delete; #endif }; void test() { foo f; no_copy nc; #ifndef WORKAROUND2 nc = f; #else nc = f.operator no_copy(); #endif }
[Bug c++/113064] New: assignement from temporary sometimes invokes copy-assign instead of move-assign operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113064 Bug ID: 113064 Summary: assignement from temporary sometimes invokes copy-assign instead of move-assign operator Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code fails to compile on any gcc version with any selected language version. Works with clang. When invoking the conversion operator the problem does not occur. Also the mere existence of second overloaded conversion operator is problematic. Even though this conversion operator does not participate in overload resolution due to being && qualified. I marked it as deleted to show that this is not the overload being chosen by compiler but just declaring it normally is enough to trigger the bug. Compilation fails with error: : In function 'void test()': :31:10: error: use of deleted function 'no_copy& no_copy::operator=(const no_copy&)' 31 | nc = f; | ^ :9:14: note: declared here 9 | no_copy& operator=(const no_copy&) = delete; | ^~~~ Compiler returned: 1 // test.cpp struct no_copy { no_copy() = default; no_copy(const no_copy&) = delete; no_copy(no_copy&&); no_copy& operator=(const no_copy&) = delete; no_copy& operator=(no_copy&&); }; struct foo { operator no_copy() & { return no_copy(); } #ifndef WORKAROUND1 operator no_copy&&() && = delete; #endif }; void test() { foo f; no_copy nc; #ifndef WORKAROUND2 nc = f; #else nc = f.operator bar(); #endif }
[Bug c++/93259] Unsized temporary array initialization problem
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93259 --- Comment #7 from m.cencora at gmail dot com --- This seems to be fixed in gcc 12.3 and gcc 13+ Can we close this?
[Bug libstdc++/111511] Incorrect ADL in std::to_array in GCC 11/12/13
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111511 --- Comment #4 from m.cencora at gmail dot com --- Ack
[Bug libstdc++/111511] Incorrect ADL in std::to_array in GCC 11/12/13
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111511 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #2 from m.cencora at gmail dot com --- (In reply to Jonathan Wakely from comment #1) > (In reply to Jiang An from comment #0) > > Not sure whether this should be WONTFIX since the implementation is > > fundamentally changed in GCC 14 (PR 110167). > > There's no reason we can't fix the old version in the release branches. > > I did notice this when rewriting it, but I didn't think to change the > branches to avoid ADL there, because I plan to backport the new > implementation eventually anyway. On a semi-related topic: Can't we use __builtin_bit_cast as even simpler implementation of to_array for trivial types?
[Bug target/110303] With -O0, _mm_shuffle_epi32 with a constexpr function argument does not compile
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110303 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #6 from m.cencora at gmail dot com --- (In reply to Denis Yaroshevskiy from comment #4) > > so _mm_shuffle_epi32 requires a constant but since it is an argument, the > > argument, it is not a constant expression requirement. > > The function is marked constexpr. So it can be a constant if you ask it. constexpr at function declaration means that it COULD be evaluated in compile time, but doesn't force it. To force it either invoke it in a context that requires a compile-time evaluation (e.g. static_assert, or initializer of constexpr variable), or mark it as consteval instead.
[Bug ipa/109770] [10/11/12/13/14 Regression] wrong(?) devirtualization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109770 --- Comment #8 from m.cencora at gmail dot com --- (In reply to Richard Biener from comment #7) > > Ah, interesting. I was looking for an answer whether > > new T > > may produce anything other than an object with dynamic type T or if there > are any constraints on the object constructed. In particular C++20 11.10.4 > refered to by 6.7.3 doesn't mention whether re-using the storage is > permitted for an object under construction. It says usage is limited > and doesn't explicitely allow re-use so that might mean re-use is not > allowed. > > Note std::launder is C++17 only, the original reporter was using C++98 / > C++14 > > Reading C++20, 6.7.3/9, at least suggests that the placement new (this) A > in the CTOR invokes undefined behavior because the lifetime of B hasn't > ended (but 6.7.3/1.5 makes this ambiguous - we're re-using the storage here, > and also we're not talking about an object with automatic storage duration). 6.7.3/9 doesn't apply to your example - this is not an automatic storage duration. If 11.10.4 is suppose to be an exhaustive allow-list, then yeah ending the complete object lifetime during its construction is UB, but I guess it would be best to get a response from real C++ expert or file a C++ core issue.
[Bug ipa/109770] [10/11/12/13/14 Regression] wrong(?) devirtualization
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109770 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #6 from m.cencora at gmail dot com --- (In reply to Richard Biener from comment #0) > #include > > struct Base > { > virtual ~Base() {} > }; > struct A : Base > { > virtual ~A() {} > }; > struct B : Base > { > [[gnu::noinline]] B() { new (this) A; } > virtual ~B() { __builtin_abort (); } > }; > int main() > { > Base *p = new B; > delete p; > } > > aborts when compiled with -O2 (with devirtualization enabled). Neither > GCC nor clang diagnose the placement new in B::B() (but it looks fishy). I believe you need to std::launder the p pointer before calling delete: https://en.cppreference.com/w/cpp/utility/launder
[Bug c++/99637] bit_cast doesn't work with padding bits and it should
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99637 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #8 from m.cencora at gmail dot com --- I think that gcc is incorrect here, because the standard says: "Each bit of the value representation of the result is equal to the corresponding bit in the object representation of from." Padding bits are part of object representation, so if padding bits are properly initialized in source object (which is the case here), the values of padding bits should become a part of value representation of destination object. Also when reading the proposal p0476r2 it is clearly stated that bit_cast is suppose to be typesafe and constexpr-compatible alternative to memcpy (which by definition copies padding bits as is).
[Bug c++/108993] Value initialization does not occur for derived class , for gcc versions > 5
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108993 --- Comment #14 from m.cencora at gmail dot com --- Yeah, in CWG issue comments it is much more clear - but I cannot find such a wording in C++ latest draft. English is not my native language so this one is on me.
[Bug c++/108993] Value initialization does not occur for derived class , for gcc versions > 5
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108993 --- Comment #11 from m.cencora at gmail dot com --- Nvm, I understood this rule differently. You are saying that initialization is two step: - first zero-initialized, - then default-initialized. For me the way this rule is written is ambiguous.
[Bug c++/108993] Value initialization does not occur for derived class , for gcc versions > 5
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108993 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #10 from m.cencora at gmail dot com --- Does it really apply? Base constructor is user-provided hence non-trivial, hence Derived defaulted default constructor is non-trivial as well. Which means we end up in this clause: "and if T has a non-trivial default constructor, the object is default-initialized"
[Bug libstdc++/109482] experimental/net/internet/endpoint/cons.cc FAILs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109482 --- Comment #8 from m.cencora at gmail dot com --- Ah, I see that gcc doesn't support nested designated initializer in C++ mode (compared to C mode, or clang in both C and C++ modes).
[Bug libstdc++/109482] experimental/net/internet/endpoint/cons.cc FAILs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109482 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #4 from m.cencora at gmail dot com --- Can't you use designated initializer? https://godbolt.org/z/nWP7avK9x struct in_addr_t { void * dummy; }; struct in_addr { union { struct { char b[4]; }; in_addr_t s_addr; }; }; constexpr bool test() { in_addr a = {.s_addr = {}}; return a.s_addr.dummy == nullptr; } static_assert(test());
[Bug c++/108788] New: Lookup of injected class name should be type-dependent
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108788 Bug ID: 108788 Summary: Lookup of injected class name should be type-dependent Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code fails to compile on any gcc version. Works on all clang versions. It looks like inside template function get_templ_base the lookup of v.templ_base::a is done eagerly, and finds templ_base at the global scope, and hence errors out because the template parameters are missing. But at this point qualified name "templ_base::a" should be type-dependent, so lookup should be delayed until template instantiation, where 'templ_base' is an injected class name, so template paremeters shouldn't be required. g++ -std=c++11 struct base { int a = 1; }; template struct templ_base { int a = 2; }; namespace bar { struct base2 { int a = 3; }; template struct templ_base2 { int a = 4; }; } struct foo : base, bar::templ_base2, templ_base, bar::base2 { int base = 5; int templ_base = 6; int base2 = 7; int templ_base2 = 8; int a = 9; }; static_assert(foo{}.base::a == 1, ""); static_assert(foo{}.templ_base::a == 2, ""); static_assert(foo{}.base2::a == 3, ""); static_assert(foo{}.templ_base2::a == 4, ""); template int get_base(T&& v) { return v.base::a; } template int get_templ_base(T&& v) { return v.templ_base::a; // fails in all gcc versions } template int get_base2(T&& v) { return v.base2::a; // fails for gcc <= 11 } template int get_templ_base2(T&& v) { return v.templ_base2::a; // fails for gcc <= 11 } int a = get_base(foo{}); int b = get_templ_base(foo{}); int c = get_base2(foo{}); int d = get_templ_base2(foo{});
[Bug c++/108594] GCC ignores deleted movement constructor is not used on return
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108594 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #2 from m.cencora at gmail dot com --- This is not a dup of bug 93106. Since C++17 the function fA() doesn't perform move, since we have "mandatory copy/move elission" happening here.
[Bug c++/108506] bit_cast from 32-byte vector generates worse code than memcpy
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108506 --- Comment #1 from m.cencora at gmail dot com --- "that is the only difference between the two funcs" I mean that deserialize and deserialize2 differ only by the way they perform store from v32uc to output (bit_cast vs memcpy)
[Bug c++/108506] New: bit_cast from 32-byte vector generates worse code than memcpy
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108506 Bug ID: 108506 Summary: bit_cast from 32-byte vector generates worse code than memcpy Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Gcc trunk on x86-64 produces much worse assembly for 'deserialize' func than for equivalent 'deserialize2'. These two should be equivalent as bit_cast should be just a type-safe equivalent of memcpy (that is the only difference between the two funcs). g++ -std=c++23 -O3 -mavx2 using v32uc = unsigned char __attribute((vector_size(32))); constexpr auto N = 1024; struct Foo { int a[8]; }; static_assert(sizeof(Foo) == sizeof(v32uc)); void deserialize(const unsigned char* input, Foo* output) { for (auto i = 0u; i != N; ++i) { v32uc vec; __builtin_memcpy(, input, sizeof(vec)); input += sizeof(vec); vec = __builtin_shuffle(vec, v32uc{ 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 19, 18, 17, 16, 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28 } ); *output = __builtin_bit_cast(Foo, vec); output++; } } void deserialize2(const unsigned char* input, Foo* output) { for (auto i = 0u; i != N; ++i) { v32uc vec; __builtin_memcpy(, input, sizeof(vec)); input += sizeof(vec); vec = __builtin_shuffle(vec, v32uc{ 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 19, 18, 17, 16, 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28 } ); __builtin_memcpy(output, , sizeof(vec)); output++; } } Disassembly: deserialize(unsigned char const*, Foo*): push rbp xor eax, eax mov rbp, rsp and rsp, -32 vmovdqa ymm1, YMMWORD PTR .LC0[rip] .L2: vmovdqu ymm3, YMMWORD PTR [rdi+rax] vpshufb ymm2, ymm3, ymm1 vmovdqa YMMWORD PTR [rsp-32], ymm2 mov rdx, QWORD PTR [rsp-32] mov rcx, QWORD PTR [rsp-24] vmovdqa xmm4, XMMWORD PTR [rsp-16] vmovq xmm0, rdx vpinsrq xmm0, xmm0, rcx, 1 vmovdqu XMMWORD PTR [rsi+16+rax], xmm4 vmovdqu XMMWORD PTR [rsi+rax], xmm0 add rax, 32 cmp rax, 32768 jne .L2 vzeroupper leave ret deserialize2(unsigned char const*, Foo*): vmovdqa ymm1, YMMWORD PTR .LC0[rip] xor eax, eax .L7: vmovdqu ymm2, YMMWORD PTR [rdi+rax] vpshufb ymm0, ymm2, ymm1 vmovdqu YMMWORD PTR [rsi+rax], ymm0 add rax, 32 cmp rax, 32768 jne .L7 vzeroupper ret .LC0: .byte 3 .byte 2 .byte 1 .byte 0 .byte 7 .byte 6 .byte 5 .byte 4 .byte 11 .byte 10 .byte 9 .byte 8 .byte 15 .byte 14 .byte 13 .byte 12 .byte 3 .byte 2 .byte 1 .byte 0 .byte 7 .byte 6 .byte 5 .byte 4 .byte 11 .byte 10 .byte 9 .byte 8 .byte 15 .byte 14 .byte 13 .byte 12
[Bug c++/108417] [ICE] Crash on aggregate initialization of base class
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108417 --- Comment #7 from m.cencora at gmail dot com --- Hmm, ok. So if I wanted to workaround this in generic code, what kind of types should I exclude from aggregate initialization? Any type that has a base class with a tail padding? Or just the last direct base cannot have tail padding? Also ICE-ing is not very user friendly, maybe we could use move/copy-ctor anyway for such a non-trivial base (similarly to what clang does) or at least error-out with a nice message.
[Bug c++/108417] [ICE] Crash on aggregate initialization of base class
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108417 --- Comment #4 from m.cencora at gmail dot com --- (In reply to Andrew Pinski from comment #3) > I am 99% sure this is the same issue as pr98995 even though this is a crash. > The ice is the same as PR 93711. > > This code has both an abi issue against it filed and a c++ defect report > filed against it. I think this is a separate issue. Here the 'NonTrivial' class is copyable, so even if compiler cannot perform copy ellision (due to ABI or etc), it should be able to initialize the base object.
[Bug c++/108417] [ICE] Crash on aggregate initialization of base class
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108417 --- Comment #1 from m.cencora at gmail dot com --- The problem seems to occur if base class has a tail padding, and derived class is trying to reuse it to store its members
[Bug c++/108417] New: [ICE] Crash on aggregate initialization of base class
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108417 Bug ID: 108417 Summary: [ICE] Crash on aggregate initialization of base class Product: gcc Version: 10.4.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Code below compiled on any gcc<11 crashes with following output: during RTL pass: expand : In function 'Derived ICE_createDerived()': :37:5: internal compiler error: in assign_temp, at function.c:984 37 | }; | ^ FWIW it doesn't crash if field 'f3' is removed. g++ -std=c++17 struct NonTrivial { NonTrivial() = default; NonTrivial(const NonTrivial&); NonTrivial& operator=(const NonTrivial&); char* ptr = nullptr; }; struct Base { int f1; NonTrivial f2; int f3; }; struct Derived : Base { int f4; }; Derived createDerivedOk() { return Derived{ Base{}, 0 }; } Base createBase(); Derived ICE_createDerived() { return Derived{ createBase(), 0 }; }
[Bug middle-end/35560] Missing CSE/PRE for memory operations involved in virtual call.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35560 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #17 from m.cencora at gmail dot com --- It is (In reply to Richard Biener from comment #16) > (In reply to Witold Baryluk from comment #15) > > I know this is a pretty old bug, but I was exploring some assembly of gcc > > and clang on godbolt, and also stumbled into same issue. > > > > https://godbolt.org/z/qPzMhWse1 > > > > class A { > > public: > > virtual int f7(int x) const; > > }; > > > > int g(const A * const a, int x) { > > int r = 0; > > for (int i = 0; i < 1; i++) > > r += a->f7(x); > > return r; > > } > > > > (same happens without loop, when just calling a->f7 multiple times) > > > > > > > > g(A const*, int): > > pushr13 > > mov r13d, esi > > pushr12 > > xor r12d, r12d > > pushrbp > > mov rbp, rdi > > pushrbx > > mov ebx, 1 > > sub rsp, 8 > > .L2: > > mov rax, QWORD PTR [rbp+0] # a vtable deref > > mov esi, r13d > > mov rdi, rbp > > call[QWORD PTR [rax]]# f7 indirect call > > add r12d, eax > > dec ebx > > jne .L2 > > > > add rsp, 8 > > pop rbx > > pop rbp > > mov eax, r12d > > pop r12 > > pop r13 > > ret > > > > > > I was expecting mov rax, QWORD PTR [rbp+0] and call[QWORD PTR > > [rax]], to be hoisted out of the loop (call converted to lea, and call > > register). > > > > > > A bit sad. > > > > Is there some recent work done on this optimization? > > > > Are there at least some cases where it is valid to do CSE, or change code so > > it is moved out of the loop? > > GCC sees a->f() as possibly altering the virtual table [pointer] since > the function gets passed 'a' and thus a pointer to it (and *a is global > memory anyway, so GCC has to assume f() has access to it). > > In C++ probably there's probably no virtual function that could do this. > A virtual DTOR would leave an uninitialized object. Not sure if > > class A > { > virtual void f() { } > } > class B : A > { > virtual void f() { new A (this); } > } > > would be valid (maybe with first calling the DTOR on the existing object). It is valid, but to be able to use B object after B::f was invoked (and a new object is placed there instead), a user need to launder the pointer. https://en.cppreference.com/w/cpp/utility/launder
[Bug c++/108181] New: [missed optimization] Call to virtual function under runtime index should be optimized into jump with an offset
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108181 Bug ID: 108181 Summary: [missed optimization] Call to virtual function under runtime index should be optimized into jump with an offset Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Given code below compiled with g++ 11 or newer, compiler should be able to optimize 'get' into similar code as manually-optimized 'get_opt'. g++ -std=c++20 -O2 #include #include struct foo { virtual constexpr int& get0() noexcept = 0; virtual constexpr int& get1() noexcept = 0; virtual constexpr int& get2() noexcept = 0; virtual constexpr int& get3() noexcept = 0; virtual constexpr int& get4() noexcept = 0; virtual constexpr int& get5() noexcept = 0; virtual constexpr int& get6() noexcept = 0; virtual constexpr int& get7() noexcept = 0; virtual constexpr int& get8() noexcept = 0; virtual constexpr int& get9() noexcept = 0; }; template constexpr auto memPtr = nullptr; template constexpr auto memPtr = ::get0; template constexpr auto memPtr = ::get1; template constexpr auto memPtr = ::get2; template constexpr auto memPtr = ::get3; template constexpr auto memPtr = ::get4; template constexpr auto memPtr = ::get5; template constexpr auto memPtr = ::get6; template constexpr auto memPtr = ::get7; template constexpr auto memPtr = ::get8; template constexpr auto memPtr = ::get9; int& get(unsigned idx, foo* f) noexcept { switch (idx) { case 0: return (f->*memPtr)(); case 1: return (f->*memPtr)(); case 2: return (f->*memPtr)(); case 3: return (f->*memPtr)(); case 4: return (f->*memPtr)(); case 5: return (f->*memPtr)(); case 6: return (f->*memPtr)(); case 7: return (f->*memPtr)(); case 8: return (f->*memPtr)(); case 9: return (f->*memPtr)(); default: __builtin_unreachable(); } } int& get_opt(unsigned idx, foo* f) noexcept { // assuming System V x64 ABI struct RawMemPtr { std::uintptr_t v[2]; }; using PtrType = int& (foo::*)() noexcept; const RawMemPtr rawPtr{{sizeof(void*) * idx + 1, 0}}; const auto ptr = std::bit_cast(rawPtr); return (f->*ptr)(); }
[Bug libgcc/107675] [13 Regression] GCC-13 is significantly slower to startup on C++ statically linked programs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107675 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #14 from m.cencora at gmail dot com --- A comment to Thomas proposed patch "[PATCH] initialize fde objects lazily" You cannot use 'relaxed' atomic load in is_object_initialized - as thread performing such load will not observe/synchronize with any modifications (other than atomic variable itself) performed by other threads. Excerpt from cppreference: Relaxed operation: there are no synchronization or ordering constraints imposed on other reads or writes, only this operation's atomicity is guaranteed.
[Bug c++/106889] New: __builtin_strlen fails for some constexpr constructs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106889 Bug ID: 106889 Summary: __builtin_strlen fails for some constexpr constructs Product: gcc Version: 10.4.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Compiling following program on any gcc version, with C++14 or newer standard fails with "'__builtin_strlen(...)' is not a constant expression" for some of the static asserts. It compiles successfuly on clang. g++ -std=c++14 constexpr unsigned constexpr_strlen(const char* str) { #ifdef WORKAROUND if (!__builtin_constant_p(str)) { unsigned i = 0; while (str[i] != '\0') { ++i; } return i; } #endif return __builtin_strlen(str); } struct StaticString { constexpr StaticString(const char ()[4]) : buf{src[0], src[1], src[2], src[3]} {} constexpr const char* data() const { return [0]; } char buf[4]; }; constexpr StaticString createStaticString() { return {"foo"}; } constexpr const char *s1 = "foo"; constexpr const char s2[] = "foo"; constexpr StaticString s3{"foo"}; constexpr StaticString s4 = s2; constexpr StaticString s5 = s4; constexpr StaticString s6 = createStaticString(); void test() { constexpr const char *s7 = "foo"; constexpr const char s8[] = "foo"; constexpr StaticString s9{"foo"}; constexpr StaticString s10 = s8; constexpr StaticString s11 = s10; constexpr StaticString s12 = createStaticString(); static constexpr const char *s13 = "foo"; static constexpr const char s14[] = "foo"; static constexpr StaticString s15{"foo"}; static constexpr StaticString s16 = s14; static constexpr StaticString s17 = s6; static constexpr StaticString s18 = createStaticString(); static_assert(constexpr_strlen(s1) == 3, ""); static_assert(constexpr_strlen(s2) == 3, ""); static_assert(constexpr_strlen(s3.data()) == 3, ""); static_assert(constexpr_strlen(s4.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s5.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s6.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s7) == 3, ""); static_assert(constexpr_strlen(s8) == 3, ""); // ERROR static_assert(constexpr_strlen(s9.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s10.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s11.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s12.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s13) == 3, ""); static_assert(constexpr_strlen(s14) == 3, ""); static_assert(constexpr_strlen(s15.data()) == 3, ""); static_assert(constexpr_strlen(s16.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s17.data()) == 3, ""); // ERROR static_assert(constexpr_strlen(s18.data()) == 3, ""); // ERROR }
[Bug c++/106567] [13 Regression] An array with a dependent type and initializer-deduced bound is treated as an array of unknown bound when captured in a lambda
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106567 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #4 from m.cencora at gmail dot com --- Seems related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93259
[Bug c++/100157] Support `__type_pack_element` like Clang
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100157 --- Comment #5 from m.cencora at gmail dot com --- Yeah, __is_same builtin beats custom unique-id comparisons, but it is available only since gcc-10 so unavailable for me. Recently I discovered this one (only works for unique types), and it is twice as fast as __is_same in my scenarios (I guess mainly due to memoization): template struct indexed_type { unsigned idx; }; template struct indexed_type_list : indexed_type... { constexpr indexed_type_list(unsigned i = 0) : indexed_type{i++}... {} }; template constexpr indexed_type_list indexed_type_list_instance; template constexpr auto index_of = static_cast>(indexed_type_list_instance).idx; Anyway, thanks for working on this topic!
[Bug c++/100157] Support `__type_pack_element` like Clang
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100157 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #2 from m.cencora at gmail dot com --- Please consider also adding a builtin for fetching index of type in type list. While there are some easy implementations (like following), they are still not very performant. template constexpr auto uniqId() { return __PRETTY_FUNCTION__; } template constexpr unsigned index_of_impl(U needle, const U ()[N]) { for (unsigned i = 0u; i != N; ++i) { if (haystack[i] == needle) { return i; } } return -1; } template constexpr auto index_of_v = index_of_impl(uniqId, { uniqId...}); using T1 = float; using T2 = int; struct A; struct B; auto c = index_of_v;
[Bug c++/90254] [9 Regression] ice on aggregate initialization of unmovable base
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90254 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #13 from m.cencora at gmail dot com --- Slightly modified example still produces ICE on gcc-10.3 (works in gcc-11 and later) g++ -std=c++17 struct A { A(); A(const A &); }; struct B : A { }; A foo (); int main () { B{foo()}; }
[Bug c++/105737] [10/11 only] Incorrect evaluation order in new expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105737 --- Comment #3 from m.cencora at gmail dot com --- FWIW Ordered evaluation of elements in braced-init-list exists since C++11 (it was not a part of P0145).
[Bug c++/105737] New: Incorrect evaluation order in new expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105737 Bug ID: 105737 Summary: Incorrect evaluation order in new expression Product: gcc Version: 11.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following program when compiled with -std=c++17 prints 1243, while it should print 1234. All gcc < 12 versions are affected. #include struct MyStruct { }; struct MyTuple { int a; int b; MyStruct c; int d; }; int deserializeInt(const char*s) noexcept { std::puts(s); return 0; } MyStruct deserializeStruct(const char*s) noexcept { std::puts(s); return {}; } int main() { #if 0 // this disabled version works fine MyTuple a = { deserializeInt("1"), deserializeInt("2"), deserializeStruct("3"), deserializeInt("4") }; #else new MyTuple{ deserializeInt("1"), deserializeInt("2"), deserializeStruct("3"), deserializeInt("4") }; #endif } Similar bug exists when placement new is used. While this problem seems to be fixed in gcc 12, I have not found a bug report for such a fix, so it may have been fixed by accident, so it would be good to at least have a test case that this doesn't regress in future. But the best would be get this fixed in gcc9, 10 and 11.
[Bug sanitizer/105592] array out of bound not detected by ubsan
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105592 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #2 from m.cencora at gmail dot com --- While forming the pointer to 'one past the last' element is fine in C/C++, dereferencing it is not valid. And that is what is happening in 'return *b;' -fsanitizer=address correctly reports the problem for a1.c
[Bug c++/105260] Union with user-defined empty destructor leads to worse code-gen
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105260 --- Comment #6 from m.cencora at gmail dot com --- Furthermore in all the scenarios the same function is called, with same arguments, so the calling convention/ABI is same.
[Bug c++/105260] Union with user-defined empty destructor leads to worse code-gen
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105260 --- Comment #5 from m.cencora at gmail dot com --- I've slighlty refactored the code, to remove the auto variables. This issue remains #include inline unsigned deserializeUInt(const unsigned char* ) { unsigned out; __builtin_memcpy(, in, sizeof(out)); in += sizeof(out); out = __builtin_bswap32(out); return out; } struct Foo { unsigned a; unsigned b; static Foo deserialize(const unsigned char* ) { return Foo{ deserializeUInt(in), deserializeUInt(in) }; } }; struct Result { unsigned idx; union { unsigned a; const void* ptr; }; }; Result dummyFunc(Foo); void deserializeAndInvoke(const unsigned char* it) { #ifndef WORKAROUND union NoDestroy { ~NoDestroy() {} Foo value; }; NoDestroy un{ Foo::deserialize(it) }; dummyFunc(un.value); #elif WORKAROUND == 1 union NoDestroy { Foo value; }; NoDestroy un{ Foo::deserialize(it) }; dummyFunc(un.value); #elif WORKAROUND == 2 alignas(Foo) char rawStorage[sizeof(Foo)]; Foo* foo = new ([0]) Foo{ Foo::deserialize(it) }; dummyFunc(*foo); #endif }
[Bug c++/105260] Union with user-defined empty destructor leads to worse code-gen
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105260 --- Comment #4 from m.cencora at gmail dot com --- I dont think ABI is an issue here. The Foo variable is spilled into stack, and then reloaded back into RDI register before invoking dummyFunc. Also clang generates optimal code as can be seen here: https://godbolt.org/z/K6jWY9h3b
[Bug c++/105260] New: Union with user-defined empty destructor leads to worse code-gen
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105260 Bug ID: 105260 Summary: Union with user-defined empty destructor leads to worse code-gen Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code leads to unnecessary stack spill of deserialized Foo variable: g++ -std=c++17 -O2 #include inline unsigned deserializeUInt(const unsigned char* ) { unsigned out; __builtin_memcpy(, in, sizeof(out)); in += sizeof(out); out = __builtin_bswap32(out); return out; } struct Foo { unsigned a; unsigned b; static Foo deserialize(const unsigned char* ) { return Foo{ deserializeUInt(in), deserializeUInt(in) }; } }; struct Result { unsigned idx; union { unsigned a; const void* ptr; }; }; Result dummyFunc(Foo); void deserializeAndInvoke(const unsigned char* it) { #ifndef WORKAROUND union NoDestroy { ~NoDestroy() {} Foo value; }; NoDestroy un{ Foo::deserialize(it) }; auto& arg = un.value; #elif WORKAROUND == 1 union NoDestroy { Foo value; }; NoDestroy un{ Foo::deserialize(it) }; auto& arg = un.value; #elif WORKAROUND == 2 alignas(Foo) char rawStorage[sizeof(Foo)]; auto& arg = *new ([0]) Foo{ Foo::deserialize(it) }; #endif dummyFunc(arg); } deserializeAndInvoke(unsigned char const*): mov edx, DWORD PTR [rdi] mov eax, DWORD PTR [rdi+4] bswap edx bswap eax mov DWORD PTR [rsp-16], edx mov DWORD PTR [rsp-12], eax mov rdi, QWORD PTR [rsp-16] jmp dummyFunc(Foo) The spill can be avoided, when we remove user-defined destructor of NoDestroy union, or when we construct Foo via placement new in raw buffer. Generated code with either of the workarounds: g++ -std=c++17 -O2 -DWORKAROUND=1 or g++ -std=c++17 -O2 -DWORKAROUND=2 deserializeAndInvoke(unsigned char const*): mov rax, rdi mov edi, DWORD PTR [rdi] mov eax, DWORD PTR [rax+4] bswap edi mov edi, edi bswap eax sal rax, 32 or rdi, rax jmp dummyFunc(Foo)
[Bug c++/104597] LTO does not inline indirect call
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104597 --- Comment #2 from m.cencora at gmail dot com --- Similarly when indirect call is a result of virtual function call, gcc cannot optimize it, while clang can: // main.cpp struct foo { virtual int getInt0() const = 0; virtual int getInt1() const = 0; }; const foo& getFooInstance(); namespace { int test() { auto& foo = getFooInstance(); return foo.getInt1(); } } int main() { return test(); } // lib1.cpp struct foo { virtual int getInt0() const = 0; virtual int getInt1() const = 0; }; namespace { struct bar final : foo { int getInt0() const override { return 0; } int getInt1() const override { return 1; } }; constexpr bar b; } const foo& getFooInstance() { return b; } gcc-11 output: Dump of assembler code for function main: 0x1040 <+0>: endbr64 0x1044 <+4>: lea0x2d75(%rip),%rdi# 0x3dc0 <_ZN12_GLOBAL__N_1L1bE> 0x104b <+11>:jmp0x1150 <_ZNK12_GLOBAL__N_13bar7getInt1Ev> clang-12 output: Dump of assembler code for function main: 0x00401110 <+0>: mov$0x1,%eax 0x00401115 <+5>: ret
[Bug c++/104597] LTO does not inline indirect call
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104597 --- Comment #1 from m.cencora at gmail dot com --- clang-12 optimizes it to: Dump of assembler code for function main: 0x00401110 <+0>: mov$0x1,%eax 0x00401115 <+5>: ret
[Bug c++/104597] New: LTO does not inline indirect call
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104597 Bug ID: 104597 Summary: LTO does not inline indirect call Product: gcc Version: 11.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Given following files: // main.cpp using intfunc = int (*)(); intfunc getIntFunc(int i); namespace { int test() { auto func = getIntFunc(1); return func(); } } int main() { return test(); } // lib1.cpp namespace { int getInt0() { return 0; } int getInt1() { return 1; } int getInt2() { return 2; } } using intfunc = int (*)(); intfunc getIntFunc(int i) { if (i == 0) { return getInt0; } else if (i == 1) { return getInt1; } else if (i == 2) { return getInt2; } __builtin_abort(); } and compilation with: g++ -std=c++20 -Wall -Wextra -O3 -flto -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -Wl,-gc-sections main.cpp lib1.cpp -o test Call to getInt1 does not get inlined: Dump of assembler code for function main: 0x1040 <+0>: endbr64 0x1044 <+4>: jmp0x1140 <_ZN12_GLOBAL__N_17getInt1Ev>
[Bug c++/104302] [12 Regression] ICE Segmentation fault since r12-6825-g2da90ad39bf8fa9e
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104302 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #4 from m.cencora at gmail dot com --- FWIW sometimes array size deduction fails even if init-list is not dependent, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93259
[Bug c++/93740] Template base classes parametrized by pointer-to-member are amibiguous
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93740 --- Comment #5 from m.cencora at gmail dot com --- I think I was able to narrow it down to the true root cause. Following fails in all gcc versions that supports C++11 and newer: struct foo { void baz(); void bar(); }; static_assert(::baz != ::bar, ""); You may ask why I think so, because when we compile following code with -std=c++17 in gcc6.x, gcc7.x or gcc8.x: struct foo { void baz(); void bar(); }; constexpr auto foo_baz() { return ::baz; } constexpr auto foo_bar() { return ::bar; } template struct member_fun_ptr; using member_foo_baz = member_fun_ptr; using member_foo_bar = member_fun_ptr; we get following errors: :20:48: error: 'void (foo::*)(){foo::baz, 0}' is not a valid template argument for type 'void (foo::*)()' using member_foo_baz = member_fun_ptr; ^ :20:48: note: it must be a pointer-to-member of the form '::Y' :21:48: error: 'void (foo::*)(){foo::bar, 0}' is not a valid template argument for type 'void (foo::*)()' using member_foo_bar = member_fun_ptr; which indicates that both ::baz and ::bar both have value '0' in compile time, which is certainly not correct (and that is most likely why we get "ambiguous base class" error in the example from comment#1).
[Bug c++/103563] ostream operator<< resolved to variant containing type resulting in stack overflow
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103563 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #3 from m.cencora at gmail dot com --- This is a known issue with operators in C++ in general. That's why coding guidelines suggest that operators should be declared as hidden friends (to prevent unexpected implicit conversions). In your scenario you cannot make it a hidden friend, so constraint it with a concept or SFINAE: https://godbolt.org/z/de869vW6h
[Bug c++/93259] Unsized temporary array initialization problem
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93259 --- Comment #4 from m.cencora at gmail dot com --- This might be related to CWG2487 "Type dependence of function-style cast to incomplete array type"
[Bug libstdc++/93059] char and char8_t does not talk with each other with memcpy. std::copy std::copy_n, std::fill, std::fill_n, std::uninitialized_copy std::uninitialized_copy_n, std::fill, std::unin
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93059 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #48 from m.cencora at gmail dot com --- Any progress on this? I have stumbled upon same inefficiencies when writing serialization code that copies raw bytes to unsigned char* raw memory buffer from contiguous containers (string/vector/array) with elements of any 1 byte trivially copyable type (signed char, char, enum, UDT).
[Bug libstdc++/99327] ENOTSUP macro does not exist on djgpp crt
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99327 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #5 from m.cencora at gmail dot com --- code review comment: the change in file 'fs_ops.cc', func: 'fs::create_directory' to use 'function_function_not_supported' looks like a typo, isn't it?
[Bug libstdc++/100334] atomic::notify_one() sometimes wakes wrong thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100334 --- Comment #5 from m.cencora at gmail dot com --- Actually standard seems to require it - at least to my understanding of wait() description in in chapter 31.8.1: it explicitly states that waiting is performed in a loop, and loop is exited only if value has changed from old. So when we force notify_all for pooled waiters, then it may happen that a thread for which value didn't change from 'old' will be woken, so we must recheck the value.
[Bug libstdc++/100334] atomic::notify_one() sometimes wakes wrong thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100334 --- Comment #3 from m.cencora at gmail dot com --- If my analysis is correct then: - we need to force __all = true param in __waiter_pool_base::_M_notify, - protect from spurious wakeups in __waiter_pool::_M_do_wait by rechecking if the value has changed from old, if not then wait again
[Bug libstdc++/100334] atomic::notify_one() sometimes wakes wrong thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100334 --- Comment #2 from m.cencora at gmail dot com --- I have adapted the test to gcc trunk, but I am not entirely sure it is correct, because I don't have gcc trunk locally, I was just testing this on wandbox.org The problem is even bigger here, because it seems that besides wrong thread is woken up, also wrong std::atomic instance finishes the wait() call! #include #include #include #include #include #include void verify(bool cond, std::source_location loc = std::source_location::current()) { if (!cond) { std::cout << "Failed at line " << loc.line() << '\n'; //std::abort(); } } void emptyDeleter(void *) {} template struct atomics_sharing_same_waiter { std::atomic tmp[49 * 4] = {}; std::shared_ptr> a[4] = { { [0], emptyDeleter }, { [16 * 4], emptyDeleter }, { [32 * 4], emptyDeleter }, { [48 * 4], emptyDeleter } }; }; constexpr unsigned key(void * a) { constexpr uintptr_t __ct = 16; return (uintptr_t(a) >> 2) % __ct; } int main() { // all atomic share the same waiter atomics_sharing_same_waiter atomics; for (auto& atom : atomics.a) { atom->store(0); } std::cout << "atom0 " << atomics.a[0].get() << " key " << key(atomics.a[0].get()) << '\n'; std::cout << "atom1 " << atomics.a[1].get() << " key " << key(atomics.a[1].get()) << '\n'; std::cout << "atom2 " << atomics.a[2].get() << " key " << key(atomics.a[2].get()) << '\n'; std::cout << "atom3 " << atomics.a[3].get() << " key " << key(atomics.a[3].get()) << '\n'; verify(::__detail::__waiter_pool_base::_S_for(reinterpret_cast(atomics.a[0].get())) == ::__detail::__waiter_pool_base::_S_for(reinterpret_cast(atomics.a[1].get(; auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); }); auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); }); auto fut2 = std::async(std::launch::async, [&] { atomics.a[2]->wait(0); }); auto fut3 = std::async(std::launch::async, [&] { atomics.a[3]->wait(0); }); // make sure the all threads already await std::this_thread::sleep_for(std::chrono::milliseconds{100}); atomics.a[2]->store(1); atomics.a[2]->notify_one(); // changing to notify_all() doesn't help on gcc trunk verify(std::future_status::timeout == fut0.wait_for(std::chrono::milliseconds{100})); verify(atomics.a[0]->load() == 0); verify(std::future_status::timeout == fut1.wait_for(std::chrono::milliseconds{100})); verify(atomics.a[1]->load() == 0); verify(std::future_status::ready == fut2.wait_for(std::chrono::milliseconds{100})); verify(atomics.a[2]->load() == 1); verify(std::future_status::timeout == fut3.wait_for(std::chrono::milliseconds{100})); verify(atomics.a[3]->load() == 0); atomics.a[0]->store(1); atomics.a[0]->notify_one(); atomics.a[1]->store(1); atomics.a[1]->notify_one(); atomics.a[3]->store(1); atomics.a[3]->notify_one(); }
[Bug libstdc++/100334] atomic::notify_one() sometimes wakes wrong thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100334 --- Comment #1 from m.cencora at gmail dot com --- This test assumes previous waiter implementation (I used gcc-11 available from Ubuntu 21.04), latest atomic_wait impl has the same problem, it is just that waiter is selected in a different way, and create_atomics would have to be adjusted to accordingly (e.g. allocate 49 atomics in a single vector, and 0,16,32,48 instances should share same waiter instance).
[Bug libstdc++/100334] New: atomic::notify_one() sometimes wakes wrong thread
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100334 Bug ID: 100334 Summary: atomic::notify_one() sometimes wakes wrong thread Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- If waiter pool implementation is used in std::atomic::wait/notify for given T, then notify_one must underneath call notify_all to make sure that proper thread is awaken. I.e. if multiple threads call atomic::wait() on different atomic instances, but all of them share same waiter, then notify_one on only one of atomics will possibly wake the wrong thread. This can lead to program hangs, deadlocks, etc. Following test app reproduces the bug: g++-11 -std=c++20 -lpthread #include #include #include #include #include #include void verify(bool cond, std::source_location loc = std::source_location::current()) { if (!cond) { std::cout << "Failed at line " << loc.line() << '\n'; std::abort(); } } template struct atomics_sharing_same_waiter { std::unique_ptr> a[4]; }; unsigned get_waiter_key(void * ptr) { return std::_Hash_impl::hash(ptr) & 0xf; } template atomics_sharing_same_waiter create_atomics() { std::vector>> non_matching_atomics; atomics_sharing_same_waiter atomics; atomics.a[0] = std::make_unique>(0); auto key = get_waiter_key(atomics.a[0].get()); for (auto i = 1u; i < 4u; ++i) { while (true) { auto atom = std::make_unique>(0); if (get_waiter_key(atom.get()) == key) { atomics.a[i] = std::move(atom); break; } else { non_matching_atomics.push_back(std::move(atom)); } } } return atomics; } int main() { // all atomic share the same waiter auto atomics = create_atomics(); auto fut0 = std::async(std::launch::async, [&] { atomics.a[0]->wait(0); }); auto fut1 = std::async(std::launch::async, [&] { atomics.a[1]->wait(0); }); auto fut2 = std::async(std::launch::async, [&] { atomics.a[2]->wait(0); }); auto fut3 = std::async(std::launch::async, [&] { atomics.a[3]->wait(0); }); // make sure the all threads already await std::this_thread::sleep_for(std::chrono::milliseconds{100}); atomics.a[2]->store(1); atomics.a[2]->notify_one(); // changing to notify_all() allows this test to pass verify(std::future_status::timeout == fut0.wait_for(std::chrono::milliseconds{100})); verify(std::future_status::timeout == fut1.wait_for(std::chrono::milliseconds{100})); verify(std::future_status::ready == fut2.wait_for(std::chrono::milliseconds{100})); verify(std::future_status::timeout == fut3.wait_for(std::chrono::milliseconds{100})); atomics.a[0]->store(1); atomics.a[0]->notify_one(); atomics.a[1]->store(1); atomics.a[1]->notify_one(); atomics.a[3]->store(1); atomics.a[3]->notify_one(); }
[Bug c++/99185] asan initialization-order-fiasco false positive
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99185 --- Comment #8 from m.cencora at gmail dot com --- It does not matter whether A constructor is default or empty. If class instance cannot be constant-initialized then dynamic initialization will take place. I think gcc just incorrectly performs constant initialization in these scenarios. clang reports error as expected: struct A { int value; }; struct B { int value; B() = default; }; constinit A a; constinit B b;
[Bug c++/99185] asan initialization-order-fiasco false positive
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99185 --- Comment #6 from m.cencora at gmail dot com --- Now that I think about and having read relevant chapters of C++20 spec, observed behavior seems to be expected. A cannot be constant initialized (because it has missing initializer for 'value' member) so at first zero-initialization is performed as part of static initialization, then A constructor is called as part of dynamic initialization.
[Bug c++/99185] asan initialization-order-fiasco false positive
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99185 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #4 from m.cencora at gmail dot com --- I think it is just that sanitizer didn't caught up to the C++20 standard where constexpr was relaxed to allow uninitialized variables. Constant initialization is applied only when class constructor in constexpr, and only since C++20 'A' class has constexpr constructor. Proof, following compiles only since C++20: struct A { int value; constexpr A() = default; };
[Bug c++/99186] std::tuple compilation error when elements are specializations of template class declared with template < auto E > syntax with E being a enumerator of a enum
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99186 m.cencora at gmail dot com changed: What|Removed |Added CC||m.cencora at gmail dot com --- Comment #1 from m.cencora at gmail dot com --- This looks like a variation of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93740
[Bug c++/98637] New: Changing active union member via assignment expression should require trivial default constructor in constexpr context
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98637 Bug ID: 98637 Summary: Changing active union member via assignment expression should require trivial default constructor in constexpr context Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- According to http://eel.is/c++draft/class.union#general-6 following code should be rejected because changing of active union member via assignment expression should be allowed only for classes with non-deleted trivial default constructor. This is per Richard Smith's comment in https://bugs.llvm.org/show_bug.cgi?id=48453 g++ -std=c++20 #include struct NonTrivial { constexpr NonTrivial() : b(true) {} bool b; }; union Un { bool f1; NonTrivial f2; }; constexpr bool test() { Un un{ .f1 = false }; un.f2 = {}; // should be an error here, and require std::construct_at(); return un.f2.b; } static_assert(test());
[Bug c++/98620] New: SFINAE code in class specialization generate warnings
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98620 Bug ID: 98620 Summary: SFINAE code in class specialization generate warnings Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code compiled in any gcc>=5, C++11 or higher, and -Wmissing-field-initializers generate compiler warning: g++ -std=c++20 -Wmissing-field-initializers #include template struct TmpArray { T arr[1]; }; template struct is_non_narrowing_conversion : std::false_type {}; template struct is_non_narrowing_conversion< Src, Dst, decltype(void(TmpArray{{ std::declval() }})) > : std::true_type {}; struct mystruct { int a; void * b; }; void test_nok() { is_non_narrowing_conversion::type v; } SFINAE is used here only to detect if a code compiles, and code inside the decltype should not generate warnings. Also this is inconsistent, because when SFINAE is used in function template the warning is not generated: template auto is_non_narrowing_conversion_func_impl(Src&&, int) -> decltype((TmpArray{{ std::declval() }}, std::true_type{})); template auto is_non_narrowing_conversion_func_impl(Src&&, ...) -> std::false_type; template using is_non_narrowing_conversion_v2 = decltype(is_non_narrowing_conversion_func_impl(std::declval(), 0)); void test_ok() { is_non_narrowing_conversion_v2 v; }
[Bug c++/98122] New: [regression] Accessing union member through pointer-to-member is not a constant expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98122 Bug ID: 98122 Summary: [regression] Accessing union member through pointer-to-member is not a constant expression Product: gcc Version: 10.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following code does not compile on gcc-10 and newer in all std C++14-20 modes. This used to work in gcc-9 and earlier. union foo { int a; }; constexpr bool test() { foo f{ .a = 42 }; constexpr auto memPtr = ::a; return (f.*memPtr) == 42; } // error: accessing value of 'f' through a 'int' glvalue in a constant expression // return (f.*memPtr) == 42; static_assert(test(), "");
[Bug c++/93740] Template base classes parametrized by pointer-to-member are amibiguous
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93740 --- Comment #4 from m.cencora at gmail dot com --- I have done some more experiments, and it seems the problem applies to all pointer-to-member (not just pointer to member function, but also for pointer to data member). Also it doesn't matter if these pointer-to-members are all from same class or not, error is the same.
[Bug c++/93259] Unsized temporary array initialization problem
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93259 --- Comment #3 from m.cencora at gmail dot com --- Still fails on gcc 10.2 and trunk, in all std C++11-20 modes
[Bug c++/93740] Template base classes parametrized by pointer-to-member are amibiguous
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93740 --- Comment #3 from m.cencora at gmail dot com --- Still broken in gcc 10.2 and trunk, also in C++20 mode. The problem seems to show up only when address of member function (virtual or not) is passed as template parameter - only then gcc fails during overload resolution. For free functions this works fine. struct A { void foo(); void bar(); }; template struct indexed_elem{}; struct A_indexed_member_funcs : indexed_elem<0, ::foo>, indexed_elem<1, ::bar> {}; template constexpr int index_of(indexed_elem) { return N; } void foo(); void bar(); struct indexed_free_funcs : indexed_elem<0, >, indexed_elem<1, > {}; void test() { // this fails due to gcc claim of ambiguous base classes static_assert(index_of<::foo>(A_indexed_member_funcs{}) == 0, ""); // this is ok static_assert(index_of<>(indexed_free_funcs{}) == 0, ""); }