[Bug c++/116534] New: [14 regression] internal compiler error with comparison of pointers calculated with array offset

2024-08-29 Thread john at drouhard dot dev via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116534

Bug ID: 116534
   Summary: [14 regression] internal compiler error with
comparison of pointers calculated with array offset
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: john at drouhard dot dev
  Target Milestone: ---

The following produces an internal compiler when compiled with -Wall starting
with gcc 14:


$ cat test.cpp
template 
class Test {
void foo(unsigned x, unsigned y) {
bool test = &a[x] == &b[y];
}
unsigned *a;
unsigned *b;
};



$ g++ -Wall ./test.cpp
./test.cpp: In member function 'void Test::foo(unsigned int, unsigned int)':
./test.cpp:4:34: internal compiler error: Segmentation fault
4 | bool test = &a[x] == &b[y];
  |  ^
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
See <https://gcc.gnu.org/bugs/> for instructions.

[Bug libstdc++/111050] [11/12/13/14 Regression] ABI break in _Hash_node_value_base since GCC 11

2023-09-12 Thread john at drouhard dot dev via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111050

John Drouhard  changed:

   What|Removed |Added

 CC||john at drouhard dot dev

--- Comment #10 from John Drouhard  ---
(In reply to frs.dumont from comment #9)
> To be honest before that report I thought that preserving abi was just a 
> matter of preserving memory layout of types. I had no idea that member 
> methods mattered !

(I was the original reporter of this to TC)

I think the specific issue here is that the member function `_M_valptr()`
returns the address of the storage data member, and that _function_ is used in
a construct call elsewhere to point to the address where a new object should be
placed. It returns the address based on the offset from the beginning of the
object which changed when the base class (which had its own data members) was
removed.

So, if the function isn't inlined, the symbol that's actually loaded by the
dynamic linker during runtime will return a potentially bogus address for that
data member if the definition of that function came from a library compiled
with the other version.

[Bug libstdc++/109111] Definition of repeat_view::_Iterator has wrong template-head

2023-03-13 Thread john at drouhard dot dev via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109111

--- Comment #1 from John Drouhard  ---
https://godbolt.org/z/csozden6e

example of gcc not diagnosing mismatched requires clauses (and clang correctly
doing so).

[Bug c++/101118] coroutines: unexpected ODR warning for coroutine frame type in LTO builds

2023-03-03 Thread john at drouhard dot dev via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101118

--- Comment #5 from John Drouhard  ---
Has there been any progress toward resolution for this? We've been trying to
use coroutines in our project but we require LTO for performance reasons, so
this is holding us back.

[Bug c++/93018] Zero initialization not occurring for empty struct in member union when converting constructor is used with -O2

2019-12-20 Thread john at drouhard dot dev
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93018

--- Comment #3 from John Drouhard  ---
I don't think this is a matter of object lifetime. Passing -fnolifetime-dse or
-flifetime-dse=1 does not change the generated assembly here at all.

As a user of the functions baz1 and baz2, I would expect the returned object to
have identical object representations. Bar's default constructor as well as its
user-defined constructor with the null_t argument should produce identical
objects here. Even if the copy constructor is used to copy from a temporary
object during the return from baz1/baz2, union class types' default copy
constructors copy the object representations (as if memmove is used), so we
should still be seeing a zero-initialized "foo" member.

The assembly generated with -O2, for reference:

baz1(long long):
xorl%eax, %eax
movl$0, %edx
testq   %rdi, %rdi
cmovg   %rdi, %rdx
setg%al
ret
baz2(long long):
xorl%eax, %eax
testq   %rdi, %rdi
jle .L7
movb$1, %al
movq%rdi, %rdx
.L7:
ret

%rax is the bool member of bar, %rdx is the union member. baz2 is simply not
storing anything in %rdx, so the caller receives an uninitialized value
(instead of zero-initialization) for the union "foo" member.

If I write the following program:

int main() {
Bar obj = baz2(0);
printf("%08x\n", *((long long*)&obj.foo));
return 0;
}

Random garbage is printed out. If I change it to use baz1 instead, 0 is
correctly printed. If I change the optimization level to -O3, 0 is correctly
printed. If I change the implementation of baz2(long long) to unconditionally
return the null sentinel object, 0 is correctly printed. "obj" is also
definitely still alive at this point in the program, so object lifetime is not
the problem.

It seems to only be uninitialized when using the converting constructor in the
return statement, using -O2 optimization, and there is another path in the
function that returns an object where the active union member is not the empty
struct and is initialized.

[Bug c++/93018] Zero initialization not occurring for empty struct in member union when converting constructor is used with -O2

2019-12-19 Thread john at drouhard dot dev
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93018

--- Comment #1 from John Drouhard  ---
I forgot to mention that changing the optimization level to -O3 appears to
"fix" baz2, and it correctly zero-initializes the empty struct in the union.

[Bug c++/92964] order of base class members generates vastly different code

2019-12-19 Thread john at drouhard dot dev
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92964

--- Comment #1 from John Drouhard  ---
I opened a separate bug report for the second issue I discussed in this one.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93018

[Bug c++/93018] New: Zero initialization not occurring for empty struct in member union when converting constructor is used with -O2

2019-12-19 Thread john at drouhard dot dev
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93018

Bug ID: 93018
   Summary: Zero initialization not occurring for empty struct in
member union when converting constructor is used with
-O2
   Product: gcc
   Version: 9.2.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: john at drouhard dot dev
  Target Milestone: ---

Created attachment 47528
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47528&action=edit
reproducible c++ source

When a converting constructor is used to return a struct that contains a bool
and a union with an instance of an empty struct as a member, the padding byte
for that empty struct member is not zero initialized. See the attached
reproducible. I've reproduced this on gcc 8.1-8.3, 9.2, and trunk (using
godbolt.org). Here's the godbolt link: https://godbolt.org/z/voL7B5

