[Bug c++/115445] [15 Regression] [modules] ICE when repeating an export of function declared in GMF

2024-06-12 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-06-11 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-06-11 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-05-06 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-10 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-05 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-04-05 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-01-04 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-01-04 Thread m.cencora at gmail dot com via Gcc-bugs
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

2024-01-03 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-19 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-19 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-12-12 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-09-21 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-09-21 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-06-19 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-05-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-05-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-21 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-21 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-21 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-12 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-04-12 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-02-14 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-30 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-23 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-23 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-17 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-16 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-16 Thread m.cencora at gmail dot com via Gcc-bugs
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

2023-01-16 Thread m.cencora at gmail dot com via Gcc-bugs
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.

2023-01-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-12-19 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-12-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-09-08 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-08-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-06-30 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-06-30 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-06-09 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-05-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-05-26 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-05-13 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-04-13 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-04-13 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-04-13 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-04-13 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-02-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-02-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-02-18 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-02-03 Thread m.cencora at gmail dot com via Gcc-bugs
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

2022-01-25 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-12-06 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-11-25 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-10-06 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-10-02 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-04-29 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-04-29 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-04-29 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-04-29 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-04-29 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-02-22 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-02-22 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-02-22 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-02-22 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-01-12 Thread m.cencora at gmail dot com via Gcc-bugs
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

2021-01-11 Thread m.cencora at gmail dot com via Gcc-bugs
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

2020-12-03 Thread m.cencora at gmail dot com via Gcc-bugs
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

2020-12-03 Thread m.cencora at gmail dot com via Gcc-bugs
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

2020-12-03 Thread m.cencora at gmail dot com via Gcc-bugs
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

2020-12-03 Thread m.cencora at gmail dot com via Gcc-bugs
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, "");
}