[Bug libstdc++/114817] Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type

2024-04-26 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817

--- Comment #3 from Arthur O'Dwyer  ---
https://github.com/boostorg/container/issues/153 , from 2020, is another
similar issue. There, boost::container::vector had assumed that if
__has_trivial_copy(T) and is_copy_constructible_v, then T could be relocated
via memcpy; but in fact __has_trivial_copy(T) is also true for move-only types.
So it was possible to create a type such that (__has_trivial_copy(T) &&
__is_constructible(T, T&)) and yet not __is_trivially_constructible(T, T&).

// https://godbolt.org/z/x5Wda1M6E
struct T {
template T(U&&);
T(T&&);
~T();
};
static_assert(__has_trivial_copy(T) && __is_constructible(T, T&));
  // ...and yet...
static_assert(not __is_trivially_constructible(T, T&));

[Bug libstdc++/114817] Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type

2024-04-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817

--- Comment #1 from Arthur O'Dwyer  ---
Yes, vector reallocation has analogous trouble with types that are "trivial,
but not trivially copy constructible."
https://godbolt.org/z/Psboqf3MP

(libc++ happens to sidestep this pitfall *on Clang 15+,* because libc++ gates
their vector reallocation optimization differently depending on whether
`__has_builtin(__is_trivially_relocatable)`; but libc++ would have the same bug
as libstdc++ when compiled on GCC.)

[Bug libstdc++/114817] New: Wrong codegen for std::copy of "trivially copyable but not trivially assignable" type

2024-04-22 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114817

Bug ID: 114817
   Summary: Wrong codegen for std::copy of "trivially copyable but
not trivially assignable" type
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

Jiang An raises an interesting issue over at
https://github.com/llvm/llvm-project/pull/89652#discussion_r1575540420
namely:

// https://godbolt.org/z/64KGP1avE
template
struct EvilPair {
T& first;
U& second;
EvilPair(T& t, U& u) : first(t), second(u) {}
EvilPair(const EvilPair&) = default;
void operator=(const volatile EvilPair&) = delete;
template EvilPair& operator=(const EvilPair& rhs) {
first = rhs.first;
second = rhs.second;
return *this;
}
};

static_assert(std::is_trivially_copyable_v>);

int main() {
int a[] = {1,2,3};
int b[] = {4,5,6};
int c[] = {0,0,0};
int d[] = {0,0,0};

EvilPair ps[] = {
{a[0], b[0]},
{a[1], b[1]},
{a[2], b[2]},
};
EvilPair qs[] = {
{c[0], d[0]},
{c[1], d[1]},
{c[2], d[2]},
};
std::copy(ps, ps+3, qs);
printf("%d %d %d\n", c[0], c[1], c[2]);
}

Here, EvilPair is trivially copyable, and also copy-assignable, but it is not
trivially copy-assignable. libstdc++'s std::copy assumes that any trivially
copyable type can be... well, trivially copied. So it copies the object
representation of EvilPair, instead of doing overload resolution to discover
that in fact the templated `operator=` should be called instead.

Looks like the std::copy optimization was introduced in the GCC 9 release.

Allegedly Microsoft STL's `std::pair` is isomorphic to `EvilPair`
these days.

libc++'s `std::copy` avoids this issue (AFAICT) by gating their optimization on
*both* is_trivially_assignable and is_trivially_copyable.

I suspect there will be similar issues with `uninitialized_foo` functions
and/or vector reallocation, for types that are trivially copyable (or trivially
relocatable!) and yet not trivially destructive-movable.

[Bug c++/114479] [14 Regression] std::is_array_v changed from false to true in GCC 14

2024-04-01 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114479

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #5 from Arthur O'Dwyer  ---
IIUC, the logic here goes as follows:

(1) Everyone's compiler extension currently makes this assertion fail, not
succeed:

  #include 
  template struct is_array : std::false_type {};
  template struct is_array : std::true_type {};
  template struct is_array : std::true_type {};
  static_assert(is_array::value, "this assert fails");

(2) Everyone's library is expected to implement `std::is_array` as the moral
equivalent of the partial specializations in (1). No reasonable library would
ever do anything else.

(3) Therefore, everyone's library will claim that int[0] is not an array type:
  static_assert(std::is_array::value, "this assert fails");

(4) The __is_array builtin is provided specifically to speed up std::is_array
(and for no other reason). Therefore, it should give the same answer as (3).
Therefore, __is_array(int[0]) should also report false:
  static_assert(__is_array(int[0]), "this assert fails");