Compile with -std=c++17 -O2 -DEMPTY (which will use an empty struct in the
union). Omit -DEMPTY to see that naming the byte (thus making it part of the
value representation instead of the object representation) causes it to
correctly zero initialize. It also correctly zero initializes if the function
that returns the struct does so by returning a value-initialized Bar (baz1). In
baz2, a converting constructor from a null_t to Bar is used, though the same
behavior should occur as in baz1.

I believe zero initialization is required by the standard for the byte in the
empty struct. From the draft standard as of 2017-11-27:

=

6.6.2 paragraph 7: Unless it is a bit-field (12.2.4), a most derived object
shall have a nonzero size and shall occupy one or more bytes of storage. Base
class subobjects may have zero size. An object of trivially copyable or
standard-layout type (6.7) shall occupy contiguous bytes of storage.

6.7 paragraph 4: The object representation of an object of type T is the
sequence of N unsigned char objects taken up by the object of type T, where N
equals sizeof(T). The value representation of an object is the set of bits that
hold the value of type T. Bits in the object representation that are not part
of the value representation are padding bits.

11.6 paragraph 6: To zero-initialize an object or reference of type T means:
(6.2) — if T is a (possibly cv-qualified) non-union class type, its padding
bits (6.7) are initialized to zero bits and each non-static data member, each
non-virtual base class subobject, and, if the object is not a base class
subobject, each virtual base class subobject is zero-initialized;
(6.3) — if T is a (possibly cv-qualified) union type, its padding bits (6.7)
are initialized to zero bits and the object’s first non-static named data
member is zero-initialized;

11.6 paragraph 8: To value-initialize an object of type T means:
(8.1) — if T is a (possibly cv-qualified) class type (Clause 12) with either no
default constructor (15.1) or a default constructor that is user-provided or
deleted, then the object is default-initialized;
(8.2) — if T is a (possibly cv-qualified) class type without a user-provided or
deleted default constructor, then the object is zero-initialized and the
semantic constraints for default-initialization are checked, and if T has a
non-trivial default constructor, the object is default-initialized;
(8.3) — if T is an array type, then each element is value-initialized;
(8.4) — otherwise, the object is zero-initialized.

=

The empty "e" member in the "Foo" union is being value-initialized in the
member initializer list of the default constructor of Foo. Value-initialization
for an empty struct should cause zero-initialization of the padding bytes,
which is the single byte of the object representation for instances of an empty
struct. baz1 seems to do this correctly, baz2 does not.

[Bug c++/92964] New: order of base class members generates vastly different code

2019-12-16 Thread john at drouhard dot dev
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92964

Bug ID: 92964
   Summary: order of base class members generates vastly different
code
   Product: gcc
   Version: 9.2.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: john at drouhard dot dev
  Target Milestone: ---

Created attachment 47510
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47510&action=edit
reproducible c++ source

I'm new at submitting bug reports, sorry if this one is invalid.D

I have attached a repro file that actually exhibits what I believe to be two
issues, but I'm unsure of the second. If I need to open a second report for it
(or if it's really not a problem) just let me know. I've reproduced this
behavior on gcc 8.3, gcc 9.2, and gcc trunk.

Godbolt link if interested: https://godbolt.org/z/F756Pe

Anyway, looking at the generated assembly when compiling the program with
-std=c++17 -O2 (and -O3) seems to indicate a missed optimization of some kind.

bar1() and bar3() are equivalent, other than the order of the union and the
bool in the base storage class. I believe gcc should be able to generate
basically the same assembly as well (other than swapping %rax/%rdx), but bar3
utilizes the stack, even using SIMD instructions for the false branch. bar1
doesn't do this. clang generates equivalent code for bar1/bar3.

I'm assuming it has something to do with alignment, but what's strange is that
if the intermediary Payload class is bypassed by using a PayloadBase directly
in Foo<>, bar1 and bar3 are generated (almost) equivalently as expected (no
SIMD instructions or stack usage).



The other issue (please let me know if I should just open another report or if
this is expected), is the difference between bar1/bar2 and bar3/bar4. They only
differ in how they return the Foo<> object. bar1/bar3 return a default
constructed Foo<>, but bar2/bar4 return a sentinel and rely on converting to
Foo<> using the user-defined constructor. Generated assembly for these pairs of
functions are very different (at least at -O2 optimization).

With the -O2 level optimization, bar2 does not set %rdx in the false branch
(bar1 does). clang sets it in both. I realize it's not strictly necessary to
ensure that a value is returned in %rdx since the empty union member is the one
being initialized, but bar1 takes care to make sure it's set to 0 (as does
clang for both). Bumping the optimization level up to -O3 actually causes bar2
to ensure both are set to 0 explicitly.

bar3 and bar4, however, both intentionally populate %rax with uninitialized
junk from the stack in the false branch (both -O2 and -O3), though it's clearer
in bar4 since it doesn't use SIMD instructions there (related to the first
point?) If initializing %rax isn't necessary, why does it move memory from the
uninitialized stack into the return register at all?

I apologize if this is not well-thought-out or if there's something obvious I'm
missing. Let me know if you need me to provide any more information.