This logic doesn't depend on any abstract reasoning about whether int[0] is
really "an array type" (I think it certainly *is* an array type, FWIW); it
simply depends on observing the extension's behavior in (1) -- and then *not*
claiming that that's a bug we need to fix. If the extension's behavior is
"correct" (i.e. we're not going to change it), then the behavior of
__is_array(T[0]) falls naturally out of that.

Personally, if I were designing the extension today, I would certainly make
T[0] match the partial specialization for T[N] (with N=0). This seems like it
would match users' expectations, and it doesn't seem to break any code that
wasn't already trying to use the extension, except for pathological party
tricks like being able to obfuscate the condition (N >= 1) as
(std::is_array_v). However, *if* the extension's behavior (1) is set in
stone, *then* conclusion (4) follows inexorably.

And since both (1) and (4) are core-language compiler issues, libstdc++ isn't
involved here: it's simply a bug for GCC to provide
partial-specialization-matching behavior as in (1) without also providing
__is_array behavior as in (4).

HOWEVER, here's a big question which I believe Aaron Ballman also raised on
llvm-project#54705: If it's not an array type, then where do we get off calling
it a compound type ( https://eel.is/c++draft/basic#compound-1 ), a literal type
( https://eel.is/c++draft/basic#types.general-10 ), an aggregate (
https://eel.is/c++draft/dcl.init.aggr#1 ), etc?

It certainly would be *simpler* -- if a big upheaval -- for GCC to provide
neither (1) nor (4), i.e. change the specialization-matching behavior to match
__is_array rather than the other way around. Then all the traits would give
consistent answers: int[0] would be a compound type, a literal type, and an
aggregate *because* it was an array type.

[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2

2024-02-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945

--- Comment #31 from Arthur O'Dwyer  ---
Oops, I guess my reading did disagree with jwakely's in one small point:
jwakely writes--
> But since one of the pointers is an invalid pointer,
> you can't do anything with its value anyway, including
> comparing it to 

In my interpretation, it was fine to compare `global == `; but the boolean
value of that comparison would be unspecified (because `*global` was
out-of-lifetime), and even if it *did* happen to come out to `true`, it would
still be UB to execute `global->i = 42` (because `*global` would still be a
different object from `w`, and `*global` is out-of-lifetime). I think this
makes no difference to the ultimate conclusion, i.e. something here ends up
being UB either way.

[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2

2024-02-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945

--- Comment #30 from Arthur O'Dwyer  ---
I think I understand jwakely's argument at this point, and it's consistent and
teachable. https://eel.is/c++draft/class.temporary#3.sentence-1 says:

> When an object of class type X is passed to or returned from a function, if X 
> has at least one eligible copy or move constructor, each such constructor is 
> trivial, and the destructor of X is either trivial or deleted, 
> implementations are permitted to create a temporary object to hold the 
> function parameter or result object.

It says "implementations are permitted"; this means that an implementation
(GCC) can create such a temporary *whenever* permitted, and then re-optimize
the codegen under the As-If Rule to eliminate the trivial move. That still ends
the lifetime of the original object. `global` points to that original object,
which is out-of-lifetime, so dereferencing `global` is UB. (Yes, even if its
value happens to _compare_ equal to some other pointer that's still
in-lifetime: this is "pointer provenance" as I see and understand it.)

So, in order for me to call this `Widget` example a "bug," I'd have to find a
`Widget` that doesn't meet [class.temporary]/3's conditions. That is, it would
have to be a type that does NOT have eligible copy or move constructors; or has
at least one NON-trivial eligible copy or move constructor; or has a
NON-deleted NON-trivial destructor. Then the implementation (GCC) would NOT be
permitted to create a temporary and the argument wouldn't hold anymore.

And indeed, I cannot find such a `Widget`! Every example I've tried so far
matches jwakely's explanation. For example: https://godbolt.org/z/rT6Mv537e

struct X {
X();
X(X&, int=0);
X(const X&) = default;
int i = 1;
int a[4];
};

This `X` has a non-trivial eligible copy constructor, so it doesn't meet
[class.temporary]/3's conditions, and GCC treats it the same at -O1 and -O2.
If you delete the characters `=0`, then that constructor is no longer a copy
constructor, so `X` DOES meet [class.temporary]/3 and GCC treats it differently
at -O1 and -O2 (which is fine because now the program has UB, as jwakely says).
GCC is not misbehaving in this example.

Here's another example (still matching jwakely's argument perfectly: GCC is not
misbehaving) -- this one exploits [special]/6 to play with whether the
non-trivial copy ctor is "eligible" -- https://godbolt.org/z/PWT85n5xb

I'm satisfied with the explanation -- and GCC seems to be implementing it
correctly AFAICT -- so I think it would be reasonable to close this bug as
INVALID. On the other hand, if anyone wants to argue that the current behavior
is technically correct but super confusing to working programmers, I wouldn't
argue against them, either. ;)

[Bug c++/113789] [13 Regression] ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter

2024-02-16 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789

--- Comment #10 from Arthur O'Dwyer  ---
FWIW, I think I agree with your analysis. To reiterate what you already said
(and I think GCC already gets the following snippet correct): in

  X g (X x) try {
throw x;
  } catch (...) {
return x;
  }

the `throw x` copies but the `return x` moves. That is, `throw x` treats `x` as
an lvalue because it could be used again later (in the function-catch-block),
but `return x` treats it as an rvalue because it can't[*] be used again later.

[* — except if you sneakily use a captured reference within a destructor, but
C++ implicit move doesn't care — has never cared — about such sneaky uses]

[Bug c++/113853] implicit move in throw in trailing return type

2024-02-10 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113853

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #1 from Arthur O'Dwyer  ---
(Sorry, not sure where's the best place to put this comment. Maybe nowhere. ;))
You probably know this already, but just in case anyone's not on the same page
yet:

https://eel.is/c++draft/except.throw#5
> When the thrown object is a class object, the constructor selected for the 
> copy-initialization *as well as the constructor selected for a 
> copy-initialization considering the thrown object as an lvalue* shall be 
> non-deleted and accessible, even if the copy/move operation is elided.

That paragraph is lurking in the background every time we talk about GCC's
handling of move-only exception objects. However, my impression is that the
paragraph is ignorable from the vendor's point of view:

- Even on paper, this "shall" is talking only about the runtime behavior "when
an exception _is_ thrown," so it doesn't change anything about the
well-formedness of _unevaluated_ throw-expressions.

- GCC+Clang _probably could_ conformingly decide that it should be ill-formed
to `throw x` when `x` is move-only; but that would break a lot of users, so
pragmatically they can't do that. GCC+Clang need a consistent theory of what it
means to throw a move-only type, and the theory can't possibly be "it's
ill-formed" (because that would break users), so the theory must agree with
Marek's test case: `throw t` ought to be well-formed in C++20-and-later (by
wording introduced to C++20 in P1155 a.k.a. P1825).

IOW, this bug and test case are *not* invalidated by [except.throw]/5. That's
all. :)

[Bug c++/113789] [13/14 Regression] ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter

2024-02-06 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789

--- Comment #6 from Arthur O'Dwyer  ---
(In reply to Marek Polacek from comment #5)
> IOW, this should be accepted in C++23 but isn't (clang++ accepts in C++23): 
> [...]

Correct, at least that's my intended interpretation. But the unexpected ICE was
more dramatic. :)
I'd be a tiny bit surprised if fixing `decltype(throw p)` actually closes the
only pathway to that ICE; but if it does, then awesome, I have no complaints.

[Bug c++/113789] New: ICE on P2266/C++23 `decltype(throw x)` where x is move-eligible parameter

2024-02-06 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113789

Bug ID: 113789
   Summary: ICE on P2266/C++23 `decltype(throw x)` where x is
move-eligible parameter
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

P2266 "Simpler Implicit Move", adopted for C++23, intends that a move-eligible
`x` should be treated as an xvalue in the context of `throw x`. This means that
`throw x` should be ill-formed (SFINAE-friendly) when `x` isn't
move-constructible.

(This might be complicated by the GCC+Clang extension that permits move-only
types to be thrown even though the paper Standard technically prohibits that.)

That is, the test program in this blog post is expected to pass after P2266:
https://quuxplusone.github.io/blog/2021/03/18/sfinae-on-throw-x/#here-is-a-program-that-uses-sfin
Clang passes; GCC fails; MSVC and EDG don't seem to implement P2266 `throw`
yet.

But the real problem for GCC is that if you then use `throw x` inside the
function body after using `decltype(throw x)` in the function's return type,
the compiler ICEs!


// https://godbolt.org/z/YG16hE7zT
struct AutoPtr {
AutoPtr() = default;
AutoPtr(AutoPtr&) {}
};
template auto f(T p, int) -> decltype(throw p, 1) { throw p; }
template int f(T p, long) { return 2; }
int main() {
return f(AutoPtr(), 42);
}


The expected behavior (and Clang's behavior) is to call `f(T, long)`. GCC 12
generates a call to `f(T, int)`. GCC 13 crashes with this output (including
that leading single-quote):
'
internal compiler error: error reporting routines re-entered.
0x2648345 diagnostic_context::report_diagnostic(diagnostic_info*)
???:0
0x26494c5 error_at(unsigned int, char const*, ...)
???:0
0xa7d834 build_new_method_call(tree_node*, tree_node*, vec**, tree_node*, int, tree_node**, int)
???:0
0xa7eb5b build_special_member_call(tree_node*, tree_node*, vec**, tree_node*, int, int)
???:0
0xb685e4 build_throw(unsigned int, tree_node*)
???:0
0xc95e47 tsubst(tree_node*, tree_node*, int, tree_node*)
???:0
0x267035c pp_format(pretty_printer*, text_info*, urlifier const*)
???:0
0x2673055 pp_verbatim(pretty_printer*, char const*, ...)
???:0
0x26481ca diagnostic_context::report_diagnostic(diagnostic_info*)
???:0
0x26494c5 error_at(unsigned int, char const*, ...)
???:0
0xa7d834 build_new_method_call(tree_node*, tree_node*, vec**, tree_node*, int, tree_node**, int)
???:0
0xa7eb5b build_special_member_call(tree_node*, tree_node*, vec**, tree_node*, int, int)
???:0
0xb685e4 build_throw(unsigned int, tree_node*)
???:0
0xc8b5c3 instantiate_decl(tree_node*, bool, bool)
???:0
0xcb56cb instantiate_pending_templates(int)
???:0
0xb54d39 c_parse_final_cleanups()
???:0
0xda8358 c_common_parse_file()
???:0

[Bug c++/113563] New: Rejects capture of `this` in C++23 `this auto` lambda

2024-01-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113563

Bug ID: 113563
   Summary: Rejects capture of `this` in C++23 `this auto` lambda
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/KWv8n6zEG
struct S {
  int x_;
  void f() {
[this](this auto) {
return this;
};
  }
};

GCC trunk complains:

:5:16: error: invalid use of 'this' in non-member function
5 | return this;
  |^~~~

The error also happens with
- [this](this auto&&) { return this; }
- [this](this auto) { return x; }
- [this](this auto) { f(); }
- [&](this auto) { return this; }
- [&](this auto) { return x; }
- [&](this auto) { f(); }

My understanding is that all of these lambdas should be well-formed, just as
long as the lambda's call operator is eventually instantiated (if it's ever
instantiated at all) with a type that satisfies [expr.prim.lambda.closure]/5,
i.e. is either the closure type itself or a class type derived from the closure
type.


Btw, I do like that GCC eagerly and SFINAE-friendlily rejects `[&](this T) {}`.
I hope fixing this bug doesn't require undoing that feature.
(By "SFINAE-friendly" I mean https://godbolt.org/z/fK4f13343 )
See also
https://quuxplusone.github.io/blog/2024/01/23/capturing-lambda-deducing-this/

[Bug c++/113541] New: Rejects __attribute__((section)) on explicit instantiation declaration of ctor/dtor

2024-01-22 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113541

Bug ID: 113541
   Summary: Rejects __attribute__((section)) on explicit
instantiation declaration of ctor/dtor
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/34Wdj1ox8

template
struct S {
S(int) {}
void operator=(int) {}
void f(int) {}
~S() {}
};
template __attribute__((section("TEST"))) S::S(int); // error
template __attribute__((section("TEST"))) void S::f(int); // OK
template __attribute__((section("TEST"))) void S::operator=(int); // OK
template __attribute__((section("TEST"))) S::~S(); // error

===

: In instantiation of 'S::S(int) [with T = int]':
:9:56:   required from here
:3:5: error: section of alias 'S::S(int) [with T = int]' must match
section of its target
3 | S(int) {}
  | ^

The problem seems to be only with the constructor and destructor, i.e., the two
kinds of functions that codegen two object-code definitions (base object xtor
and complete object xtor) for a single C++ declaration.

Somehow, giving `S` a virtual base class (`struct S : virtual B`) fixes the
problem. Then both codegenned xtors correctly wind up in the "TEST" section.

GCC 4.9.4 is happy with the code as written. The bug started happening with GCC
5.

(This was noted on Slack in June 2019, but never reported on Bugzilla AFAICT
until now: https://cpplang.slack.com/archives/C5GN4SP41/p1560800562026000 )

[Bug c++/113427] New: ICE: tree check: C++23 `this auto` lambda + multiple (ambiguous) inheritance from closure type

2024-01-16 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113427

Bug ID: 113427
   Summary: ICE: tree check: C++23 `this auto` lambda + multiple
(ambiguous) inheritance from closure type
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/fd3zzfrTd
auto factory(int x) {
return [x=x](this auto self) { return x; };
}
using Lambda = decltype(factory(0));
struct LeftCat : Lambda { LeftCat() : Lambda(factory(1)) {} };
struct RightCat : Lambda { RightCat() : Lambda(factory(2)) {} };
struct SiameseCat : LeftCat, RightCat { using Lambda::operator(); };
int main() {
return SiameseCat()();
}

===

: In instantiation of 'factory(int):: [with auto:1
= SiameseCat]':
:11:24:   required from here
   11 | return SiameseCat()();
  |^~
:3:32: error: 'factory(int)::' is an ambiguous
base of 'SiameseCat'
3 | return [x=x](this auto self) { return x; };
  |^
:3:32: error: 'factory(int)::' is an ambiguous
base of 'SiameseCat'
:3:32: internal compiler error: tree check: expected class 'type', have
'exceptional' (error_mark) in tsubst_decl, at cp/pt.cc:15542
0x264113c internal_error(char const*, ...)
???:0
0x9641cf tree_class_check_failed(tree_node const*, tree_code_class, char
const*, int, char const*)
???:0
0xa88c8c tree_class_check(tree_node*, tree_code_class, char const*, int, char
const*)
???:0
0xc88d63 instantiate_decl(tree_node*, bool, bool)
???:0
0xb4de55 maybe_instantiate_decl(tree_node*)
???:0
0xb4f948 mark_used(tree_node*, int)
???:0
0xa81a04 build_op_call(tree_node*, vec**, int)
???:0
0xcce9e7 finish_call_expr(tree_node*, vec**, bool,
bool, int)
???:0
0xc521ea c_parse_file()
???:0
0xda5b99 c_common_parse_file()
???:0
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

===

Found by noodling around with explicit object parameters and corner cases
related to https://eel.is/c++draft/expr.prim.lambda#closure-5 . That wording
currently demands that the explicit object parameter of a capturing lambda be
"a class type derived from the closure type," but it probably ought to say more
like "a class type _unambiguously_ derived from the closure type." At least, I
don't know what the expected behavior of the above program ought to be, if it's
_not_ supposed to be ill-formed. I think GCC's ICE happens because GCC is
trying too hard to assign a meaning to an essentially meaningless program.

[Bug c++/112555] New: NTTP of cv-qualified pointer type fails to mangle in those qualifiers

2023-11-15 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112555

Bug ID: 112555
   Summary: NTTP of cv-qualified pointer type fails to mangle in
those qualifiers
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/EGv36xzY6
template struct A;

template void foo();

int i;
int main() {
foo>();
foo>();
foo>();
foo>();
}

Clang mangles each call to `foo` differently:
  callq _Z3fooI1AILPi0EEEvv@PLT
  callq _Z3fooI1AILPKi0EEEvv@PLT
  callq _Z3fooI1AIXadL_Z1ivv@PLT
  callq _Z3fooI1AIXcvPKiadL_Z1ivv@PLT
GCC mangles the `int*` and `const int*` versions differently for nullptr, but
identically for ``. I think this is a GCC bug.
  call _Z3fooI1AILPi0EEEvv
  call _Z3fooI1AILPKi0EEEvv
  call _Z3fooI1AIXadL_Z1ivv
  call _Z3fooI1AIXadL_Z1ivv

NVC++ (EDG front-end) matches GCC, not Clang.
MSVC matches Clang, in that the `int*` and `const int*` versions are mangled
distinctly (but using MSVC ABI's mangling conventions of course).

Bug #107222 might be related but seems to be the opposite problem, if anything?

[Bug c++/102470] C++20 NTTP causes ICE

2023-11-15 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102470

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
Segfaults starting in GCC 9.1 (the first release with class NTTPs) until 12.3,
succeeds fine in GCC 13.1 and later.
Reduced: https://compiler-explorer.com/z/Kea5ar6MM

struct MA { int x; };
template constexpr int mao = 1;
template struct AST {};
template using AS = AST;
template using ASF = AS>;

: In substitution of 'template using AS = AST<((const MA)ma).x>
[with MA ma = mao]':
:5:39:   required from here
:4:32: internal compiler error: Segmentation fault
4 | template using AS = AST;
  |^~
0x1bbabfe internal_error(char const*, ...)
0x109f844 strip_array_types(tree_node*)
0x8d3f2c cp_type_quals(tree_node const*)
0x88e40f tsubst_template_args(tree_node*, tree_node*, int, tree_node*)
0x87b764 tsubst(tree_node*, tree_node*, int, tree_node*)
[...]

[Bug c++/99524] initializer_list storage considered a temporary when accessed through NTTP

2023-11-15 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99524

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #1 from Arthur O'Dwyer  ---
I don't see this as a bug (and indeed Clang/MSVC reject it too). It's okay to
use the address of `il` itself as the value of a template parameter, because we
know a mangleable name for that; but the address of the first element of the
backing array isn't a valid value for a template parameter, because the backing
array is anonymous — it hasn't got a mangleable name — in the
very-new-like-as-of-last-week Standardese, it's a "potentially non-unique
object." The same rejection applies to this example employing a string literal
(the other kind of "potentially non-unique object") in the Standard
post-CWG2753):

constexpr const char *il = "hello world";
template constexpr bool front = true;
static_assert(front<>); // OK
static_assert(front<[0]>);  // Reject

So I think this is not-a-bug.

[Bug c++/112471] New: catch handler of type "reference to array" should be unreachable, but is reached

2023-11-09 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112471

Bug ID: 112471
   Summary: catch handler of type "reference to array" should be
unreachable, but is reached
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/W9P6GrG4x
#include 
int main() {
try {
throw nullptr;
} catch (const int(&)[2]) {
puts("caught int(&)[2]");
} catch (const int*) {
puts("caught int*");
}
}

The correct output is "caught int*", because nullptr is not an array.
Clang and EDG produce the correct output.
MSVC is so confident that you can't throw an array (I think they're right!)
that it diagnoses the `catch` at -W4:

// https://godbolt.org/z/v6M1e5ff5
warning C4843: 'const int (&)[2]': An exception handler of reference to array
or function type is unreachable, use 'const int *' instead

GCC also mishandles unreachable catch handlers of type "reference to function":
again the correct output is "caught int*", Clang/EDG/MSVC all get it right, and
MSVC diagnoses.

// https://godbolt.org/z/sqoW6cPTn
try {
throw nullptr;
} catch (int(&)()) {
puts("caught int(&)()");
} catch (const int*) {
puts("caught int*");
}

[Bug c++/112436] New: SFINAE-unfriendly error on throwing pointer to incomplete type

2023-11-07 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112436

Bug ID: 112436
   Summary: SFINAE-unfriendly error on throwing pointer to
incomplete type
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---


template
concept Throwable = requires { throw T(); };
struct Incomplete;

static_assert(!Throwable);
static_assert(!Throwable);


:2:32: error: invalid use of incomplete type 'struct Incomplete'
2 | concept Throwable = requires { throw T(); };
  |^
:3:8: note: forward declaration of 'struct Incomplete'
3 | struct Incomplete;
  |^~
:2:32: error: invalid use of array with unspecified bounds
2 | concept Throwable = requires { throw T(); };
  |^

Instead of a hard error in both cases, we expect the concept to be false and
the static_assert to succeed. Clang and EDG succeed. MSVC succeeds on
`Incomplete*` and incorrectly permits throwing `int(*)[]`.

The terse/multi-purpose "invalid use of..." error message seems to come up a
lot in Bugzilla, but I didn't see any search hits for that message plus the
word "throw".

Bug #98388 is probably related.

[Bug c++/94039] conditional operator fails to use proper overload

2023-10-07 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94039

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #3 from Arthur O'Dwyer  ---
You can also hit this with a lambda, which of course is isomorphic to Andre's
test case:

void (*a)() = true ? []{} : nullptr;

Bug #88458 ("GCC rejects (true ? 0 : nullptr)") might be tangentially related.

[Bug libstdc++/111351] constexpr std::string objects permitted to escape constant evaluation when SSO

2023-09-12 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111351

--- Comment #6 from Arthur O'Dwyer  ---
(In reply to James Y Knight from comment #5)
> > Does using __builtin_is_constant_p on the union member not work?
> 
> I've created a proof-of-concept patch for libc++ to support SSO strings
> during constant evaluation. It works.
> 
> If everyone disagrees with me and believes that this is a really awesome
> foot-gun to give to users, I will go ahead and propose that patch to libc++
> maintainers. (As mentioned, that'll cause more code to be compilable under
> libc++ than is possible to permit under libstdc++/MSVC implementations).

FWIW #1: Personally I would be weakly in favor of that patch, but I would also
be pessimistic about its chances of getting accepted in the current libc++
climate.

FWIW #2: A worst-of-both-worlds option ;) would be for your patch to `if
consteval` the SSO buffer size so that it would be 24 at runtime (matching
libc++'s current behavior) but 16 at compile time (matching libstdc++ and
Microsoft if I'm not mistaken, so you'd get your cross-vendor portability at
compile time). *I* would still consider that an unnecessary-and-thus-bad
crippling of libc++ string's cool 24-byte-SSO feature; but I could imagine
someone else finding it more palatable than any other alternative. 
["Worst-of-both-worlds" in the sense that you're paying to change the code at
all, but the end result still has two codepaths that both need to be
maintained, and divergence between compile-time and runtime SSO behavior.]

[Bug libstdc++/111351] constexpr std::string objects permitted to escape constant evaluation when SSO

2023-09-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111351

--- Comment #1 from Arthur O'Dwyer  ---
(Author of the blog post here.)
In contrast to James' view, I think the libstdc++/MSVC behavior is relatively
easy to explain; I think libc++'s `if consteval` approach is baroque and
confusing. [That is, _both_ behaviors are confusing to the newbie and need
expert explanation, but libc++'s choice is confusing even for the experts, who
have to maintain its split-brain SSO logic forever because Hyrum's Law. If you
have to maintain something forever, you should at least choose to make it
_simple_! As I say in the blog post, in hindsight I think libc++ screwed up
here.]

IMHO it is a feature, not a bug, that I can write these lines:

constinit std::string s1;
constinit std::vector v1;

libstdc++ would be within its rights, paper-Standard-wise, to reject both of
these lines; but I don't think libstdc++ _should_ reject either of them.
They're both fine code as far as I'm concerned. I think libc++ is the
user-hostile/broken implementation here, not libstdc++.

Anyone who thinks libstdc++ ought to reject `s1` above should at least be
forced to explain what libstdc++ ought to do about `v1`. From the
user-programmer's POV, there's no difference between a default-initialized
string and a default-initialized vector. Users don't care about these SSO
details; they just want the code to work. That's what libstdc++ currently does.
Good, IMO.

[Bug c++/86646] Special member function 'cannot be defaulted' if type alias is used

2023-08-18 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86646

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #4 from Arthur O'Dwyer  ---
I just ran into this (it's one of the examples of vendor divergence in
P2953R0).
https://isocpp.org/files/papers/P2953R0.html#corner-cases

  // https://godbolt.org/z/sxv5rvn8o
  template
  struct C {
C& operator=(std::add_lvalue_reference_t) = default;
  };
  C cl;

GCC 13 says:

error: 'C<  >& C< 
>::operator=(std::add_lvalue_reference_t >
>)' cannot be defaulted
5 |   C& operator=(std::add_lvalue_reference_t) = default;
  |^~~

I confirm Andrew's observation that Clang is the odd one out in accepting this
code (GCC, MSVC, EDG all reject). But it also seems pretty obvious that it
should be accepted. Brian Bi concurs: "I couldn't figure out any reason why
this shouldn't be valid."

Or again something like this:

  template
  struct C {
C(std::conditional_t) = default;
C(std::conditional_t);
  };
  static_assert(std::is_trivially_copy_constructible_v>);
  static_assert(std::is_trivially_move_constructible_v>);

GCC+EDG+MSVC reject; Clang accepts; and I think Clang is the conforming one.

A related situation is

  // https://godbolt.org/z/1bhEx1Gr1
  template
  struct C {
template using A = const C&;
C(A...) = default;
  // this is a default ctor or a copy ctor, depending on sizeof...(Ts)
  };
  static_assert(std::is_trivially_constructible_v>);
  static_assert(std::is_trivially_copy_constructible_v>);

GCC rejects; Clang+EDG+MSVC accept; and I think Clang+EDG+MSVC are conforming.

[Bug libstdc++/106611] std::is_nothrow_copy_constructible returns wrong result

2023-08-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106611

--- Comment #13 from Arthur O'Dwyer  ---
(In reply to Andrew Pinski from comment #12)
> I suspect this is a dup of bug 100470 then.

Yep, I agree. My previous comment was a longwinded version of jwakely's
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100470#c1 :)

[Bug libstdc++/106611] std::is_nothrow_copy_constructible returns wrong result

2023-08-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106611

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #11 from Arthur O'Dwyer  ---
Jiang An wrote:
> I've mailed the LWG Chair to submit an LWG issue that requests clarification 
> of "is known not to throw any exceptions".
> FYI, there's at least one library implementor holding the same opinion as 
> yours.
> https://quuxplusone.github.io/blog/2023/04/17/noexcept-false-equals-default/

Quuxplusone here. :) I don't think this is LWG jurisdiction at all. This isn't
even a bug in libstdc++'s . This is purely a GCC core-language
bug. GCC's builtin __is_nothrow_constructible(T, T&&) simply returns the wrong
answer when the selected constructor is "trivial, but noexcept(false)."

// https://godbolt.org/z/5szW6KeWq
struct C {
  C(C&&) noexcept(false) = default;
};
static_assert(!__is_nothrow_constructible(C, C&&));
  // GCC+EDG fail; Clang+MSVC succeed

Notice that the builtin returns the correct answer when the selected
constructor is "non-trivial, noexcept(false), but still defaulted so we know it
can't throw." The problem is specifically with *trivial* ctors.

@jwakely, I propose that this issue should be recategorized as a compiler bug.
(And I'm also voting effectively "NAD" on LWG3967.)

[Bug c++/94162] ICE [neg] bad return type in defaulted <=>

2023-08-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94162

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #15 from Arthur O'Dwyer  ---
The test case in #c10 seems to be fixed since GCC 12; the rest were fixed since
GCC 11. Should this bug be RESOLVED FIXED at this point?
https://godbolt.org/z/d16x181xh

[Bug c++/101943] ICE: Segmentation fault (in cat_tag_for)

2023-08-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101943

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #4 from Arthur O'Dwyer  ---
This seems to be fixed since GCC 11.1; should it be RESOLVED FIXED at this
point?
https://godbolt.org/z/Tox8f716q

[Bug c++/110948] New: Incorrect -Winvalid-constexpr on virtual defaulted operator==

2023-08-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110948

Bug ID: 110948
   Summary: Incorrect -Winvalid-constexpr on virtual defaulted
operator==
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Keywords: diagnostic
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

Bug #98712 seems related.

// https://godbolt.org/z/eKKxcovEn
struct D;
struct B {
bool operator==(const B&) const;
virtual bool operator==(const D&) const;
};
struct D : B {
bool operator==(const D&) const override = default;
};

GCC alone gives this bogus -Winvalid-constexpr warning:

: In member function 'virtual constexpr bool D::operator==(const D&)
const':
:10:10: warning: call to non-'constexpr' function 'bool
B::operator==(const B&) const' [-Winvalid-constexpr]
   10 | bool operator==(const D&) const override = default;
  |  ^~~~
:5:10: note: 'bool B::operator==(const B&) const' declared here
5 | bool operator==(const B&) const;
  |  ^~~~

This is obviously contrived code, but the symptom might indicate that GCC is
too eager to pretend that the user actually wrote `constexpr`, in situations
where the compiler is merely supposed to make an implicitly defined function
constexpr-friendly if possible.

The AFAICT-analogous situation with `operator=` instead of `operator==`
correctly compiles without warning: https://godbolt.org/z/Mof1qaadr

[Bug libstdc++/110917] std::format_to(int*, ...) fails to compile because of _S_make_span

2023-08-07 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110917

--- Comment #2 from Arthur O'Dwyer  ---
> Alternatively, we could replace the contiguous_iterator<_OutIter> constraint 
> with constructible_from, _OutIter, iter_difference_t<_OutIter>>.

I think `is_same` is preferable to `constructible_from<...>` just because it's
simpler; I wouldn't recommend the hairier thing unless there was a known reason
for it. Doing the hairier thing would immediately trigger a search for the
corner case where it would fail. ;)  (Suppose the author of _OutIter arranges
that sentinel_for — maybe that'd do the trick...)


Btw, even though my reduced test case was contrived, it originates from an
actually realistic use-case AFAIK: using `format` to format ASCII text
automatically into an array of char16_t or char32_t (presumably on a platform
with unsigned plain char).

[Bug libstdc++/110917] New: std::format_to(int*, ...) fails to compile because of _S_make_span

2023-08-05 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110917

Bug ID: 110917
   Summary: std::format_to(int*, ...) fails to compile because of
_S_make_span
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Keywords: rejects-valid
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/9onGvqfha
#include 
#include 
#include 

void f(std::list::iterator it) {
std::format_to(it, "");  // OK
}
void g(std::vector::iterator it) {
std::format_to(it, "");  // boom!
}

libc++ and Microsoft are both completely happy with this code. libstdc++ is
happy with `f` but unhappy with `g`. I suspect that someplace is accepting
"contiguous iterators of any old T" when it means to limit itself to
"contiguous iterators of char" specifically.


In file included from :1:
.../include/c++/14.0.0/format:2609:36: error: cannot initialize a parameter of
type 'char *' with an rvalue of type 'int *'
 2609 |   : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n,
_M_buf)),
  |^~
.../include/c++/14.0.0/format:3641:32: note: in instantiation of member
function 'std::__format::_Iter_sink>>::_Iter_sink' requested here
 3641 |   _Iter_sink<_CharT, _Out> __sink(std::move(__out));
  |^
.../include/c++/14.0.0/format:3683:24: note: in instantiation of function
template specialization
'std::__format::__do_vformat_to<__gnu_cxx::__normal_iterator>, char,
std::basic_format_context, char>>' requested
here
 3683 | { return __format::__do_vformat_to(std::move(__out), __fmt,
__args); }
  |^
.../include/c++/14.0.0/format:3778:19: note: in instantiation of function
template specialization 'std::vformat_to<__gnu_cxx::__normal_iterator>>' requested here
 3778 |   return std::vformat_to(std::move(__out), __fmt.get(),
  |   ^
:9:10: note: in instantiation of function template specialization
'std::format_to<__gnu_cxx::__normal_iterator>>'
requested here
9 | std::format_to(it, "");
  |  ^
.../include/c++/14.0.0/format:2574:28: note: passing argument to parameter
'__ptr' here
 2574 |   _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n,
  |^
1 error generated.

[Bug libstdc++/70472] is_copy_constructible>>::value is true

2023-07-24 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70472

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #14 from Arthur O'Dwyer  ---
> The problem is that std::vector does have a copy constructor, so the trait 
> value is true, but instantiating that constructor produces an error when the 
> value_type is not copyable.

Worse, the value_type can be incomplete, as in

struct Node {
  std::vector children_;
};

Askar: see
https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/
I suggest closing this bug report as Not A Bug. It certainly shouldn't be
tagged `wrong-code`.

[Bug c++/110102] [13 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type

2023-06-10 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102

--- Comment #9 from Arthur O'Dwyer  ---
(In reply to Jason Merrill from comment #8)
> (In reply to Arthur O'Dwyer from comment #6)
> > I still think it would be nice if GCC stopped supporting
> > int f(std::vector v) { return v[0]; }
> > , at least silently by default.
> 
> Fixed (to require -fconcepts-ts) on trunk.

Nice! Thank you!

[Bug c++/110102] [13/14 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type

2023-06-05 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102

--- Comment #6 from Arthur O'Dwyer  ---
(In reply to Jason Merrill from comment #5)
> (In reply to Arthur O'Dwyer from comment #4)
> > My first, reduced, example, where `std::list v = {1,2,3}` is accepted for
> > move-only type `A`, is 100% a bug and should be fixed. But that is easy to
> > fix.
> 
> It's pedantically a bug, but only because of the suboptimal specified
> initializer_list semantics.  Just looking at that line I expect a list of As
> initialized from integers [...] It's also unfortunate that initialization 
> from a prvalue initializer_list can't use A's move constructor.

Yes, but since you just implemented P2752, you know why we can't do *that*. :)

I strongly disagree that this is [only] "pedantically" a bug. The behavior of
std::initializer_list is super fundamental to "Intro C++". If GCC continues
with this behavior, I guarantee there will be tons of newbies asking (me, other
instructors, StackOverflow, etc) "If initializer lists are so immutable, then
why does this code compile? You told me it wouldn't!"

Before C++20, I got tons of the same question for GCC's acceptance of
int f(auto x) { return x; }
I still think it would be nice if GCC stopped supporting
int f(std::vector v) { return v[0]; }
, at least silently by default.

Similarly here: I wouldn't actually mind if GCC supported
std::vector> v = { f, g, h };
with an on-by-default warning. It's that it accepts the extension *silently*,
and the extension is *so visible to newbies* and *so critical to their
understanding of the actual language*, that has me worried.

Here's a sketch of the `vector` example:
https://godbolt.org/z/dPnfbnhsf

[Bug c++/110102] [13/14 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type

2023-06-04 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102

--- Comment #4 from Arthur O'Dwyer  ---
I came across the `Widget` bug in the course of writing (and it's now mentioned
in) this blog post on value semantics and PMR:
https://quuxplusone.github.io/blog/2023/06/03/p1144-pmr-koans/#the-evil-allocator-aware-type
FWIW I'm highly sympathetic to the idea that `Widget` is "not a sensible
program" and I would love to see CWG or LWG make it UB. ;) It would make what
I'm trying to do with value semantics in P1144 so much easier if some more of
these "unreasonable programs" were less well-defined. But that seems like a
*gigantic* task.

My first, reduced, example, where `std::list v = {1,2,3}` is accepted for
move-only type `A`, is 100% a bug and should be fixed. But that is easy to fix.

Jason, *I* don't know by what heuristic the optimizer decides to do this
optimization or not... but are *you* at all worried that it might be a
pessimization for some types? For example, suppose we had
struct NthPrime { constexpr NthPrime(int); ... };
std::vector primes = {1,2,3,4,5,6};
Here we *want* to make an initializer_list backed by a static array
of NthPrime at compile time. If we make an initializer_list, then we'll
have to run the NthPrime(int) constructor at runtime, and that's expensive.
I tried out this example on Godbolt and the optimizer made the correct choice
in this specific case, so that's good. But I figured I should mention the
scenario in case it brings something to your mind.

[Bug libstdc++/110102] New: [13 regression] initializer_list ctors of containers skip Allocator_traits::construct, copies move-only type

2023-06-02 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110102

Bug ID: 110102
   Summary: [13 regression] initializer_list ctors of containers
skip Allocator_traits::construct, copies move-only
type
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Keywords: accepts-invalid
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/4Gq3TWE6M
#include 
struct A {
A(int) {}
A(const A&) = delete;
A(A&&) {}
};
int main() {
std::list v = {1,2,3};
}

This should be ill-formed, but GCC 13.1 accepts it!
GCC 12.3 and earlier correctly reject it.

This is supposed to be constructing a std::initializer_list and calling
`list::list(initializer_list)`, which should then complain because `A(const
A&)` is deleted.

My guess as to what's happening here:
- We're definitely calling list(initializer_list)
- It's calling _M_range_initialize(il.begin(), il.end())
- That's calling __uninitialized_copy_a
- That's probably somehow deciding that because `A` is trivially copyable, we
can just memcpy it. I.e. bug #89164 redux.

Even if it were copyable, we still wouldn't be allowed to bypass
`allocator_traits::construct`. The above snippet uses std::allocator, but I
originally found a more complicated case with pmr::polymorphic_allocator:

// https://godbolt.org/z/ToT6dW5dM
#include 
#include 
#include 
struct Widget {
using allocator_type = std::pmr::polymorphic_allocator;
Widget(int i) : i_(i) {}
explicit Widget(int i, allocator_type) : i_(i) {}
explicit Widget(const Widget& rhs, allocator_type) : i_(rhs.i_ + 100) {}
int i_;
};
static_assert(std::is_trivially_copyable_v);
int main() {
std::pmr::vector v = {1,2,3};
printf("%d %d %d\n", v[0].i_, v[1].i_, v[2].i_);
}

My understanding is that this should print "101 102 103", as GCC 12 does. But
GCC 13.1 prints "1 2 3" instead.

[Bug c++/110005] New: Writable strings seem too greedy in overload resolution

2023-05-27 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110005

Bug ID: 110005
   Summary: Writable strings seem too greedy in overload
resolution
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Keywords: diagnostic
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

I'm not clear on the entire behavior of -Wwrite-strings; bug 61579 seems
relevant. So there's probably an iceberg lurking below the surface. But here's
the tip, anyway.

// https://godbolt.org/z/Y5saPdozT
struct Evil {
Evil(const char*, const void*) { puts("1"); }
Evil(const char*, std::string) { puts("2"); }
Evil(const char*, char*) { puts("3"); }
};

int main() {
Evil e = {"", ""};
}

MSVC considers the only viable candidates #1 and #2.
Clang considers #1 and #2 preferable to #3, but will pick #3 if it's the only
candidate.
GCC considers #3 the *best* candidate, even better than #1.

Or again, something like this:

void f(const char *, std::string) { puts("4"); }
template void f(T *, std::remove_const_t *) { puts("5");
int main() {
f("", "");
}

MSVC considers #4 the only viable candidate.
Clang considers #4 preferable to #5, but will pick #5 if it's the only
candidate.
GCC considers #5 the *best* candidate, even better than #4.

Obviously MSVC's behavior is the conforming one; but I understand GCC isn't
likely to go all the way *there*. Still, Clang's behavior strikes me as a
better compromise than GCC's.

As a consolation prize, assuming there's some way to turn off GCC's
writable-strings extension, could the text of -Wwrite-strings' warning message
be updated to provide that option? E.g. instead of the current

> warning: ISO C++ forbids converting a string constant to 
> 'std::remove_const_t*' {aka 'char*'} [-Wwrite-strings]

it could say, like,

> warning: ISO C++ forbids converting a string constant to 
> 'std::remove_const_t*' {aka 'char*'}; pass -fno-writable-strings 
> to disable this extension [-Wwrite-strings]

or however the extension can actually be disabled.

[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2

2023-05-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945

--- Comment #11 from Arthur O'Dwyer  ---
(In reply to Andrew Pinski from comment #8)
> (In reply to Arthur O'Dwyer from comment #7)
> > // https://godbolt.org/z/Ea43Y65z4
> > struct Widget {
> > int i = 1;
> ...
> > In this case, Widget has no constructors,
> 
> No, it has a constructor because of the NSDMI. NSDMI causes a non-trivial
> constexpr constructor to be created.

Fair. I meant Widget has no _program-defined_ constructors (such as would have
unknown effects and might invisibly-to-the-compiler escape a copy of ``). I
might still be using the wrong term. But you found a better example without
that wrinkle, anyway. :)

[Bug tree-optimization/109945] Escape analysis hates copy elision: different result with -O1 vs -O2

2023-05-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945

--- Comment #7 from Arthur O'Dwyer  ---
Richard Biener wrote:
> Are we using the wrong check or is escaping 'this'
> for these kind of classes invoking undefined behavior?

Wow, this got a lot of traffic quickly!  Sounds like you (Richard, Andrew) are
on top of the issue here, where a constructor is involved; but once you start
talking about heuristics and checks, I think it would be productive for you two
to make sure you're both on the same page with *this* example:

// https://godbolt.org/z/Ea43Y65z4
struct Widget {
int i = 1;
int a[4];
};
Widget *global = nullptr;
Widget make2() { Widget w; global =  return w; }
void g() { global->i = 42; }
int main() {
  Widget w = make2();
  int i = w.i;
  g();
  return (i == w.i);
// Does this need to be reloaded and
// compared? or is it obviously true?  
}

In this case, Widget has no constructors, and I think it would be perfectly
defensible for the compiler to say that "global = " is not a valid way to
escape the address of that prvalue result (even though copy elision will make
the w in make() and the w in main() the same object). But do both of *you* have
the same answer to that paradox? If you don't, then you might also not agree
about what the appropriate heuristic should be in the original case and might
end up talking past each other.

[Bug c++/109945] New: Escape analysis hates copy elision: different result with -O1 vs -O2

2023-05-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109945

Bug ID: 109945
   Summary: Escape analysis hates copy elision: different result
with -O1 vs -O2
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Keywords: wrong-code
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

Background:
https://quuxplusone.github.io/blog/2021/03/07/copy-elision-borks-escape-analysis/
The background paradox here is, "When class Widget is subject to copy elision,
then any unseen function can return a prvalue Widget whose address has already
escaped!" Aaron Puchert and I were discussing this, with examples. (He thinks
the resolution of the paradox is "you *must* treat a lot more things as
escaped"; I think an acceptable resolution would be "you may treat copy-elision
itself as a magic that invalidates pointers and references even though the
object is still in the same place.")
But then I came up with an example that didn't rely on copy elision at all. We
both agree this code is perfectly well-defined — yet GCC miscompiles it at -O1!

// https://godbolt.org/z/bTnv68nhG
struct Widget {
Widget();
int i = 1;
int a[4];
};
Widget *global = nullptr;
Widget::Widget() { global = this; }
Widget make() { return Widget(); }
void g() { global->i = 42; }
int main() {
  Widget w = make();
  int i = w.i;
  g();
  return (i == w.i);
// Does this need to be reloaded and
// compared? or is it obviously true?  
}

gcc -O0 and gcc -O2 both correctly return 0 from main.
gcc -O1 wrongly returns 1 from main.

*At least* since C++17, I think the -O1 result is flat-out wrong codegen. We
have `global == `, and so the call to `g()` can definitely modify `w.i`.

(Clang always treats Widgets' addresses as escaped, no matter what Widget looks
like. MSVC's escape analysis is more complicated and I have not yet been able
to trick it into wrong codegen.)

[Bug c++/93106] [c++2a] Deleted move constructor is not selected when returning an automatic variable

2023-04-27 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93106

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #7 from Arthur O'Dwyer  ---
According to godbolt.org, Bug 93929, Bug 108594, and this Bug 93106 all appear
to be fixed now (failed in GCC 12, correct behavior in GCC 13.1).

[Bug c++/108759] "mandatory copy elision" not implemented during constant evaluation redux

2023-04-27 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108759

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
I believe what I'm going to say is simply a duplicate of Davis's report, but
just in case it's different, I'll add mine here. This is a slightly modified
version of the example from [class.copy.elision], merely modified so that g()
returns a C++17 prvalue instead of relying on NRVO/copy-elision.
Original example: https://eel.is/c++draft/class.copy.elision#2

Modified example:

// https://godbolt.org/z/n43jPs1Kj
struct A {
  void *p;
  constexpr A(): p(this) {}
};
constexpr A g() {
  return A();
}
constexpr A b = g();// well-formed, b.p points to b
static_assert(b.p == );

MSVC and Clang accept. GCC incorrectly rejects:

:11:19: error: 'A{((void*)(&))}' is not a constant
expression
   11 | constexpr A b = g();// well-formed, b.p points to b
  |   ^
:12:19: error: non-constant condition for static assertion
   12 | static_assert(b.p == );
  |   ^

[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects

2023-04-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846

--- Comment #23 from Arthur O'Dwyer  ---
(In reply to Jonathan Wakely from comment #22)
> 
> Richi suggested that we could avoid these runtime branches (which hurt
> optimization, see PR 109445) if we knew how many bytes of tail padding there
> are in _Tp [...]
> We don't have a built-in to tell us the number of [trailing] padding bytes, 
> but we
> might be able to use something like this

Three thoughts that might be helpful:
- There may be padding in the middle of an object, and I'm not confident that
the Standard actually forbids it from being used. Of course your approach works
fine on the Itanium ABI, and probably works everywhere that actually exists. If
you've got chapter+verse proving that it must work *everywhere*, I'd appreciate
seeing it, just for my own information.
- If GCC were ever to add a builtin for this notion, IMO the proper name would
be `__datasizeof(T)`. See
https://danakj.github.io/2023/01/15/trivially-relocatable.html#data-size
- You can implement your library trait like this; see
https://quuxplusone.github.io/blog/2023/03/04/trivial-swap-prize-update/#step-1.-std-swap-can-t-assume-it

template 
struct __libcpp_datasizeof {
struct _Up {
[[__no_unique_address__]] _Tp __t_;
char __c_;
};
static const size_t value = __builtin_offsetof(_Up, __c_);
};

Unfortunately it looks like GCC doesn't support
`__attribute__((__no_unique_address__))` in C++03 mode. (Neither does Clang.
What is up with that!)

Your suggested trait implementation is slightly wrong for `is_final` types: you
return 0 but really a final type _can_ have usable tail padding. See
https://godbolt.org/z/P6x459MEq

[Bug c++/109381] New: Ambiguous member lookup with this-> accepted when it should be rejected

2023-04-02 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109381

Bug ID: 109381
   Summary: Ambiguous member lookup with this-> accepted when it
should be rejected
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Keywords: accepts-invalid
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/ex97db8cT
template
struct B {
  int f() { return 1; }
};
struct C {
  int f() { return 2; }
};
template
struct D : B, C {
  int test() {
return this->f();  // GCC calls C::f; Clang and MSVC reject
  }
};
int main() {
  D d;
  return d.test();
}

This can't possibly be unreported yet, but a quick search failed to find any
bug filed on the subject. Sorry if this is a duplicate.

GCC correctly thinks that `return f();` should call `C::f` because `B::f` is
not considered because `B` is a dependent base class and we didn't say
`this->`.

But, GCC wrongly thinks that `return this->f();` should ALSO call `C::f`. Clang
and MSVC agree that it should be ambiguous, because now it IS looked up in both
phase 1 and phase 2, and an `f` is found in both base classes, so the lookup
should be considered ambiguous.

According to Godbolt, the issue was introduced somewhere between GCC 7.5 (OK)
and GCC 8.1 (buggy).

[Bug c++/100248] ICE with global "default" keyword

2023-03-29 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100248

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #3 from Arthur O'Dwyer  ---
Bug 107321 and bug 105202 are duplicates.
In bug 107321, Martin Liška writes: "Started with r10-4397-gb7689b962dd6536b."

[Bug c++/109017] New: ICE on unexpanded pack from C++20 explicit-template-parameter lambda syntax

2023-03-03 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109017

Bug ID: 109017
   Summary: ICE on unexpanded pack from C++20
explicit-template-parameter lambda syntax
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Keywords: ice-on-invalid-code
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/bdT84P318
template
struct A {
static void g() {
int dummy[] = {
[](Ts... ts){
int i = Ts();
} ...
};
}
};
int main() {
A::g();
}


: In instantiation of 'static void A<  >::g()
[with  = {int}]':
:12:14:   required from here
:4:13: internal compiler error: in tsubst_pack_expansion, at
cp/pt.cc:13388
4 | int dummy[] = {
  | ^
0x247a53e internal_error(char const*, ...)
???:0
0xae95dc fancy_abort(char const*, int, char const*)
???:0
0xd09f45 instantiate_decl(tree_node*, bool, bool)
???:0
0xd362db instantiate_pending_templates(int)
???:0
0xbe4555 c_parse_final_cleanups()
???:0
0xe21948 c_common_parse_file()
???:0
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Compiler returned: 1


Apparently GCC fails to recognize the `class... Ts` in the angle brackets (new
syntax in C++20) as pertaining to the lambda itself, and not to the outer
scope. So when GCC sees an unexpanded `Ts` in the inner scope, GCC happily
accepts it (and then ICEs). Notice that if you change `Ts()` to `ts` in the
inner scope, GCC correctly rejects the code with the usual "parameter packs not
expanded" error. The ICE is triggered specifically by misuse of
`Ts`-from-the-new-in-C++20-syntax.

[Bug libstdc++/108846] std::copy, std::copy_n and std::copy_backward on potentially overlapping subobjects

2023-02-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846

--- Comment #11 from Arthur O'Dwyer  ---
(In reply to Jonathan Wakely from comment #10)
> std::move(x,y,z) and std::copy(z,y,z) use the same underlying
> implementation, so it does have the same issue, but will be fixed by the
> same change.

Right; also std::rotate, std::set_union, etc., I'd expect would all be fixed by
the same change to std::copy.

You might want to peek at std::swap_ranges, though. Microsoft's STL has trouble
there; I don't *think* libstdc++ does, but you might as well check me.

[Bug libstdc++/108846] New: std::copy, std::copy_n on potentially overlapping subobjects

2023-02-18 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846

Bug ID: 108846
   Summary: std::copy, std::copy_n on potentially overlapping
subobjects
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://gcc.godbolt.org/z/EfdG4nzv9
#include 
#include 
struct B { 
B(int i, short j) : i(i), j(j) {}
int i; 
short j; /* 2 byte padding */ 
};
struct D : B { 
D(int i, short j, short x) : B(i, j), x(x) {}
short x;
};
int main() {
D ddst(1, 2, 3);
D dsrc(4, 5, 6);
B *dst = 
B *src = 
std::copy_n(src, 1, dst);  // should do `*dst = *src`
assert(ddst.x == 3);  // FAILS
}

Similarly if you use `std::copy(src, src+1, dst)`.
The problem here is that `std::copy` and `std::copy_n` (and presumably some
other algorithms too, like `std::move`) believe that if a type is trivially
copyable, then it's safe to use `memcpy` or `memmove` on it. But in fact that's
safe only if either
- the type's "sizeof" is equal to its "data size, without trailing padding"; or
- you happen to have external information proving that the object being copied
is not a potentially overlapping subobject.

I think it's safe for `std::copy` and `std::copy_n` to use memcpy/memmove if
they are given a destination range of 2-or-more elements; but if it's just a
single object, then (by the letter of the law) they must assume the destination
object might be a potentially overlapping subobject, and not memcpy into it.

(Full disclosure: I will be THRILLED if you close this as "not a bug," because
that will be ammunition to go to LWG and say "look, vendors think this behavior
is fine, we should actually standardize this behavior and remove the
expectation that STL algorithms can ever handle potentially overlapping
subobjects.")

[Bug c++/108257] New: Incorrect (non-unique) mangling of structured binding's backing variable

2022-12-31 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108257

Bug ID: 108257
   Summary: Incorrect (non-unique) mangling of structured
binding's backing variable
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

C++20 permits structured bindings (decomposition declarations) to be `static`.
This means we can use them in inline functions, where they need to be mangled
in the context of that inline function. Clang seems to get this right; GCC
forgets to include the context.

// https://godbolt.org/z/aKanscav3
struct A { int x,y; };
inline int f() {
static auto [a,b] = A{1,2};
return a;
}
inline int g() {
static auto [a,b] = A{3,4};
return a;
}
int (*pf)() = f;
int (*pg)() = g;
int main() {
printf("%d %d\n", f(), g());
printf("%d %d\n", pf(), pg());
}

This program should print "1 3" twice. On GCC, it fails to assemble, because
the symbol name `_ZNDC1a1bEE` is used for both backing variables.
On Clang, the symbol names are `_ZZ1fvEDC1a1bE` and `_ZZ1gvEDC1a1bE` instead.

(Totally off-topic, it is awful that the name of the backing variable includes
all of the names of the individual bindings, concatenated. That can easily
produce humongous symbol names, and interacts unusually poorly with (UB)
macro-expansion. If anyone wants to go talk to the Itanium ABI folks and get
everyone to switch to a simple "mangling number" scheme like we have already
built for lambda closure types, that would be awesome. Notice that you already
need a "mangling number" scheme *on top* of the current design, because of
https://godbolt.org/z/cYqxzxfxe — so I'm just proposing to make the scheme
simpler, if the Itanium ABI folks are willing to change it.)

[Bug c++/108216] Wrong offset for (already-constructed) virtual base during construction of full object

2022-12-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108216

--- Comment #1 from Arthur O'Dwyer  ---
Possibly tangentially related: #70644, #81051

[Bug c++/108216] New: Wrong offset for (already-constructed) virtual base during construction of full object

2022-12-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108216

Bug ID: 108216
   Summary: Wrong offset for (already-constructed) virtual base
during construction of full object
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/6qMTY6bGn
#include 

struct A *ga = nullptr;
struct B *gb = nullptr;
struct C *gc = nullptr;
struct D *gd = nullptr;

struct A {
explicit A() {
printf("Constructing A at %p\n", (void*)this);
ga = this;
printf(" A is %p\n", (void*)ga);
}
virtual void f() {}
void *a() { return this; }
};

struct B : virtual A {
explicit B() {
printf("Constructing B at %p\n", (void*)this);
gb = this;
printf(" B.A is %p\n", (void*)(A*)gb);
}
void *b() { return this; }
};

struct C : virtual A {
explicit C() {
printf("Constructing C at %p\n", (void*)this);
gc = this;
printf(" B.A is %p -- look here!\n", (void*)(A*)gb);
printf(" C.A is %p\n", (void*)(A*)gc);
}
// void f() override {}  // give Clang trouble, too
void *c() { return this; }
};

struct D : B, C {
explicit D(): B(), C() {
printf("Constructing D at %p\n", (void*)this);
gd = this;
printf(" D.B.A is %p\n", (void*)(A*)(B*)gd);
printf(" D.C.A is %p\n", (void*)(A*)(C*)gd);
}
};

int main() {
D d;
printf(" is %p\n", (void*));
printf(" is %p\n", d.c());
printf(" is %p\n", d.b());
printf(" is %p\n", d.a());
}

==

Constructing A at 0x7ffd2ef4db10
 A is 0x7ffd2ef4db10
Constructing B at 0x7ffd2ef4db10
 B.A is 0x7ffd2ef4db10
Constructing C at 0x7ffd2ef4db18
 B.A is 0x7ffd2f34ed1c -- look here!
 C.A is 0x7ffd2ef4db10
Constructing D at 0x7ffd2ef4db10
 D.B.A is 0x7ffd2ef4db10
 D.C.A is 0x7ffd2ef4db10
 is 0x7ffd2ef4db10
 is 0x7ffd2ef4db18
 is 0x7ffd2ef4db10
 is 0x7ffd2ef4db10

==

Before the line marked "look here":
- The `A` object was constructed at 0x7ffd2ef4db10.
- The `B` object pointed to by `gb` has been completely constructed.
- So `gb->a()` ought to return the address of that `A` object, 0x7ffd2ef4db10.
But instead it returns 0x7ffd2f34ed1c, which is 0x40120c bytes away from the
correct value!

I wonder if this is caused by the B-in-D and C-in-D vptrs having the same
offset, so that when we think we're access the B vtable of `*gb`, we're
actually accessing the C vtable of that empty C object...? But then, still, the
offset from the beginning of the B object or the beginning of the C object, to
the A virtual base, ought to be exactly the same number. I can't figure out a
reason for the answer to be off by 0x40120c.

==

Notice that Clang passes this test case as shown; BUT, if you uncomment the
line marked "give Clang trouble, too", then Clang will join GCC in producing
wrong results for the line marked "look here".  MSVC passes both test cases,
but that's not surprising because MSVC has a radically different ABI for struct
layout.

Originally reported by @caster on Slack, here:
https://cpplang.slack.com/archives/CBTFTLR9R/p1671750342552189

[Bug c++/87697] Casting a base class to derived gives no warning

2022-12-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87697

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #4 from Arthur O'Dwyer  ---
jynelson: Static-casting from Base& to Derived& is the foundation of the
"Curiously Recurring Template Pattern" in C++, and therefore can't be allowed
to trigger any diagnostic with -Wall -Wextra. (Many industry codebases build
with -Wall -Wextra, and also use the CRTP.)
*Aside* from that practical consideration, I don't think there's anything wrong
with casting from one type to another. The point of type-cast syntax is to say
"Don't worry, compiler, I know what I'm doing." If one doesn't know what one's
doing, then one shouldn't use casts at all, and just stick to the implicit
conversions. It's already an error to *implicitly convert* from Base& to
Derived&, so if you stick to implicit conversions you'll get exactly the
behavior you want.

Suggest closing this issue as NOTABUG.
But see also #96765 (for this kind of cast specifically *inside a
constructor*).

[Bug c++/106903] New: Incorrectly accepts call to function template when deduced type doesn't match adjusted type

2022-09-11 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106903

Bug ID: 106903
   Summary: Incorrectly accepts call to function template when
deduced type doesn't match adjusted type
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/T1vPGYash
template
struct Array {
template
operator Array() const;
};

template
void foo(Array x,
 Array y);

int main()
{
foo(Array(), Array());
}

My understanding is that template type deduction on the call to `foo` should
fail, because even though we can unambiguously deduce [T=int, U=char], and even
though the actual argument's type Array is CONVERTIBLE to the formal
parameter's type Array, it's not actually the same type. My
understanding is that a parameter that contributes to deduction must have the
same type as its corresponding function argument.

MSVC correctly rejects with this confusing message-spew:
(13): error C2664: 'void foo(Array,Array)':
cannot convert argument 2 from 'Array' to 'Array'
(13): note: Binding to reference
(13): note: followed by
(13): note: Call to user-defined-conversion 'Array::operator
Array(void) const<4>'
(4): note: see declaration of 'Array::operator Array'
(13): note: followed by
(13): note: Exactly the same type
(8): note: see declaration of 'foo'

Clang correctly rejects with this message:
:13:5: error: no matching function for call to 'foo'
foo(Array(), Array());
^~~
:8:6: note: candidate template ignored: deduced type 'Array<[...],
sizeof(int) aka 4>' of 2nd parameter does not match adjusted type 'Array<[...],
6>' of argument [with T = int, U = char]
void foo(Array x,
 ^

[Bug libstdc++/105241] New: std::bitset::reference should have an ADL swap

2022-04-12 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105241

Bug ID: 105241
   Summary: std::bitset::reference should have an ADL swap
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

(Originally reported by Nicholas Sielicki on the cpplang Slack)

// https://godbolt.org/z/138cPv5cn
#include 
#include 
std::bitset<1> a = {1};
std::bitset<1> b = {0};
int main() {
using std::swap;
swap(a[0], b[0]);
return a[0] == 0 && b[0] == 1;  // should be TRUE, right?
}

:8:9: error: no matching function for call to
'swap(std::bitset<1>::reference, std::bitset<1>::reference)'
8 | swap(a[0], b[0]);
  | ^~~~

Swapping elements via the std::swap two-step works for `std::vector`; I
see no reason it shouldn't also work for `std::bitset`.
libc++ and Microsoft STL both support `swap` on `bitset::reference` just fine.

[Bug c++/104792] [g++ and/or libstdc++] Wunused-local-typedefs + C++20 concepts = annoying

2022-03-05 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104792

--- Comment #2 from Arthur O'Dwyer  ---
@Andrew Pinski: Sorry, looks like my description ended up not matching the
Godbolt (I said "three lines marked X," but there are only two lines marked X,
for example.)

Here's the Godbolt with one of the two lines commented out. The annoying
warning is present. 

// https://godbolt.org/z/Ms4sePPfe
#include 
void test() {
struct It {
using value_type = int;
using difference_type = int;
int& operator*() const;
It& operator++();   // X
//It operator++(int); // X
};
static_assert(std::is_same_v<
std::iter_value_t, int>);
static_assert(std::is_same_v<
std::iter_rvalue_reference_t, int&&>);
}

$ g++ -std=c++20 -Wall -Wextra test.cpp
test.cpp: In function 'void test()':
test.cpp:6:15: warning: typedef 'using difference_type = int' locally defined
but not used [-Wunused-local-typedefs]
6 | using difference_type = int;
  |   ^~~

[Bug c++/104792] New: [g++ and/or libstdc++] Wunused-local-typedefs + C++20 concepts = annoying

2022-03-04 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104792

Bug ID: 104792
   Summary: [g++ and/or libstdc++] Wunused-local-typedefs + C++20
concepts = annoying
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

This might be considered "not a bug", or "duplicate of #61596", or "bug but in
a different way from what Arthur suggests," so I'm going to give the
non-reduced test case and let one of you (@jwakely perhaps) worry about how to
reduce it.

// https://godbolt.org/z/v9Wv8vY3G
#include 
void test() {
struct It {
using value_type = int;
using difference_type = int;
int& operator*() const;
It& operator++();   // X
It operator++(int); // X
};
static_assert(std::is_same_v, int>);
static_assert(std::is_same_v, int&&>);
}

Compile with "g++ -std=c++20 -W -Wall" and libstdc++.
GCC will give a warning:

warning: typedef 'using difference_type = int' locally defined but not used
[-Wunused-local-typedefs]
6 | using difference_type = int;
  |   ^~~

However, if you then delete any of the three lines marked "X", the warning will
go away again.
I believe this is because `iter_value_t` relies on a C++20 Concepts
constraint where `difference_type` *is* checked when `It` is an
`input_iterator`, but is *not* checked when `It` is not an iterator. So, when
these precise three operators exist, the typedef isn't unused, but when any one
of them doesn't exist, GCC gives the unused-typedef warning.
I claim that the user-programmer shouldn't be responsible for tracking the
internal implementation details of the constraints of `std::iter_value_t`. I
just want to make a local type that has all the pieces of an iterator, without
GCC helpfully getting in the way and warning me that *right now* (according to
the internal implementation details of libstdc++) some of those pieces aren't
being used.

I admit that in this case the warning is surfaced only when I *fail* to
implement one of those three member functions, so I actually have *not*
implemented "all the pieces of an iterator" in this test case. I'm betting that
it's possible to reproduce this annoying issue, somewhere in libstdc++, even
without that caveat, though.

For now, I'll silence the warning by removing my unused typedef
`difference_type`, i.e.

#include 
void test() {
struct It {
using value_type = int;
int& operator*() const;
};
static_assert(std::is_same_v, int>);
static_assert(std::is_same_v, int&&>);
}

But I'm uncomfortable with that, because I don't know if later
revisions/bugfixes to the library will require me to re-add those pieces I've
removed.

[Bug libstdc++/68350] std::uninitialized_copy overly restrictive for trivially_copyable types

2022-02-24 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68350

--- Comment #12 from Arthur O'Dwyer  ---
jwakely wrote:
> Correction: they need to be the same type. We can't memcpy here:
>
> struct A { };
> struct B { B() = default; B(A) { do_stuff(); } };
>
> void (A* f, A* l, B* out) {
>   std::uninitialized_copy(f, l, out);
> }

Right, in your case, the ctor `B(A)` runs user-defined code (it's not
"trivial") so obviously we can't do the optimization. But even in general, see
my 2018 blog post "Trivially-constructible-from."
https://quuxplusone.github.io/blog/2018/07/03/trivially-constructible-from/

  using A2 = long long;
  using B2 = int64_t;  // for the sake of argument, this is "long int"
  void (A* f, A* l, B* out) {
std::uninitialized_copy(f, l, out);
  }

The library can't, by itself, determine that memcpy would be safe here. The
library needs help from the compiler, e.g. via a new compiler builtin
__is_trivially_constructible_from(T, U). (This is *not* the same as the
existing `is_trivially_constructible` type trait, because blog post.)

[Bug libstdc++/104559] New: vector v; v.insert(v.begin()); compiles, but it shouldn't

2022-02-15 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104559

Bug ID: 104559
   Summary: vector v; v.insert(v.begin()); compiles, but it
shouldn't
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/3efs3aY67
#include 
int main() {
std::vector v;
v.insert(v.begin());  // libstdc++ accepts!
}

Somehow libstdc++ believes that `vector::insert(_Bit_const_reference)`
should work. (I bet it inserts "false" at the given position, but I haven't
checked.)

[Bug middle-end/104195] New: Fails to optimize nested array indexing p[i/N].data[i%N]

2022-01-23 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104195

Bug ID: 104195
   Summary: Fails to optimize nested array indexing
p[i/N].data[i%N]
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: middle-end
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

GCC seems to be unable to optimize some nested array accesses of the form
p[i/N].data[i%N] into a simple ((T*)p)[i]. The C test case is

struct CChunk { int data[4]; };
int f(struct CChunk *p, unsigned long long i) { return p[i/4].data[i%4]; }

gcc -O2 currently produces:

movq %rsi, %rax
andl $3, %esi
shrq $2, %rax
salq $4, %rax
addq %rax, %rdi
movl (%rdi,%rsi,4), %eax
ret

but I would prefer it to produce:

movl (%rdi,%rsi,4), %eax
retq

A more exhaustive C++ test follows — GCC can optimize a few of these, but not
all. (Clang can't optimize any of these; I've just filed
https://github.com/llvm/llvm-project/issues/53367 about that.)
https://godbolt.org/z/3E1e6c5e3

template
struct Chunk {
T data[N];
};

template
int f(Chunk *p, IndexType i) {
return p[i/N].data[i%N];
}

template int f(Chunk*, unsigned long long);  // GCC wins
template int f(Chunk*, unsigned long long);  // GCC wins
template int f(Chunk*, unsigned);
template int f(Chunk*, unsigned);
template int f(Chunk*, unsigned long long);  // GCC wins
template int f(Chunk*, unsigned long long);
template int f(Chunk*, unsigned);
template int f(Chunk*, unsigned);

[Bug c++/101421] ICE: in lookup_template_class_1, at cp/pt.c:10005

2022-01-04 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101421

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
C++14 reproducer: https://gcc.godbolt.org/z/WafKPneef

template
void f() {
[](auto){}.operator();
}
template void f();

[Bug c++/101239] "Internal compiler error: Error reporting routines re-entered." in size_in_bytes_loc

2021-12-13 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101239

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #4 from Arthur O'Dwyer  ---
I believe I just hit this as well. Here's a C++20 reproducer:

auto f(auto a) -> decltype(a+1) { return a+1; }
struct Incomplete *p;
auto b = f(p);

The problem seems to be something about over-eager hard-erroring on pointer
arithmetic with incomplete types, because GCC also rejects this valid code:

auto f(auto a) requires requires { a+1; } { return a+1; }
auto f(auto a) { return a; }
struct Incomplete *p;
auto b = f(p);

(Should call the unconstrained overload; but GCC hard-errors instead.)

[Bug c++/96441] ICE in tree check: expected integer_cst, have cond_expr in get_len, at tree.h:5954

2021-10-27 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96441

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
Still there in trunk. Here's a very slightly reduced version:

// https://godbolt.org/z/8arT4Gn6P
enum a : int;
template;
template<> enum a : int {c};



:2:35: error: expected unqualified-id before ';' token
2 | template;
  |   ^
:3:26: internal compiler error: Segmentation fault
3 | template<> enum a : int {c};
  |  ^
0x20037b9 internal_error(char const*, ...)
???:0
0x8c7150 build_enumerator(tree_node*, tree_node*, tree_node*, tree_node*,
unsigned int)
???:0
0xa0bea5 c_parse_file()
???:0
0xb92e22 c_common_parse_file()
???:0
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

[Bug c++/102419] [11/12 Regression][concepts] [regression] return-type-requirement of "Y" does not check that T::type actually exists

2021-09-21 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102419

--- Comment #4 from Arthur O'Dwyer  ---
> IMHO Clang/MSVC are clearly misbehaving here -- when evaluating the 
> concept-id X, they appear to be substituting {int} into X's 
> constraint-expression instead of into the normal form of X's 
> constraint-expression.

Isn't this situation exactly analogous to `std::void_t`?

  template using void_t = void;
  template auto foo(T t) -> void_t;  // SFINAEs away
  template auto foo(T t) -> int;  // this is the only viable candidate
  static_assert(std::same_as);

The language has definitely decided that you can't preemptively fold
`void_t` down to `void`; I don't think you should be
allowed to preemptively fold `Y` down to `true`,
either.
I don't know for sure that Clang/MSVC have been authoritatively dubbed
righteous, but their behavior certainly seems, to me, more consistent and
useful than GCC's.

[Bug c++/102419] New: [concepts] [regression] return-type-requirement of "Y" does not check that T::type actually exists

2021-09-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102419

Bug ID: 102419
   Summary: [concepts] [regression] return-type-requirement of
"Y" does not check that T::type
actually exists
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/GWjYYnrnM
template concept Y = true;
template concept X = requires {
{ 1 } -> Y;
};
static_assert(!X);


:8:15: error: static assertion failed
8 | static_assert(!X);
  |   ^~~

Clang and MSVC both appear to have the correct behavior -- or what I believe to
be the consistent/useful/majority behavior, anyway -- which is that since
T::type doesn't exist, the concept shouldn't be satisfied.

This seems to be a regression; according to Godbolt, GCC 10.3 had the correct
behavior but GCC 11.1 lost it. 

I wonder if #92268 could be related somehow, since it seems to be something
like the inverse issue (nonexistent nested type causing a hard error in 10.x),
and it was marked fixed presumably somewhere in the 11.x timeframe.

[Bug c++/94673] [concepts] What is the return type of local parameters of requires expressions?

2021-09-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94673

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
Yes, this is/was a Clang bug; a return-type-requirement should be applied to
decltype((expr)), but Clang was incorrectly applying the requirement to
decltype(expr).

I think this can now be closed as "not a bug" (the bug was in Clang, not GCC).

[Bug c++/81157] If constexpr does not support Short-circuit evaluation

2021-09-20 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81157

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #1 from Arthur O'Dwyer  ---
I'd say neither a bug nor a defect. In `if constexpr (X && Y)`, `X && Y` is an
expression and it must be well-formed, even if it's false -- just like if you
did `static_assert((X && Y) == false)`. GCC is behaving according to the C++
Standard in this case.

Recommend closing as INVALID.

[Bug c++/92505] Using mutable in constexpr

2021-09-06 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92505

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #4 from Arthur O'Dwyer  ---
Confirmed; the test case can be as simple as

// https://godbolt.org/z/M9rf31qqq
struct S { mutable int m; };
static_assert(S{42}.m == 42);

(Removing the "mutable" keyword makes GCC happy.)

[Bug libstdc++/81078] dynamic_cast to virtual base produces the wrong answer

2021-08-18 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81078

--- Comment #3 from Arthur O'Dwyer  ---
Yes, this is a libstdc++ issue.

I'm not 100% sure that "the RTTI [generated by GCC] is correct," because I
don't know how to use GCC with libc++; but yeah, there's definitely at least
some problem with libstdc++ here. Observe that Clang-with-libstdc++ fails,
Clang-with-libc++ succeeds: https://godbolt.org/z/PMq6rW9cE

[Bug c++/101353] New: [x86-64] missed optimization: missed tail call in placement-new

2021-07-06 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101353

Bug ID: 101353
   Summary: [x86-64] missed optimization: missed tail call in
placement-new
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/9zP5dP3sE
#include 
struct T {
int x;
T(int) noexcept;
~T();
};
T factory(int) noexcept;
alignas(T) char buffer[sizeof(T)];
void placement_new() {
::new ((void*)buffer) T(42);
}
void placement_call() {
::new ((void*)buffer) T(factory(42));
}

g++ -O2 -std=c++20 test.cpp

Somehow the compiler is failing to generate an actual `jmp` tail call for
`placement_call` the way it's able to for `placement_new`.

  _Z13placement_newv:
movl $42, %esi
movl $buffer, %edi
jmp _ZN1TC1Ei
  _Z14placement_callv:
subq $8, %rsp
movl $42, %esi
movl $buffer, %edi
call _Z7factoryi
addq $8, %rsp
ret

Note that right now Clang has the same symptom; but ICC and MSVC both get this
right and generate tail-calls appropriately in both cases. So this isn't any
obscure C++ corner case AFAICT; seems it's truly just a missed optimization.

Clang's missed-optimization bug is filed as
https://bugs.llvm.org/show_bug.cgi?id=51000

[Bug libstdc++/96416] to_address() is broken by static_assert in pointer_traits

2021-03-26 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416

--- Comment #13 from Arthur O'Dwyer  ---
> And are you recommending that everyone who defines their custom contiguous
> iterators specializes pointer_traits for them? Call it _quite_ annoying...

Definitely not! When you define a contiguous iterator type, you should just
give it a sixth nested typedef alongside the other five (or three in C++20):
`using element_type = value_type;`. This enables contiguous-iterator machinery.
See
https://stackoverflow.com/questions/65712091/in-c20-how-do-i-write-a-contiguous-iterator/66050521#66050521

You should never specialize std::pointer_traits for your own type.
("Can" you? Yes. "Should" you? No.)

[Bug c++/76262] list-initialization prefers initializer_list over copy constructor

2021-03-17 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=76262

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #5 from Arthur O'Dwyer  ---
GCC still has the buggy behavior as of 2021. This bug should be reopened.

GCC's behavior here disagrees with all of Clang, ICC, MSVC, and common sense.

// https://godbolt.org/z/GKxh8P
struct A {};
struct B {
B(const B&);
explicit B(std::initializer_list);
operator A() const;
};

extern B b;
void test() {
auto a{b};  // constructs as if by `B a = { static_cast(b) }`, not `B a
= b`
}

I recently observed real teaching materials claiming that brace-initialization
didn't work for copies -- if you want to invoke the copy constructor you MUST
use parentheses -- and giving essentially this bug as the reason. (They
apparently didn't realize that this behavior was unique to GCC, and the subject
of a bug report.)

[Bug c++/70816] bogus error __builtin_strcmp is not a constant expression in a constexpr function

2021-03-14 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70816

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #2 from Arthur O'Dwyer  ---
Confirmed, I'm also seeing this in C++20 mode. This affects libc++'s
 `char_traits::length(const char *)`.

Example test case: https://godbolt.org/z/MTq1ex

[Bug libstdc++/99417] New: [C++17] std::variant assignment fails to compile

2021-03-05 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99417

Bug ID: 99417
   Summary: [C++17] std::variant assignment fails to compile
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/b3P6Ta
#include 
struct Original {};
struct C {
C(const Original&);
C(C&&) noexcept;
C& operator=(const Original&);
~C();
};
void testc(std::variant& vc, const Original& original) {
vc = original;
}

In file included from :1:/include/c++/11.0.1/variant:1445:3:
error: call to deleted member function 'operator='
operator=(variant(std::forward<_Tp>(__rhs)));
^
:13:8: note: in instantiation of function template specialization
'std::variant::operator=' requested here
vc = original;
   ^
/include/c++/11.0.1/variant:1368:16: note: candidate function has been
implicitly deleted
  variant& operator=(const variant&) = default;
   ^
/include/c++/11.0.1/variant:1431:2: note: candidate template ignored:
requirement '__not_self &&>' was not satisfied [with _Tp =
std::variant]
operator=(_Tp&& __rhs)
^
1 error generated.


Removing the keyword `noexcept` from the move-constructor makes this compile.
It compiles fine (with or without `noexcept`) on libc++ and MSVC STL.

[Bug c++/99093] New: [missed optimization] Missed devirtualization involving internal-linkage class type (but only sometimes)

2021-02-13 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99093

Bug ID: 99093
   Summary: [missed optimization] Missed devirtualization
involving internal-linkage class type (but only
sometimes)
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/hx7h7v
struct Base {
virtual int f() { return 1; }
};

namespace {
struct Derived1 : public Base {
int f() override { return 2; }
};
struct Derived2 : public Base {};
}

int leaf_class1(Base *p) { return ((Derived1*)p)->f(); }
// devirtualized by GCC, because PrivateDerived is provably a leaf

int leaf_class2(Base *p) { return ((Derived2*)p)->f(); }
// not devirtualized by GCC -- this smells like a missed-optimization bug



GCC 4.9 started to be able to devirtualize things in the compiler, based on
translation-unit-wide (but still compiler-time) information. GCC 4.9.0 is able
to devirtualize the call in `leaf_class1`. This is awesome!

However, both GCC 4.9 and GCC trunk fail to apply the exact same optimization
to `leaf_class2`. The only difference between `Derived1` and `Derived2` is that
`Derived1::f` is declared directly in `Derived1` whereas `Derived2::f` is
technically a member of `Base`. That shouldn't matter at all to the
devirtualization logic. But apparently it does.



Barely possibly related missed-devirtualization bugs: #47316, #60674, #89924,
#94243.

[Bug c++/98644] New: [concepts] ICE in satisfaction_value, at cp/constraint.cc:2825

2021-01-12 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98644

Bug ID: 98644
   Summary: [concepts] ICE in satisfaction_value, at
cp/constraint.cc:2825
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/qh1zos
template concept Signed = bool(T(1));
static_assert(Signed);

Compile with "-std=c++20":

:2:28: internal compiler error: in satisfaction_value, at
cp/constraint.cc:2825
2 | static_assert(Signed);
  |^
0x1cc31d9 internal_error(char const*, ...)
???:0
0x6b25f7 fancy_abort(char const*, int, char const*)
???:0
0x7390d2 evaluate_concept_check(tree_node*, int)
???:0
0x7255f4 maybe_constant_value(tree_node*, tree_node*, bool)
???:0
0x97ffcd finish_static_assert(tree_node*, tree_node*, unsigned int, bool, bool)
???:0

Another very similar ICE, even though the stack trace is different:

// https://godbolt.org/z/rPn6vd
bool Signed = requires { requires bool((char *)1); };

:1:35: internal compiler error: in satisfaction_value, at
cp/constraint.cc:2825
1 | bool Signed = requires { requires bool((char *)1); };
  |  ~^~~
0x1cc31d9 internal_error(char const*, ...)
???:0
0x6b25f7 fancy_abort(char const*, int, char const*)
???:0
0x737597 tsubst_requires_expr(tree_node*, tree_node*, int, tree_node*)
???:0

[Bug c++/98639] GCC accepts cast from Base to Derived in C++20 mode

2021-01-12 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98639

--- Comment #5 from Arthur O'Dwyer  ---
Meh, I guess this is just an unintended (but conforming) consequence of the
shifting C++17/20 rules. Jonathan links to
https://twitter.com/wakomeup/status/1274778577087627267 as another example:

// https://godbolt.org/z/WWr9b8 
Base b;
const Derived& rd = b; // ill-formed forever, I hope
const Derived& rd{b};  // ill-formed until '14, OK in '17 and later
const Derived& rd(b);  // ill-formed until '17, OK in '20 and later

It remains _surprising_ that you can make a `Derived` out of a `Base` in the
absence of a constructor... but that's just the new aggregate-paren-init rules
at work.
It remains _surprising_ that you can bind a `const Derived&` to a `Base&`
without a cast... but that's just the interaction of lifetime extension with
the new aggregate-init rules.

I do think it'd be nice for GCC to give some sort of diagnostic here. But I
guess it would have to be an opt-in diagnostic switch. And we already have that
switch today; it's called `-std=c++17`. ;)  So maybe there's really no way to
improve the situation here at all, and this can be closed as NOTABUG.

[Bug c++/98639] New: GCC accepts cast from Base to Derived in C++20 mode

2021-01-12 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98639

Bug ID: 98639
   Summary: GCC accepts cast from Base to Derived in C++20 mode
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/96EEPa
struct Base {};
struct Derived : Base {};
Derived t() { Base b; return Derived(b); }

// https://godbolt.org/z/G4covG
auto lam = [i=42]() { return i; };
struct Derived : decltype(lam) {
bool is_derived() const { return true; }
};
Derived t() { return Derived(lam); }

I actually suspect that this behavior is related to C++20's paren-init for
aggregates; it might even be conforming? But there's no way this behavior was
*intentional.* A value of type Base shouldn't be castable to Derived.

static_cast(b) is also accepted by GCC.

[Bug c++/97034] [11 Regression] ICE on C++20 code: gcc_assert failure in return type deduction (gcc/cp/pt.c:26984 in type_dependent_expression_p(tree_node*))

2021-01-08 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97034

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #5 from Arthur O'Dwyer  ---
Is mine the same bug? Mine is also a regression (trunk crashes where GCC 10.2
had succeeded).

// https://godbolt.org/z/Ysh6as
struct C { void f(auto) noexcept; };
void C::f(auto) noexcept(C::x) {}

Compile with -std=c++20:


:3:29: error: 'x' is not a member of 'C'
3 | void C::f(auto) noexcept(C::x) {}
  | ^
:3:6: error: declaration of 'void C::f(auto:2)' has a different
exception specifier
3 | void C::f(auto) noexcept(C::x) {}
  |  ^
:2:17: note: from previous declaration 'void C::f(auto:1) noexcept'
2 | struct C { void f(auto) noexcept; };
  | ^
:3:30: internal compiler error: in type_dependent_expression_p, at
cp/pt.c:27166
3 | void C::f(auto) noexcept(C::x) {}
  |  ^
0x1cc31d9 internal_error(char const*, ...)
???:0
0x6b25f7 fancy_abort(char const*, int, char const*)
???:0
0x8ee70a type_dependent_expression_p(tree_node*)
???:0
0x137d4f3 walk_tree_1(tree_node**, tree_node* (*)(tree_node**, int*, void*),
void*, hash_set >*,
tree_node* (*)(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*),
void*, hash_set >*))
???:0
0x1381b55 walk_tree_without_duplicates_1(tree_node**, tree_node*
(*)(tree_node**, int*, void*), void*, tree_node* (*)(tree_node**, int*,
tree_node* (*)(tree_node**, int*, void*), void*, hash_set >*))
???:0
0x8ea937 instantiation_dependent_uneval_expression_p(tree_node*)
???:0
0x8f2198 instantiation_dependent_expression_p(tree_node*)
???:0
0x8f2216 uses_template_parms(tree_node*)
???:0
0x78ffe8 duplicate_decls(tree_node*, tree_node*, bool, bool)
???:0
0x79a2b6 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*,
decl_context, int, tree_node**)
???:0
0x79dda6 start_function(cp_decl_specifier_seq*, cp_declarator const*,
tree_node*)
???:0
0x8d803d c_parse_file()
???:0
0xa54072 c_common_parse_file()
???:0

[Bug c++/98249] New: Improper ADL on the `arg` in `new (arg) T`

2020-12-11 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98249

Bug ID: 98249
   Summary: Improper ADL on the `arg` in `new (arg) T`
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/xavfej

#include 
struct Incomplete;
template struct Holder { T t; };
Holder *p;
void test() {
::new (p) int;
new (p) int;
}

In an "ADL call," the compiler needs to compute the associated types of
`Holder`, which means it needs to complete that type in order to
check for friend declarations.  In a "non-ADL call" (such as a qualified call),
the compiler does NOT need to complete `Holder`.  Since completing
`Holder` produces a hard error, we can detect the difference
between an ADL and a non-ADL call.

All other compilers use "non-ADL calls" for both `::new (p) int` and `new (p)
int`: they don't attempt to complete the incomplete type. GCC uses "ADL calls"
for both, which means it hard-errors on both lines.

I'm not sure what the Standard has to say about this, but GCC disagrees with
all of Clang/MSVC/ICC, so I think GCC ought to change.

(Detected while testing libc++ patch https://reviews.llvm.org/D92884)

[Bug c++/98039] New: Member function template with dependent return type involving class's own name: wrong-mangling, accepts-invalid

2020-11-27 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98039

Bug ID: 98039
   Summary: Member function template with dependent return type
involving class's own name: wrong-mangling,
accepts-invalid
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/qq7196
struct S {
template static void f(T);
template static auto h(T t)
-> decltype(S::f(t));
};
void test() {
S::h(42);
}

Here, GCC trunk mangles `S::h` as `_ZN1S1hIiEEDTclsrS_1ffp_EET_`, but both
Clang and ICC agree that the mangling should be
`_ZN1S1hIiEEDTclsr1SE1ffp_EET_`. I naively assume that this indicates a bug in
GCC's mangling.

_ZN1S1hIiEEDTclsrS_1ffp_EET_ has "S_" where
_ZN1S1hIiEEDTclsr1SE1ffp_EET_ has "1SE".



It gets worse: If you make `f` non-static, then GCC accepts this code even
though it is invalid. In that case, the mangled name of the `h` that is
(wrongly) called is

_ZN1S1hIiEEDTcldtdefpTsrS_1ffp_EET_

// https://godbolt.org/z/Kr1baT
struct S {
template void f(T);
template static auto h(T t)
-> decltype(S::f(t));
};
void test() {
S::h(42);
}

[Bug c++/97988] New: [C++20] Forward-declared class type declared inside requires-expression gives weird inconsistencies

2020-11-25 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97988

Bug ID: 97988
   Summary: [C++20] Forward-declared class type declared inside
requires-expression gives weird inconsistencies
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/sxWY1f
template
concept C = requires (P ptr) { (struct D*)ptr; };

struct D {};
D d;



Clang accepts. GCC rejects; GCC's error messages imply that GCC is sometimes
treating `D` as a class template `template struct D` and sometimes
treating it as a normal class type, as if its internal representation is
inconsistent.

:6:3: error: class template argument deduction failed:
6 | D d;
  |   ^
:6:3: error: no matching function for call to 'D()'
:3:40: note: candidate: 'template D()-> D'
3 | concept C = requires (P ptr) { (struct D*)ptr; };
  |^
:3:40: note:   template argument deduction/substitution failed:
:6:3: note:   couldn't deduce template parameter 'P'
6 | D d;
  |   ^
:3:40: note: candidate: 'template D(D)-> D'
3 | concept C = requires (P ptr) { (struct D*)ptr; };
  |^
:3:40: note:   template argument deduction/substitution failed:
:6:3: note:   candidate expects 1 argument, 0 provided
6 | D d;
  |   ^



I can also make GCC segfault by trying to use `D` as an NTTP, but I think
that's essentially just a duplicate of #95159 #95291 #96123 #97749 etc., not
necessarily related to the rejects-invalid bug described here.

template
concept C = requires (P ptr) { (struct D*)ptr; };

struct D { constexpr D(); };
template struct S {};
S<1> s;

[Bug c++/97883] New: [C++20] Segmentation fault on template with braced initializer list A<{}>

2020-11-17 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97883

Bug ID: 97883
   Summary: [C++20] Segmentation fault on template with
braced initializer list A<{}>
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/841ahx
template struct A;
A<{}> a;

In -std=c++17 mode, this gives an error as expected. In -std=c++20 mode, this
segfaults:

:2:5: error: deducing from brace-enclosed initializer list requires
'#include '
  +++ |+#include 
1 | template struct A;
2 | A<{}> a;
  | ^
:2:5: internal compiler error: Segmentation fault
0x1bf9b89 internal_error(char const*, ...)
???:0
0x8a5846 do_auto_deduction(tree_node*, tree_node*, tree_node*, int,
auto_deduction_context, tree_node*, int)
???:0
0x8c48ac lookup_template_class(tree_node*, tree_node*, tree_node*, tree_node*,
int, int)
???:0
0x9197cd finish_template_type(tree_node*, tree_node*, int)
???:0
0x87f57c c_parse_file()
???:0
0x9f7452 c_common_parse_file()
???:0
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.


If you "#include ", you successfully suppress the first error
message; but the segfault still happens in the same place.

Might be related to #95291 or #97749. It's weird that this happens ONLY in
C++20 mode, even though it uses nothing but C++17 features.

[Bug c++/97801] New: overload resolution ambiguity isn't detected when rvalue ref qualifier is involved

2020-11-11 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97801

Bug ID: 97801
   Summary: overload resolution ambiguity isn't detected when
rvalue ref qualifier is involved
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/7onfa6
struct G {
   static int min(int=0) { return 1; }
   int min() && { return 2; }
};
int x = G::min();

GCC accepts; Clang, MSVC, and ICC reject.

GCC treats `G::min()` as an unambiguous call to the static member function.
However, C++ seems to require that overload resolution reject this code as
ambiguous -- it should be ambiguous between the two different G::min()s capable
of taking zero arguments, *even though* the non-static one can't actually be
called without a "this" argument.

Strangely, this bug appears only when the non-static candidate is
rvalue-ref-qualified (either "&&" or "const&&" or "volatile&&"). It does not
appear with "&" or "const&" or "const", nor if the function is not
ref-qualified.

[Bug c++/97716] New: Class's `operator delete`should be implicitly `noexcept`

2020-11-04 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97716

Bug ID: 97716
   Summary: Class's `operator delete`should be implicitly
`noexcept`
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

#include 
#include 
struct S {
void operator delete(void*);
};

static_assert(std::is_same_v<
decltype(S::operator delete),
void(void*) noexcept
>);

Clang and ICC and MSVC accept this static_assert; GCC rejects.

The wording controlling this is http://eel.is/c++draft/except.spec#10 :
> A deallocation function with no explicit noexcept-specifier has a 
> non-throwing exception specification.

[Bug c++/86769] g++ destroys condition variable in for statement too early

2020-10-28 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86769

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #3 from Arthur O'Dwyer  ---
Confirmed. https://godbolt.org/z/MfbrcG

[Bug c++/68003] Variable declared in condition in for loop is destroyed too soon

2020-10-28 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68003

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #1 from Arthur O'Dwyer  ---
Confirmed. https://godbolt.org/z/MfbrcG
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86769 is a duplicate.

[Bug c++/93085] ICE in get_class_binding_direct and alias_ctad_tweaks, with C++20 NTTP + CTAD + alias template

2020-10-17 Thread arthur.j.odwyer at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93085

--- Comment #3 from Arthur O'Dwyer  ---
Re comment 2: My original test code was "invalid-code", but here's one I
believe to be "valid-code" in C++20.

// https://godbolt.org/z/dqcWeq
template class A>
struct G {
template using B = A;
template static int foo();
template static int foo();
int x = foo<42>();  // OK
};

test.cc:7:21: internal compiler error: in get_class_binding_direct, at
cp/name-lookup.c:1238
7 | int x = foo<42>();  // OK
  | ^


If you change the `` to an ``, the ICE disappears, but GCC still gives a
bogus error at template-definition time:

// https://godbolt.org/z/Tjrnzv
template class A>
struct G {
template using B = A;
template static int foo();// #1
template static int foo();  // #2
int x = foo<42>();  // OK
};

test.cc:7:21: error: call of overloaded 'foo()' is ambiguous
7 | int x = foo<42>();  // OK
  | ^

GCC shouldn't even be trying to resolve `foo<42>()` until `G` has been
instantiated; and once `G` has been instantiated with some specific `A`, this
call may or may not be ambiguous (depending on whether it's possible to deduce
the template arguments to foo #1 or not).

[Bug c++/97096] New: ICE on invalid: in register_constexpr_fundef, on out-of-line-defaulted operator== or operator<=>

2020-09-17 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97096

Bug ID: 97096
   Summary: ICE on invalid: in register_constexpr_fundef, on
out-of-line-defaulted operator== or operator<=>
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/neqx1q

cat >test.cpp <https://gcc.gnu.org/bugs/> for instructions.


The same ICE happens if you replace both instances of `==` with `<=>`.

[Bug c++/95407] [DR 1873] G++ allows access to base class members from a friend of a derived class

2020-08-14 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95407

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #1 from Arthur O'Dwyer  ---
According to Richard's comment on https://bugs.llvm.org/show_bug.cgi?id=46036 ,
http://cwg-issue-browser.herokuapp.com/cwg1873 indicates that Clang may be
correct according to the Standard as written. HOWEVER...

The "misbehavior" here isn't really about `friend`; it's about the interaction
between `static` and `protected`. If you change your test case to make `value`
non-static, then all vendors agree that the non-static `value` is inaccessible.

With a static protected member (Clang rejects, GCC and MSVC accept):
https://godbolt.org/z/essofs
With a non-static protected member (all three correctly reject):
https://godbolt.org/z/T1GWTP

And here's a test case that doesn't use `friend` at all, but rather uses a
private inheritance path, so that `C` is derived from `A`, but `C` itself is
not aware of the fact. This case came up on Slack on 2020-08-14:
https://cpplang.slack.com/archives/C5GN4SP41/p1597391677014800

With a static protected member (GCC and Clang accept, MSVC rejects):
https://godbolt.org/z/6d786M
With a non-static protected member (all three correctly reject):
https://godbolt.org/z/MeTxeW

// https://godbolt.org/z/6d786M
struct A {
protected:
static int sf();
};
struct B : private A {};

struct C : public B {
static void test();
};

void C::test() { &::A::sf; }

[Bug c++/96555] New: "template argument involves template parameter(s)" with dot or arrow operator in partial specialization

2020-08-10 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96555

Bug ID: 96555
   Summary: "template argument involves template parameter(s)"
with dot or arrow operator in partial specialization
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/Kc98ea
struct A { int x; };
extern A a;
template struct B {};
template
struct B {};


:5:8: error: template argument '(int)sizeof (a.x)' involves template
parameter(s)
5 | struct B {};
  |^


GCC seems to have a problem only with expressions involving the dot operator
(e.g. `sizeof(a.x)`) and the arrow operator (e.g. `sizeof(p->x)`), but not any
other operators, which leads me to believe that the root cause here is related
to the root cause of bug 96215.

Grepbait: template argument involves template parameters

Same error message in different situations, all involving partial
specializations but none involving dot or arrow specifically: bug 67593, bug
83426, bug 90099

[Bug c++/96515] New: [concepts] Segfault on ill-formed pack expansions in requires-expression

2020-08-06 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96515

Bug ID: 96515
   Summary: [concepts] Segfault on ill-formed pack expansions in
requires-expression
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/rafY6G
template
concept PackHasAdd = (requires(Args... args) {
   (args+1);
} && ...);

static_assert(PackHasAdd);
int main() {}


Compile with GCC trunk (11.0.0), "g++ -std=c++20":

:7:31: internal compiler error: Segmentation fault
7 | static_assert(PackHasAdd);
  |   ^
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://gcc.gnu.org/bugs/> for instructions.

[Bug c++/96213] GCC doesn't complain about ill-formed non-dependent template default argument

2020-07-23 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213

--- Comment #2 from Arthur O'Dwyer  ---
Here's a similar situation I just ran into again, somehow!

// https://godbolt.org/z/3TKG1z
struct S {};
template void f() {}
template void g() {}
int main() {
f();  // correctly errors out
g();  // incorrectly accepted by GCC
}

GCC is happy to treat `S(I)` as well-formed when `I` is a template parameter.
Obviously `decltype(S(I), void())` can't be anything because `S(I)` is
ill-formed, so I'm not sure what GCC is doing to compile this.

[Bug c++/96215] Wrong mangling for non-dependent return type involving decltype(g.x) or decltype(p->x)

2020-07-16 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96215

--- Comment #2 from Arthur O'Dwyer  ---
WG21's commentary on CWG 1273 (which is now
http://cwg-issue-browser.herokuapp.com/cwg1172
) seems completely bizarre to me. Sure, `decltype(g.x)` could theoretically
refer to a private member of `g`; but so could `decltype(g+1)` or
`decltype(*g)` or any other expression that might involve a private member.

(In `g+1`, there might be a private member `S::operator+(int)`.)

https://godbolt.org/z/ehd9fr
GCC happily accepts
template  constexpr decltype (a.i) f() { return 1; }
template  constexpr decltype (b.i) f() { return 2; }
as an overload set, but rejects
template  constexpr decltype (a+1) g() { return 3; }
template  constexpr decltype (b+1) g() { return 4; }
and also rejects
template  constexpr decltype (::i, 0) h() { return 5; }
template  constexpr decltype (::i, 0) h() { return 6; }

Clang sensibly rejects all three, all for the same reason.

Normally I'd be all for GCC injecting some implementation divergence into this
poorly specified area of the standard; but since this affects name-mangling and
thus causes GCC to be unable to link against (hypothetical) code compiled with
Clang and vice versa, I think it might be worth trying to reconcile.

To be clear: This name-mangling issue doesn't affect any real-world codebase
AFAIK. I discovered it purely by accident while messing around in Godbolt.

[Bug c++/96215] New: Wrong mangling for non-dependent return type involving decltype(g.x) or decltype(p->x)

2020-07-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96215

Bug ID: 96215
   Summary: Wrong mangling for non-dependent return type involving
decltype(g.x) or decltype(p->x)
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/z4rjjq

struct S { int x; int operator*() const; };
extern const S g;
extern const S *p;
extern int S::*m;

template
decltype(g.x) foo() { return 0; }

template
decltype(p->x) bar() { return 0; }

template int foo();
template int bar();

Clang mangles these instantiations as
_Z3fooIiEiv
_Z3barIiEiv
GCC mangles them as
_Z3fooIiEDtdtL_Z1gE1xEv
_Z3barIiEDtptL_Z1pE1xEv

Weirdly, GCC doesn't seem to have this issue with any other operators --
decltype(g+1), decltype(g.*m), etc. are all handled as synonyms for `int`. Only
dot and arrow are handled as-if-they-were-dependent-even-though-they-aren't.

[Bug c++/39970] gcc accepts the . dot operator in template arguments

2020-07-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39970

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #9 from Arthur O'Dwyer  ---
As of C++11, the original code is legitimate-ish:

struct blah { int member; };
constexpr blah global = {42};

template 
class template_blah { };

template_blah<> x;  // OK, param is 42

But:
(1) GCC still incorrectly accepts the template even when `global` is non-const.
So does MSVC. Clang correctly(?) rejects it.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213 might be related.


(2) I don't understand Brandon's original concern around mangling operator dot.
The value of the default argument here is just "42"; we don't have to mangle
the dot at all.

An example of name-mangling the dot operator would be like

template
decltype(T().x) foo() { return 0; }
struct S { int x; };
template int foo();

which GCC correctly mangles as `_Z3fooI1SEDtdtcvT__E1xEv`.

So I think the only remaining issue here is the incorrect acceptance of a
non-const default argument for `int param`, and that part MIGHT duplicate bug
#96213 which I just filed.

[Bug c++/87234] GCC should warn if template parameter redefines default argument

2020-07-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87234

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #3 from Arthur O'Dwyer  ---
Duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50370

[Bug c++/82850] g++ permits redefinition of default arguments

2020-07-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82850

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #5 from Arthur O'Dwyer  ---
Duplicate of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50370

[Bug c++/96213] New: GCC doesn't complain about ill-formed non-dependent template default argument

2020-07-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96213

Bug ID: 96213
   Summary: GCC doesn't complain about ill-formed non-dependent
template default argument
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

Possibly related (although these seem to complain about the opposite of what
I'm complaining about):
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=12672
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58071


// https://godbolt.org/z/EYzxx9
template int g;

template(0,1,2)>
void h() { }

int main() {
h<1>();
}

MSVC and Clang both reject template `h` as ill-formed, because `g(0,1,2)`
is nonsense -- `g` is an `int` and thus cannot be called like a function.

GCC accepts template `h` as well-formed, and in fact will treat this as a
SFINAE situation:

template int g;
template(42)> void h() {} // #1
template void h() {} // #2

int main() {
h<>();  // unambiguously calls #2, because #1 has a deduction failure
}

My guess is that MSVC and Clang are closer to correct here.

[Bug c++/93295] ICE in alias_ctad_tweaks

2020-05-20 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93295

Arthur O'Dwyer  changed:

   What|Removed |Added

 CC||arthur.j.odwyer at gmail dot 
com

--- Comment #6 from Arthur O'Dwyer  ---
Another test case from Peter O'Rourke on cpplang Slack:
https://godbolt.org/z/YEw4v9

template struct A {};
template A() -> A<1>;
template using B = A<2>;
B bar;

[Bug c++/94376] New: When nested inside a lambda body, [=] captures by const value instead of by value

2020-03-27 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94376

Bug ID: 94376
   Summary: When nested inside a lambda body, [=] captures by
const value instead of by value
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

David Blaikie, Richard Smith, and I discovered this GCC bug while tracking down
a separate bug in llvm::function_ref whose constructor template was improperly
SFINAEd so that construction from `const T&&` was done wrong. A GCC bug caused
construction from `const T&&` to happen on GCC but not on Clang or EDG. Here's
the reduced test case:

// https://godbolt.org/z/oCvLpv
#include 
#include 

struct I {
I() { puts(__PRETTY_FUNCTION__); }
I(I&) { puts(__PRETTY_FUNCTION__); }
I(const I&) { puts(__PRETTY_FUNCTION__); }
I(I&&) { puts(__PRETTY_FUNCTION__); }
I(const I&&) { puts(__PRETTY_FUNCTION__); }

void operator++() const {}
};

int main() {
I i;
auto one = [=]() { 
return [=]() {
++i;
};
}();
puts("-");
auto two = std::move(one);  // !!
}

On the line marked "!!", one's implicitly generated move-constructor calls
`I(const I&&)` rather than `I(I&&)` to move the captured copy of `i`. It does
this because it has improperly decided that the type of the captured copy of
`i` should be `const I` instead of plain old `I`.

Richard Smith writes:
> [expr.prim.lambda.capture]p10 is the relevant rule:
> "The type of such a data member is the referenced type
> if the entity is a reference to an object, an lvalue reference
> to the referenced function type if the entity is a reference to a function,
> or the type of the corresponding captured entity otherwise."
>
> Regardless of whether you think the captured entity is
> the original variable or the member of the outer closure type,
> the type of that entity is not const-qualified.
> So the inner capture should not have a const-qualified type.

Besides exposing bugs in llvm::function_ref (a good effect!), GCC's
implementation divergence here could have the bad effect of causing additional
expensive copies when lambdas with improperly const-qualified captures are
moved around. Example:
https://godbolt.org/z/LWEF47


Bug 86697 might be related:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86697

[Bug c++/93503] New: Duplicated warning on pure virtual implicit template in C++2a

2020-01-29 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93503

Bug ID: 93503
   Summary: Duplicated warning on pure virtual implicit template
in C++2a
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

// https://godbolt.org/z/FCqkWh
template concept A = true;
struct S {
virtual int foo(A auto) = 0;
};

g++ test.cc -std=c++2a

test.cc:3:31: error: templates may not be 'virtual'
3 | virtual int foo(A auto) = 0;
  |   ^
test.cc:3:17: error: implicit templates may not be 'virtual'
3 | virtual int foo(A auto) = 0;
  | ^~~

It is just a tiny bit suboptimal that the same warning appears twice.
The issue seems to be something about the "=0"; a virtual function with
";" or "{}" or "=delete" does not give the same duplicated warning.

[Bug libstdc++/87106] Group move and destruction of the source, where possible, for speed

2020-01-15 Thread arthur.j.odwyer at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87106

--- Comment #23 from Arthur O'Dwyer  ---
@Dan Stahlke: I believe
https://stackoverflow.com/questions/47464819/uninitialized-copy-memcpy-memmove-optimization
answers your question. Or, if it doesn't, then Marc or someone should consider
posting an answer that's better than mine... and tell me whether I should
delete my answer. :)

  1   2   >