[Bug c++/115163] New: Requesting better diagnostic for explicit constructor failure

2024-05-20 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115163

Bug ID: 115163
   Summary: Requesting better diagnostic for explicit constructor
failure
   Product: gcc
   Version: 14.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Here's a simple program:

struct C {
explicit C(int);
};

int main() {
C c = 42;
}

gcc's error for this right now is:

:6:11: error: conversion from 'int' to non-scalar type 'C' requested
6 | C c = 42;
  |   ^~

clang's error, on the other hand, is much more informative:

:6:7: error: no viable conversion from 'int' to 'C'
6 | C c = 42;
  |   ^   ~~
:1:8: note: candidate constructor (the implicit copy constructor) not
viable: no known conversion from 'int' to 'const C &' for 1st argument
1 | struct C {
  |^
:1:8: note: candidate constructor (the implicit move constructor) not
viable: no known conversion from 'int' to 'C &&' for 1st argument
1 | struct C {
  |^
:2:14: note: explicit constructor is not a candidate
2 | explicit C(int);
  |  ^

Ideally we could get something that was closer to this (i.e. given that
overload resolution succeeds and picks the explicit constructor if it were a
candidate, that's probably the right thing to tell the user):

:6:7: error: no viable conversion from 'int' to 'C'
6 | C c = 42;
  |   ^   ~~
:2:14: note: explicit constructor is not a candidate
2 | explicit C(int);
  |  ^

[Bug c++/112490] infinite meta error in reverse_iterator::iterator>>

2024-04-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112490

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #3 from Barry Revzin  ---
I ran into this also in a different direction, have been trying to reduce:

#include 

template  concept my_partially_ordered_with = requires (T t,
U u) { t < u; };
template  concept my_totally_ordered = my_partially_ordered_with;
template  concept my_totally_ordered_with =
my_totally_ordered && my_totally_ordered && my_partially_ordered_with;

template class basic_const_iterator;

namespace __detail
{
template
inline constexpr bool __is_const_iterator = false;

template
inline constexpr bool __is_const_iterator> =
true;

template
concept __not_a_const_iterator = !__is_const_iterator<_Tp>;

} // namespace detail

template
class basic_const_iterator
{
#ifdef MAKE_THIS_PUBLIC
public:
#endif
int m;

public:
template <__detail::__not_a_const_iterator _It2>
friend bool operator<(const _It2& __x, const basic_const_iterator& __y)
requires my_totally_ordered_with<_It, _It2> { return true; }
};

template 
struct wrapped
{
Iter iter;
constexpr std::strong_ordering operator<=>(const wrapped& rhs) const
noexcept;
};

bool check(wrapped> x) {
return x < x;
}


gcc rejects this with constraint recursion. clang and MSVC accept. Oddly, if
you make _M_current public, gcc trunk accepts (even though no code even
references this) while gcc 13.2 still rejects. On compiler explorer:
https://godbolt.org/z/zfvxdGneK

Trunk's rejection message is also incomplete:

: In substitution of 'template  requires 
__not_a_const_iterator<_It2> bool operator<(const _It2&, const
basic_const_iterator&) requires  my_totally_ordered_with<_It, _It2> [with
_It2 = int*]':
:3:89:   required by substitution of 'template  requires 
__not_a_const_iterator<_It2> bool operator<(const _It2&, const
basic_const_iterator&) requires  my_totally_ordered_with<_It, _It2> [with
_It2 = int*]'
3 | template  concept my_partially_ordered_with =
requires (T t, U u) { t < u; };
  |
  ~~^~~
:43:16:   required from here
   43 | return x < x;
  |^

It tells you _It2=int*, but not what _It is. 

In this case, we're comparing two objects of type
wrapped> with <, so we should have two candidates:

1. wrapped's <=>, which has no constraints
2. basic_const_iterator's friend operator<, which we start instantiating
with _It=int* and _It2=wrapped>. 

(2) requires checking if _It and _It2 can be ordered, which I think recursively
instantiates itself.

Assuming that's correct (hopefully?), I think CWG 2369 should actually cause
this to be accepted - since wrapped> is not
convertible to basic_const_iterator, that should cause (2) to be rejected
before we even consider constraints since it's not viable. 

I have no idea what the public-ness of the member changes.

[Bug c++/114589] New: missed optimization: losing bool range information

2024-04-04 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114589

Bug ID: 114589
   Summary: missed optimization: losing bool range information
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following example:

template 
struct simple_optional {
bool has_val;
T val;

auto begin() const -> T const* { return  }
#ifdef SIMPLE
auto end() const -> T const* { return  + (has_val ? 1 : 0); }
#else
auto end() const -> T const* { return has_val ?  + 1 :  }
#endif
};

void f(int);

void call_f(simple_optional const& o) {   
for (int i : o) {
f(i);
}
}

This function should call f at most one time. With the SIMPLE implementation
that adds (has_val ? 1 : 0), or simply has_val, or static_cast(has_val),
or any version thereof - gcc trunk -O3 still emits a loop:

call_f(simple_optional const&):
pushrbp
pushrbx
lea rbx, [rdi+4]
sub rsp, 8
movzx   edx, BYTE PTR [rdi]
lea rbp, [rbx+rdx*4]
testdl, dl
je  .L1
.L3:
mov edi, DWORD PTR [rbx]
add rbx, 4
callf(int)
cmp rbp, rbx
jne .L3
.L1:
add rsp, 8
pop rbx
pop rbp
ret

With the other approach, where end() explicitly returns either  + 1 or
, gcc does not emit a loop:

call_f(simple_optional const&):
cmp BYTE PTR [rdi], 0
jne .L4
ret
.L4:
mov edi, DWORD PTR [rdi+4]
jmp f(int)

On compiler explorer: https://godbolt.org/z/jaMxqsj5q

[Bug sanitizer/71962] error: ‘((& x) != 0u)’ is not a constant expression

2024-03-25 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71962

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #12 from Barry Revzin  ---
Similar failure:

struct A {
void f();
};

int main() {
constexpr auto pmf = ::f;
static_assert(pmf != nullptr); // error with UBSAN only
}

This surfaces from attempting to implement function_ref
(https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0792r14.html) which
has a constructor that takes the callable as a non-type template parameter and
static_asserts that it's not a null pointer.

Which apparently doesn't work with UBSAN.

[Bug c++/114135] New: Diagnostic missing useful information for ranges code

2024-02-27 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114135

Bug ID: 114135
   Summary: Diagnostic missing useful information for ranges code
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This is an example using Ranges:

#include 
#include 
using namespace std;

int main() {
auto rng = views::iota(0, 3);
const auto [a, b] = * ranges::min_element(views::cartesian_product(rng,
rng));
return 0;
}

This is an ill-formed program, the error given by gcc trunk is:

:7:25: error: no match for 'operator*' (operand type is
'std::ranges::borrowed_iterator_t, std::ranges::iota_view > >')
7 | const auto [a, b] = *
ranges::min_element(views::cartesian_product(rng, rng));
  |
^

This is all correct. However, it would be more helpful in this case for the
reader to also note that the type
std::ranges::borrowed_iterator_t is actually the type
std::ranges::dangling. Seeing "dangling" in the error message makes it a lot
easier to understand what the issue here actually is.

[Bug c++/104255] parsing function signature fails when it uses a function parameter outside of an unevaluated context

2024-02-26 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104255

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #8 from Barry Revzin  ---
(In reply to Patrick Palka from comment #2)
> The error message is obscure, but it seems what GCC has issue with here is
> the use of the function parameter seq2 in the trailing return type occurring
> outside of an unevaluated context.
> 
> I'm not totally sure if the testcase is valid
> (https://eel.is/c++draft/basic.scope.param#note-1 might suggest it's not?),

But we're not using the parameter for its "value" here (which I think means in
the sense of lvalue-to-rvalue conversion... as in reading a parameter of type
int), so I don't think this would be a reason to reject?

[Bug c++/114124] New: Rejected use of function parameter as non-type template parameter in trailing-return-type

2024-02-26 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114124

Bug ID: 114124
   Summary: Rejected use of function parameter as non-type
template parameter in trailing-return-type
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced from StackOverflow:

template 
struct Constant {
constexpr operator int() const noexcept { return V; }
};


template 
struct Array { };

auto function(auto s) -> Array {
return {};
}

auto const a = function(Constant<3>{});


gcc trunk rejects this example with:

:10:42: error: template argument 2 is invalid
   10 | auto function(auto s) -> Array {
  |  ^
:10:42: error: template argument 2 is invalid
:10:42: error: template argument 2 is invalid
:10:42: error: template argument 2 is invalid
:10:26: error: invalid template-id
   10 | auto function(auto s) -> Array {
  |  ^
:10:39: error: use of parameter outside function body before '+' token
   10 | auto function(auto s) -> Array {
  |   ^
:10:42: error: use of parameter outside function body before '>' token
   10 | auto function(auto s) -> Array {
  |  ^
:10:1: error: deduced class type 'Array' in function return type
   10 | auto function(auto s) -> Array {
  | ^~~~
:8:8: note: 'template struct Array' declared here
8 | struct Array { };
  |^
:14:16: error: 'function' was not declared in this scope; did you mean
'union'?
   14 | auto const a = function(Constant<3>{});
  |^~~~
  |union

But this exact equivalent formulation of function is accepted:

auto function(auto s) {
return Array{};
}

In this case, we're not actually reading the value of s to form the non-type
template argument, so this should be valid.

[Bug c++/49974] missing -Wreturn-local-addr for indirectly returning reference to local/temporary

2024-02-15 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49974

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #19 from Barry Revzin  ---
Another example of this:

int get();

int const& f() {
int const r = get();
return r;
}

int const& g() {
int const& r = get();
return r;
}

gcc trunk warns on the incorrect use in f, but it does not currently warn on
the incorrect use in g (which is the exact same bug). clang warns on both.

[Bug c++/113008] New: Trivially default constructible requires default member initializer before the end of its enclosing class

2023-12-13 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113008

Bug ID: 113008
   Summary: Trivially default constructible requires default
member initializer before the end of its enclosing
class
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This is related to bugs PR96645 and PR88165.

Consider this:

#include 

template 
struct Array {
T elems[N];
};

struct A {
struct B {
int i = 0;
};

static constexpr bool v1 = std::is_trivially_default_constructible_v;
static constexpr bool v2 =
std::is_trivially_default_constructible_v>;
};



Declaring v1 works (and it correctly evaluates to false).

Declaring v2 fails to compile entirely:

opt/compiler-explorer/gcc-trunk-20231213/include/c++/14.0.0/type_traits:3284:7:
  required from 'constexpr const bool
std::is_trivially_default_constructible_v >'
 3284 | = __is_trivially_constructible(_Tp);
  |   ^
:14:37:   required from here
   14 | static constexpr bool v2 =
std::is_trivially_default_constructible_v>;
  |
^~
/opt/compiler-explorer/gcc-trunk-20231213/include/c++/14.0.0/type_traits:3284:7:
error: default member initializer for 'A::B::i' required before the end of its
enclosing class
 3284 | = __is_trivially_constructible(_Tp);
  |   ^
:10:15: note: defined here
   10 | int i = 0;
  |   ^~~~

If we know that B isn't trivially default constructible (A::v1 is initialized
to false), then can't we likewise also know that Array isn't trivially
default constructible?

[Bug libstdc++/112591] variant allows for creating multiple empty objects at same address

2023-11-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112591

--- Comment #1 from Barry Revzin  ---
Basically, in C++17, Sub looks like this:

struct Sub17 : Empty {
aligned_membuf storage;
unsigned char index;
};

But in C++20 it turns into:

struct Sub20 : Empty {
union { Empty storage; };
unsigned char index;
};

sizeof(Sub17) == 2 because of the empty base optimization, but sizeof(Sub20) ==
3 because now the language understands that storage is an Empty and thus needs
a distinct address from the Empty base class.

[Bug libstdc++/112591] New: variant allows for creating multiple empty objects at same address

2023-11-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112591

Bug ID: 112591
   Summary: variant allows for creating multiple empty objects at
same address
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider:

#include 
#include 

struct Empty { ~Empty() {} };
struct Sub : Empty { std::variant e; };

int main() {
Sub v;

Empty* base = 
Empty* obj = ::get(v.e);

std::cout
<< "base=" << (void*)base
<< " obj=" << (void*)obj
<< " matches=" << (base == obj)
<< '\n';
}

In C++17 mode on trunk, base and obj have the same address.
In C++20 mode up through 11.4, they have the same address. Since 12.1, they do
not.

If Empty were trivially destructible, they never have the same address.

[Bug c++/112296] New: __builtin_constant_p doesn't propagate through member functions

2023-10-30 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112296

Bug ID: 112296
   Summary: __builtin_constant_p doesn't propagate through member
functions
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Here's a short example:

using size_t = decltype(sizeof(0));

struct Span {
int const* ptr;
size_t len;

inline constexpr auto size() const noexcept -> size_t { return len; }
};

inline int direct(Span span) {
return __builtin_constant_p(span.size());
}

inline int indirect(Span span) {
size_t s = span.size();
return __builtin_constant_p(s);
}

int call_direct(int const* p) {
return direct({.ptr=p, .len=8});
}

int call_indirect(int const* p) {
return indirect({.ptr=p, .len=8});
}



The functions direct() and indirect() do the same thing - try to see if span's
size is constant, with direct checking size() directly and indirect first
caching it to a local variable and checking that variable. In both cases, the
size is constant - but on -O3 call_direct() returns 0 while call_indirect()
returns 1. That is, __builtin_constant_p tells me the size is constant - but
only if I put it into a variable first. 

Checking __builtin_constant_p(span.len) also returns 1, but in the real code
the member variable is private and my only access to it is via the size()
function.

[Bug c++/111854] new (align_val_t) should be ill-formed

2023-10-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111854

--- Comment #4 from Barry Revzin  ---
The standard says this should be ill-formed.

[Bug c++/111854] New: new align_val_t usual deallocation

2023-10-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111854

Bug ID: 111854
   Summary: new align_val_t usual deallocation
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

gcc accepts this program (copied from the MSVC documentation for
https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-2/compiler-error-c2956?view=msvc-170)
without any warning or error:

#include 
struct T {};

int main()
{
T* p = new (std::align_val_t{64}) T; // C2956
delete p; // ordinary, not over-aligned delete
}

But this should be ill-formed, violating:
https://eel.is/c++draft/expr.new#28.sentence-3

[Bug c++/111538] New: Unhelpful message when returning initializer list when deducing the return type

2023-09-22 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111538

Bug ID: 111538
   Summary: Unhelpful message when returning initializer list when
deducing the return type
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider:

auto f(bool c) {
if (c) {
return 2;
} else {
return {};
}
}

This code is ill-formed, but the error gcc 13 gives is:

:5:17: error: returning initializer list
5 | return {};
  | ^

But returning an initializer list is fine... sometimes. It's just not fine
here, specifically. So would be nice if the error reflected that. Maybe
something to the effect of:

"error: returning an initializer list from a function with deduced return type
is not allowed"

[Bug c++/111485] New: Constraint mismatch on template template parameter

2023-09-19 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111485

Bug ID: 111485
   Summary: Constraint mismatch on template template parameter
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced from StackOverflow (https://stackoverflow.com/q/77136297/2069064):

template  constexpr bool regular = true;

template  concept C = regular;

template typename T> struct example { };
template typename T> using example_t = example;

gcc 13.2 rejects with:

:6:61: error: constraint mismatch at argument 1 in template parameter
list for 'template class requires  C< 
> T> struct example'
6 | template typename T> using example_t = example;
  | ^
:6:61: note:   expected 'template class requires  C<
 > T' but got 'template class requires  C<
 > T'

But this should be fine. Clang and MSVC accept. "

[Bug c++/111299] New: lack of warning on dangling reference to temporary

2023-09-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111299

Bug ID: 111299
   Summary: lack of warning on dangling reference to temporary
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following reduced example:

using size_t = decltype(sizeof(0));

template 
struct array {
T elems[N];

auto data() -> T* { return elems; }
auto data() const -> T const* { return elems; }

auto size() const -> size_t { return N; }
};

template 
struct Span {
T* p;
size_t len;

Span(T* p, size_t len) : p(p), len(len) { }

template 
Span(R&& r) : p(r.data()), len(r.size()) { }
};

struct [[gnu::packed]] X {
array value;
};

auto get_slice_ref(X const& x) {
return Span(x.value);
}

auto get_slice_ptr(X const& x) {
return Span(x.value.data(), 1);
}


Span is a heavily reduced version of std::span: no fixed extent, no
constraints, etc.

X is a packed struct with a single array member.

Neither version (get_slice_ptr or get_slice_ref) emits any warnings on gcc,
with -Wall -Wextra -Wdangling-reference. 

But the -DREF version is horribly broken. What ends up happening is that in
order to bind x.value to the reference parameter R&& r, we can't actually do
that, so instead we create a temporary initialized by copying x.value and we
bind a reference to that temporary, returning a Span pointing to... that. Which
immediately goes out of scope and we end up with a dangling Span.

You can see the broken-ness in the codegen (https://godbolt.org/z/zY77eresb).
The pointer version does the right thing:

get_slice_ptr(X const&):
mov rax, rdi
mov edx, 1
ret

The ref version gives me some garbage:

get_slice_ref(X const&):
lea rax, [rsp-12]
mov edx, 1
ret

It would be really helpful if I had any indication that something is going
wrong here.

[Bug c++/111158] New: diagnostics, colors, and std::same_as

2023-08-25 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58

Bug ID: 58
   Summary: diagnostics, colors, and std::same_as
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this broken example:

#include 

template 
struct Optional { };

auto f() -> Optional;

auto g()
#ifdef CONCEPTS
-> std::same_as> auto
#else
-> Optional
#endif
{
return f();
}

The code is wrong, g() is specifying it returns Optional but actually
returns Optional and there's no conversion.

Without concepts (just using a normal trailing return type), we get:

: In function 'Optional g()':
:15:13: error: could not convert 'f()' from 'Optional' to
'Optional'
   15 | return f();
  |~^~
  | |
  | Optional
Compiler returned: 1

Pasting it here like this actually undersells how good the error it is, because
it's actually in color, and the "int&" and "int" parts are a different color
from the Optinoal<...> part, so it really visually stands out. Very nice, gcc
devs!

With concepts (the -> std::same_as> auto approach), we get:

: In function 'auto [requires std::same_as<, Optional
>] g()':
:15:13: error: deduced return type does not satisfy placeholder
constraints
   15 | return f();
  |~^~
:15:13: note: constraints not satisfied
In file included from :1:
/opt/compiler-explorer/gcc-trunk-20230824/include/c++/14.0.0/concepts:57:15:  
required for the satisfaction of '__same_as<_Tp, _Up>' [with _Tp =
Optional; _Up = Optional]
/opt/compiler-explorer/gcc-trunk-20230824/include/c++/14.0.0/concepts:62:13:  
required for the satisfaction of 'same_as, Optional >], Optional >' [with auto
[requires std::same_as<, Optional >] = Optional]
/opt/compiler-explorer/gcc-trunk-20230824/include/c++/14.0.0/concepts:57:32:
note: the expression 'is_same_v<_Tp, _Up> [with _Tp = Optional; _Up =
Optional]' evaluated to 'false'
   57 |   concept __same_as = std::is_same_v<_Tp, _Up>;
  |   ~^~~

This isn't colored as nicely, and in general the diagnostic is I think quite a
bit worse - it contains a lot of information that simply isn't relevant to the
user. Like the fact that std::same_as is specified in this weird way in terms
of this other __same_as thing. That's an implementation detail that pretty much
never matters.

It'd be nice if gcc had dedicated diagnostics handling for std::same_as
and just wrote that T and U are different types and applied the same kind of
color highlighting that it does for the non-concepts case - which helped me a
lot to visually call out that the distinction was int vs int&. 

Link to compiler explorer, where you can see the colors with gcc 13.2:
https://godbolt.org/z/YaKjzvM98

[Bug c++/102609] [C++23] P0847R7 - Deducing this

2023-08-21 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102609

--- Comment #14 from Barry Revzin  ---
> I am finding myself realizing that implementing this as a member function and 
> turning off member function bits seems to be more difficult than implementing 
> it as a static function and implementing member function bits will be.

That's how I implemented this in EDG - static member functions that just have
some extra powers. 

> Of these cases, is f0 or f1 and g0 or g1 correct? I assume the answer is f1 
> and g1.

Both are correct - you're still a member of S, so you don't have to qualify
S::my_type (I mean, you can, it's not incorrect, but it's just not necessary -
means the same thing either way).

> When deduced, f0 or f1 and g0 or g1? I would definitely think f1 and g1 now.

These now might actually mean different things. Unqualified my_type is still
valid and means S::my_type (i.e. int). But Self::my_type could now mean a
different type. Merging the two examples:

struct S {
using my_type = int;

template
void f0(this Self, my_type);

template
void f1(this Self, Self::my_type);
};

struct D : S {
using my_type = double;
};

D().f0(2.0); // calls S::f0, which takes an int
D().f1(2.0); // calls S::f1, which takes a double

[Bug c++/110806] New: Suggest this-> for dependent base classes in more contexts

2023-07-25 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110806

Bug ID: 110806
   Summary: Suggest this-> for dependent base classes in more
contexts
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this [broken] program:

template 
struct Outer {
struct Inner {
template 
void wait(F f);
};

struct InnerD : Inner {
template 
void advance(F f) {
wait(f);
}
};

#ifdef OUTER
template 
void wait(F f);
#endif
};

void f(Outer::InnerD i) {
i.advance(42);
}

gcc's compile error is:

: In instantiation of 'void Outer::InnerD::advance(F) [with F = int;
T = int]':
:22:14:   required from here
:11:17: error: 'wait' was not declared in this scope, and no
declarations were found by argument-dependent lookup at the point of
instantiation [-fpermissive]
   11 | wait(f);
  | ^~~
:11:17: note: declarations in dependent base 'Outer::Inner' are
not found by unqualified lookup
:11:17: note: use 'this->wait' instead

This is pretty good - indicates what the problem is and suggests the correct
fix.

However, if you compile with -DOUTER, such that lookup for wait(f) ends up
finding Outer::f, you get this error:

: In instantiation of 'void Outer::InnerD::advance(F) [with F = int;
T = int]':
:22:14:   required from here
:11:17: error: cannot call member function 'void Outer::wait(F)
[with F = int; T = int]' without object
   11 | wait(f);
  | ^~~

If we had the exact same note in this context too, that'd be very helpful -
since if what you meant to call was Inner::wait, the fact that you cannot call
Outer::wait isn't really useful. Plus when the names of these types are a
little longer, the error message can be pretty confusing if you gloss over the
fact that the error is reporting that you tried to call void Outer::wait and
not void Outer::Inner::wait!

[Bug c++/110793] New: regression in optimizing unused string

2023-07-24 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110793

Bug ID: 110793
   Summary: regression in optimizing unused string
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this reduced, silly-looking example:

#include 

inline int zero(std::string const& = {}) { return 0; }

int main() {
return zero();
}

In several versions of gcc (12.2, 11.4, 10.5), this simply compiles to:

main:
xor eax, eax
ret

But in 13.1 (C++17, but not C++20), we get:

main:
sub rsp, 40
lea rax, [rsp+16]
mov rdi, rsp
mov BYTE PTR [rsp+16], 0
mov QWORD PTR [rsp], rax
mov QWORD PTR [rsp+8], 0
callstd::__cxx11::basic_string,
std::allocator >::_M_dispose()
xor eax, eax
add rsp, 40
ret

Notably, 13.1 C++20 and C++23 also compiles to just xor. 

I'm not sure if this is a language or library issue, so tagging it language for
now.

[Bug c++/109642] False Positive -Wdangling-reference with std::span-like classes

2023-06-21 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109642

--- Comment #10 from Barry Revzin  ---
Check out the report I opened for an example where the #pragma around the whole
class isn't really enough anyway - since you might want to disable the warning
for specializations of class/function templates.

[Bug c++/110358] New: requesting nicer suppression for Wdangling-reference

2023-06-21 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110358

Bug ID: 110358
   Summary: requesting nicer suppression for Wdangling-reference
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

As everyone is already aware, Wdangling-reference gives false positives for
reference-semantic classes. The compiler has special cases for the ones it
knows about, but not for mine. So:

template 
struct Span {
T* data_;
int len_;

[[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& {
return data_[n]; }
[[nodiscard]] constexpr auto front() const noexcept -> T& { return
data_[0]; }
[[nodiscard]] constexpr auto back() const noexcept -> T& { return
data_[len_ - 1]; }
};

auto get() -> Span;

auto f() -> int {
int const& a = get().front(); // warning
int const& b = get().back();  // warning
int const& c = get()[0];  // warning

return a + b + c;
}

The suppression for this is to #pragma around all my functions, which is a bit
of a tedious suppression, since this is two prefix lines and one postfix line
(but for libraries it's actually 4 prefix lines because we can't ignore
Wdangling-reference until gcc 13, so need to #ifdef that out).

It'd be nice if we could:

* add an attribute to a class to conditionally suppress the warning
* add an attribute to a function to conditionally suppress the warning
* both

Basically in this case to let me do something like:

template 
struct [[gnu::marek_is_awesome_but_this_warning_has_too_many_false_positives]]
Span {
   // ...
};

And I say conditional so that I can do this (because Optional wants to
suppress the warning, but Optional definitely does not!)

template 
struct
[[gnu::marek_is_awesome_but_this_warning_has_too_many_false_positives(std::is_reference_v)]]
Optional {
   // ...
};

Obviously I am not the best at naming.

[Bug c++/110231] New: unhelpful diagnostic when constructing through initializer_list

2023-06-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110231

Bug ID: 110231
   Summary: unhelpful diagnostic when constructing through
initializer_list
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

#include 

struct Point {
int first;
int second;
};

struct Inner {
Inner(std::initializer_list);
};

Inner i = {{.x=1, .y=1}, {.x=2, .z=2}};

This is wrong, because I wrote .z=2 instead of .y=2. The error, even on trunk,
is:

:12:38: error: could not convert '{{1, 1}, {2, 2}}' from
'' to 'Inner'
   12 | Inner i = {{.x=1, .y=1}, {.x=2, .z=2}};
  |  ^
  |  |
  |  

This gives no indication of the problem is. 

Compare that to:

Point p = {.x=2, .z=2};

which fails with the quite clear message:

:17:22: error: 'Point' has no non-static data member named 'z'
   17 | Point p = {.x=2, .z=2};
  |  ^

Even the latter could be better - if the members were first and second and I
wrote frist, it just says no member named 'frist' instead of giving a hint, but
pointing to the specific problem is significantly better than... not.

[Bug c++/110064] New: spurious missing initializer for member for anonymous

2023-05-31 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110064

Bug ID: 110064
   Summary: spurious missing initializer for member for anonymous
   Product: gcc
   Version: 13.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This program (reduced from StackOverflow:
https://stackoverflow.com/q/76375145/2069064):

struct B { };
struct D : B {
int x;
int y;
};

int main(int, char**) {
D d = {.x=1, .y=2};
(void)d;
}

with -Wall -Wextra gives a warning on:

:8:22: warning: missing initializer for member 'D::'
[-Wmissing-field-initializers]
8 | D d = {.x=1, .y=2};
  |  

But there's... no member here that isn't initialized.

[Bug libstdc++/109890] New: vector's constructor doesn't start object lifetimes during constant evaluation

2023-05-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109890

Bug ID: 109890
   Summary: vector's constructor doesn't start object lifetimes
during constant evaluation
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/76269606/2069064), clang
rejects this code when compiling with libstdc++:

#include 

consteval auto bar(int n){
std::vector v(n);
return v[0];
}
constexpr auto m = bar(5);

This is because libstdc++ basically does something like this:

#include 

class V {
int* p;
int n;
std::allocator alloc;

public:
constexpr V(int n)
: n(n)
{
p = alloc.allocate(n);

// fill with 0s?
for (int i = 0; i != n; ++i) {
p[i] = 0;
}
}

constexpr ~V() {
alloc.deallocate(p, n);
}
};

consteval auto bar(int n) {
V v(n);
return n;
}
static_assert(bar(5) == 5);

And clang is more picky about the assignment there - it doesn't like just
writing p[0] = 0, because the int's lifetime hasn't started yet. gcc accepts
the above though. 

I think that's... technically correct (if pedantic) and libstdc++'s path needs
to do a construct_at somewhere.

[Bug c++/109876] New: initializer_list not usable in constant expressions in a template

2023-05-16 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109876

Bug ID: 109876
   Summary: initializer_list not usable in constant expressions in
a template
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

#include 

template 
struct Array {

};

#ifdef USE_TEMPLATE
template 
#endif
struct Foo
{
  static constexpr std::initializer_list num = { 1, 2 };

  Array ctx;

};

#ifdef USE_TEMPLATE
void f(Foo<5>) { }
#else
void f(Foo) { }
#endif

In all recent versions of gcc, compiling with -DUSE_TEMPLATE fails with an
error like:

:15:17:   in 'constexpr' expansion of
'Foo::num.std::initializer_list::size()'
:15:19: error: the value of 'Foo::num' is not usable in a constant
expression
   15 |   Array ctx;
  |   ^

This used to work in gcc 7 and gcc 8 (except 8.1), and I don't think there's
anything about Foo being a template that should prevent this from working. The
non-template case works on all gcc versions I've tried.

[Bug c++/109715] New: abi_tag attribute is not applied to variable templates

2023-05-03 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109715

Bug ID: 109715
   Summary: abi_tag attribute is not applied to variable templates
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Given:

template 
[[gnu::abi_tag("ABI")]] inline int value = 0;

int get() {
return value;
}

gcc mangles the variable value as _Z5valueIiE, instead of
_Z5valueB3ABIIiE. That is, there is no "[abi:ABI]" tag.

clang does propagate this attribute as expected.

gcc does include the abi_tag in the mangling in other template cases (static
data member of a class template, static local variable of a function template,
etc.)

This is a related (but, I'm guessing, much easier) problem to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88061.

[Bug c++/109515] New: Diagnostic request: warning on out-of-order structured bindings names

2023-04-14 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109515

Bug ID: 109515
   Summary: Diagnostic request: warning on out-of-order structured
bindings names
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

struct div_t {
int quot;
int rem;
};

auto div(int, int) -> div_t;

int main() {
auto [rem, quot] = div(1, 2);
return quot;
}

I'm using structured bindings, but div_t's members are in the order quot then
rem, but I accidentally typed rem then quot. This is a bug! Currently, nobody
warns here though.

At the very least, if I'm:
(a) using a name in a structured binding,
(b) where we fall into the 3rd case of structured bindings (struct, not
array/tuple),
(c) the name I'm using is the name of one of the members of the type, and
(d) the structured binding is in the wrong place

I think that's a situation where a warning would have a low false-positive
rate, could be a useful -Wall (or at least -Wextra) kind of warning. 

There's a more expansive potential diagnostic, if I used names that weren't
names of members at all, but I think that sort of warning would have to be
opt-in.

[Bug libstdc++/109474] chunk_by doesn't work for ranges of proxy references

2023-04-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109474

--- Comment #2 from Barry Revzin  ---
Serves me right for only checking vector (which worked) and vector
(which didn't) and not bothering to check vector const (which also doesn't
work) and thus overly complicating the bug report.

I got too excited that vector played an important role I guess.

[Bug libstdc++/109474] New: chunk_by doesn't work for ranges of proxy references

2023-04-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109474

Bug ID: 109474
   Summary: chunk_by doesn't work for ranges of proxy references
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced example from Conor's tweet
(https://twitter.com/code_report/status/1645831980473282560):

#include 
#include 

void f(std::vector v) {
auto z = std::views::chunk_by(
v,
[](auto&& lhs, auto&& rhs){
return true;
});
auto i = z.begin();
}

This fails because the find_next implementation right now
(https://github.com/gcc-mirror/gcc/blob/0c5e64c4249322a178e1a0e843874e4d6b43b992/libstdc%2B%2B-v3/include/std/ranges#L6741-L6750)
passes a predicate into adjacent_find that requires both parameters be the same
type, but in this case indirect_binary_predicate is checking that it's
invocable with both value_type& (bool&) and reference
(vector::reference), which in this case are different types.

The original example was a zip_view of two ranges - which likewise would have
value_type& and reference be different.

[Bug c++/88061] section attributes of variable templates are ignored

2023-04-06 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88061

--- Comment #6 from Barry Revzin  ---
Any action on this one?

A workaround right now is to change code that would ideally look like (which is
pretty clean in my opinion):

template 
void foo() {
[[gnu::section(".meow")]] static int value = 0;
}

to code that looks like:

template 
void foo() {
static int PUT_IN_MEOW_value = 0;
}

and add a linker script that moves these variables over:

.meow : {
KEEP(*(SORT(.*PUT_IN_MEOW_*)))
}

But this is, to put it mildly, less than ideal.

[Bug c++/109396] New: Winit-self doesn't warn when std::move()-d

2023-04-03 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109396

Bug ID: 109396
   Summary: Winit-self doesn't warn when std::move()-d
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

In this example:

#include 

struct A {
int i_;

A(int i) : i_(i_) { }
};

struct B {
int i_;

B(int i) : i_(std::move(i_)) { }
};

Compiling on gcc trunk with -Wall -Wextra gives me these warnings:

:6:5: warning: 'A::i_' is initialized with itself [-Winit-self]
6 | A(int i) : i_(i_) { }
  | ^
:6:11: warning: unused parameter 'i' [-Wunused-parameter]
6 | A(int i) : i_(i_) { }
  |   ^
: In constructor 'B::B(int)':
:12:11: warning: unused parameter 'i' [-Wunused-parameter]
   12 | B(int i) : i_(std::move(i_)) { }
  |   ^

-Winit-self warns on the self-initialization of A::i_ but not of B::i_ (which
is just as much a self-initialization, but via std::move). 

It would be nice if -Winit-self caught the std::move (or other explicit rvalue
cast) case as well.

[Bug c++/109362] codegen adds unnecessary extra add when reading atomic member

2023-03-31 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109362

--- Comment #4 from Barry Revzin  ---
Awesome!

[Bug c++/109362] codegen adds unnecessary extra add when reading atomic member

2023-03-31 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109362

--- Comment #1 from Barry Revzin  ---
Sorry, in this reduced example, it doesn't actually consume an extra register -
only rdi is used. 

In this slightly less reduced example:

#include 

struct S {
std::atomic size;
std::atomic read_ptr;

auto peek() const -> const char* {
auto const s = size.load(std::memory_order_acquire);
return read_ptr.load(std::memory_order_acquire);
}
};

auto with_atomic(S const& v) {
while (true) {
if (v.peek()) {
return true;
}
}
}


the codegen is:

with_atomic(WithAtomic const&):
lea rdx, [rdi+8]
.L2:
mov rax, QWORD PTR [rdi]
mov rax, QWORD PTR [rdx]
testrax, rax
je  .L2
mov eax, 1
ret

which now does consume rdx unnecessarily.

[Bug c++/109362] New: codegen adds unnecessary extra add when reading atomic member

2023-03-31 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109362

Bug ID: 109362
   Summary: codegen adds unnecessary extra add when reading atomic
member
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This program:

#include 

struct S {
long size;
std::atomic read_ptr;

auto peek() const -> const char* {
return read_ptr.load(std::memory_order_acquire);
}
};

auto with_atomic(S const& v) {
while (true) {
if (v.peek()) {
return true;
}
}
}

emits (on gcc 12.2 -O3):

with_atomic(S const&):
add rdi, 8
.L2:
mov rax, QWORD PTR [rdi]
testrax, rax
je  .L2
mov eax, 1
ret

But that add is completely necessary, the mov could just be:

mov rax, QWORD PTR [rdi + 8]

which is what clang (16.0 -O3) generates:

with_atomic(S const&):# @with_atomic(S const&)
.LBB0_1:# =>This Inner Loop Header: Depth=1
mov rax, qword ptr [rdi + 8]
testrax, rax
je  .LBB0_1
mov al, 1
ret

It's not just an extra add, it's consuming an extra register - which has more
downstream optimization effects.

[Bug c++/109268] New: Guard variable still provided for static constinit variable

2023-03-23 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109268

Bug ID: 109268
   Summary: Guard variable still provided for static constinit
variable
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This program: 

struct X {
constexpr X() { }
constexpr ~X() { }
};

int main()
{
static constinit X data;
}

compiled on gcc trunk with -std=c++2b -O3 emits:

X::~X() [base object destructor]:
ret
main:
movzx   eax, BYTE PTR guard variable for main::data[rip]
testal, al
je  .L14
xor eax, eax
ret
.L14:
pushrcx
mov edi, OFFSET FLAT:guard variable for main::data
call__cxa_guard_acquire
testeax, eax
jne .L15
.L5:
xor eax, eax
pop rdx
ret
.L15:
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZZ4mainE4data
mov edi, OFFSET FLAT:_ZN1XD1Ev
call__cxa_atexit
mov edi, OFFSET FLAT:guard variable for main::data
call__cxa_guard_release
jmp .L5

But data is constant-initialized (enforced by constinit), so there shouldn't be
a need for a guard variable in this context? clang does not generate one in
this case.

[Bug c++/109222] New: Confusing error for declaring an enum class with unknown type

2023-03-20 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109222

Bug ID: 109222
   Summary: Confusing error for declaring an enum class with
unknown type
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

This program fails to compile (as it should, since the first line is commented
out):

// using i32 = int;
enum class E : i32 { red, green, blue };

But the error is... 

:2:6: warning: elaborated-type-specifier for a scoped enum must not use
the 'class' keyword
2 | enum class E : i32 { red, green, blue };
  |  ^
  |  -
:2:14: error: found ':' in nested-name-specifier, expected '::'
2 | enum class E : i32 { red, green, blue };
  |  ^
  |  ::
:2:12: error: 'E' has not been declared
2 | enum class E : i32 { red, green, blue };
  |^
:2:20: error: expected unqualified-id before '{' token
2 | enum class E : i32 { red, green, blue };
  |^

In this case I was missing an include for the typedef, but boy did that take me
a while to figure out.

[Bug c++/108953] New: inefficient codegen for trivial equality

2023-02-27 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108953

Bug ID: 108953
   Summary: inefficient codegen for trivial equality
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

#include 
#include 
#include 

struct C
{
   uint8_t a;
   uint8_t b;
   uint8_t c;
   uint8_t d;
   uint16_t e;
   uint16_t f;
   int32_t g;

   bool operator==(C const&) const = default;
};

bool check(C const& lhs, C const& rhs) {
#ifdef MEMCMP
return memcmp(, , sizeof(lhs)) == 0;
#else
return lhs == rhs;
#endif
}

There are two implementations of check here, but lead to suboptimal code.

When using MEMCMP, gcc trunk -O3 emits:

check(C const&, C const&):
mov rax, QWORD PTR [rsi]
cmp QWORD PTR [rdi], rax
je  .L5
.L2:
mov eax, 1
testeax, eax
seteal
ret
.L5:
mov eax, DWORD PTR [rsi+8]
cmp DWORD PTR [rdi+8], eax
jne .L2
xor eax, eax
testeax, eax
seteal
ret

There's a few extra instructions here (mov eax, 1; test eax, eax; sete al;...
do we need all three of those to return 0?)

When using defaulted comparisons, gcc trunk -O3 doesn't collapse any of the
comparisons, and instead emits 7 distinct checks:

check(C const&, C const&):
movzx   ecx, BYTE PTR [rsi]
xor eax, eax
cmp BYTE PTR [rdi], cl
jne .L1
movzx   edx, BYTE PTR [rsi+1]
cmp BYTE PTR [rdi+1], dl
jne .L1
movzx   edx, BYTE PTR [rsi+2]
cmp BYTE PTR [rdi+2], dl
jne .L1
movzx   edx, BYTE PTR [rsi+3]
cmp BYTE PTR [rdi+3], dl
jne .L1
movzx   edx, WORD PTR [rsi+4]
cmp WORD PTR [rdi+4], dx
jne .L1
movzx   eax, WORD PTR [rsi+6]
cmp WORD PTR [rdi+6], ax
mov edx, DWORD PTR [rsi+8]
seteal
cmp DWORD PTR [rdi+8], edx
setedl
and eax, edx
.L1:
ret

Compare this to clang, which for both the memcmp and the default equality
versions emits this:

check(C const&, C const&):# @check(C const&, C const&)
mov rax, qword ptr [rdi]
xor rax, qword ptr [rsi]
mov ecx, dword ptr [rdi + 8]
xor ecx, dword ptr [rsi + 8]
or  rcx, rax
seteal
ret

Looks like there are two missing optimizations here for gcc: (1) the memcmp
does get optimized into an 8-byte and 4-byte comparison, but then the result of
that optimization doesn't get optimized further and (2) multiple trivial
comparisons don't get coalesced together.

[Bug libstdc++/108823] New: ranges::transform could be smarter with two sized ranges

2023-02-16 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108823

Bug ID: 108823
   Summary: ranges::transform could be smarter with two sized
ranges
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/75464599/2069064):

#include 
#include 
#include 

#include 
#include 
#include 

std::vector fn1(std::vector u, std::vector const& v) {
#ifdef RANGES
std::ranges::transform(u, v, u.begin(), std::plus{});
#else
std::transform(u.begin(), u.end(), v.begin(), u.begin(), std::plus{});
#endif
return u;
}

Without RANGES defined, this generates vectorized code. With RANGES, it does
not. These aren't exactly identical, since without RANGES the function is UB if
u.size() > v.size() while with RANGES it's fine - but the RANGES implementation
is still suboptimal.

Rewriting the RANGES impl to:

auto sz = std::min(u.size(), v.size());
std::ranges::transform(
std::ranges::subrange(u.begin(), u.begin() + sz),
std::ranges::subrange(v.begin(), std::unreachable_sentinel),
u.begin(),
std::plus{});

gets the code to vectorize again. This is probably because the loop is simply:

»···for (; __first1 != __last1 && __first2 != __last2;
»··· ++__first1, (void)++__first2, ++__result)

The two conditions probably throws the optimizer, where if the algorithm is
written as a single condition (as the rewrite reduces to, since __first2 !=
__last2 becomes true), it's easier to optimize.

[Bug c++/108744] error message when trying to use structured bindings in static member declaration could be cleaner

2023-02-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108744

--- Comment #3 from Barry Revzin  ---
Yeah, they're banned in non-static data members also. But there, we just can't
have any "auto" non-static data members, whereas you can have "auto" static
data members (just not structured bindings).

[Bug c++/108744] New: error message when trying to use structured bindings in static member declaration could be cleaner

2023-02-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108744

Bug ID: 108744
   Summary: error message when trying to use structured bindings
in static member declaration could be cleaner
   Product: gcc
   Version: 13.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider:

struct X {
int i, j;
};

struct C {
static auto [a, b] = X{1, 2};
};


This is ill-formed, but the error is currently:

:6:17: error: expected unqualified-id before '[' token
6 | static auto [a, b] = X{1, 2};
  | ^

clang, in contrast, says:

:6:17: error: decomposition declaration not permitted in this context
static auto [a, b] = X{1, 2};
^~

Which is a lot clearer. I think ideally the error states explicitly that
structured bindings can't be used in static data member declarations.

[Bug c++/105200] user-defined operator <=> for enumerated types is ignored

2022-12-30 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #6 from Barry Revzin  ---
This strikes me as a definite wording issue rather than actual design intent.
Patrick is correct as to what the wording says - it says non-member candidate,
so the rewritten candidates don't count. But I think really we should also
consider rewritten candidates. Clang and MSVC both do - which seems much more
in line with expectation and the original design.

For class types, you can just provide <=>, but for enums, you have to provide
<, >, <=, >=, and <=>?? 

I'm opening a Core issue for this: https://github.com/cplusplus/CWG/issues/205

[Bug c++/106667] New: Diagnosing misuses of capturing lambda coroutines

2022-08-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106667

Bug ID: 106667
   Summary: Diagnosing misuses of capturing lambda coroutines
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following example using std::generator from P2502 (sorry the
example isn't super reduced, https://godbolt.org/z/b4vj7E7d1): 

int main() {
int lo = 10;
int hi = 20;

auto gen = [=]() -> std::generator {
for (int i = lo; i != hi; ++i) {
co_yield i;
}
}();

for (int i : gen) {
printf("%d\n", i);
}
}

This usage is bad! The lambda captures lo and hi, the coroutine is going to
capture a reference to the lambda, which then gets destroyed. Then we attempt
to access the coroutine, which attempts to read the dead lambda's captures.

ASAN flags the first iteration of that loop as stack-use-after-scope.

Is this situation in general statically diagnosable? The situation here is we
have:

1. A coroutine that is a non-static member function
2. That initially suspends
3. And has non-static data members that are used in the body (or, for lambdas,
captures) 
4. And the coroutine outlives the class instance

This will probably be a more common bug in lambdas, specifically, than other
kinds of non-static member functions. This is specifically Core Guideline CP.51
(https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rcoro-capture).

[Bug c++/106631] New: Unhelpful diagnostic on variable template specialization with unknown name

2022-08-15 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106631

Bug ID: 106631
   Summary: Unhelpful diagnostic on variable template
specialization with unknown name
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Short example:

template 
constexpr bool trait = true;

template <>
constexpr bool triat = false;

Note the typo on triat.

The current error message gcc provides is:

:5:21: error: expected initializer before '<' token
5 | constexpr bool triat = false;
  | ^

Which is... technically true. Given that triat doesn't exist as a variable
template, the next thing coming up needs to be an initializer for it, since
this is really a declaration. But the intent was for it to specialize trait -
it seems like it's more likely that this kind of error would come from getting
the name of the variable template wrong rather than spelling the initializer
incorrectly?

So something like:

:5:21: error: unknown variable template 'triat' being specialized
5 | constexpr bool triat = false;
  |^
note: did you mean trait?

Would be much more helpful.

[Bug c++/106596] New: Not a helpful diagnostic when putting things out of order in a member function

2022-08-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106596

Bug ID: 106596
   Summary: Not a helpful diagnostic when putting things out of
order in a member function
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

template  concept C = true;

template 
struct Widget {
void foo() requires C noexcept;  
};

The issue here is that the noexcept needs to go before the requires clause, but
how many people really remember what the order of these things needs to be?

The gcc 12.1 error for this is:

:5:25: error: expected ';' at end of member declaration
5 | void foo() requires C noexcept;
  | ^~~~
  | ;
:5:30: error: expected unqualified-id before 'noexcept'
5 | void foo() requires C noexcept;
  |  ^~~~

I suspect this might be a difficult thing to provide a diagnostic for, but this
particular one is pretty unhelpful. The first one is suggesting I needed to
write void foo() requires; which isn't even valid.

Hypothetical ideal:

:5:30: error: the noexcept-specifier needs to precede the
requires-clause
5 | void foo() requires C noexcept;
  |^ ^~~~
  |noexcept requires C;

[Bug c++/106371] New: Bogus narrowing conversion reported due to bitfield

2022-07-20 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106371

Bug ID: 106371
   Summary: Bogus narrowing conversion reported due to bitfield
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider:

#include 

struct A {
  uint64_t x : 32;
};

struct B {
  uint32_t x;
};

void f() {
auto a = A{.x = 1};
auto b = B{.x = a.x};
}

gcc currently emits a narrowing warning here:

:13:24: warning: narrowing conversion of '(long unsigned int)a.A::x'
from 'long unsigned int' to 'uint32_t' {aka 'unsigned int'} [-Wnarrowing]
   13 | auto b = B{ .x = a.x };
  |  ~~^

It is true that a.x is a uint64_t, but also it's only a 32-bit bitfield, there
isn't actually any narrowing possible. This code should be fine. 

clang doesn't warn here (only if A::x were actually a uint64_t, or the width of
the bitfield was larger than 32).

[Bug c++/106354] New: Diagnostic could be more user friendly

2022-07-19 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106354

Bug ID: 106354
   Summary: Diagnostic could be more user friendly
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider:

template 
constexpr bool some_check() {
return true;
}

struct C { };

static_assert(some_check::value);

This is (obviously) wrong: some_check is a function template, not a type trait,
so the correct way to validate it is some_check() and not
some_check::value. But there's a lot of code uses type traits, so this sort
of thing happens.

gcc 12 tells me:

:8:15: error: function template-id 'some_check' in
nested-name-specifier
8 | static_assert(some_check::value);
  |   ^
:2:16: note: 'template constexpr bool some_check()' declared
here
2 | constexpr bool some_check() {
  |^~

Now, technically, this is all... correct. You can't use a function template-id
in a nested-name-specifier, and the error does point me to the declaration of
the function template in question which helped me realize my error. 

But it'd be nice to provide this error in less grammatical terms (especially
since the problem here was that I didn't realize some_check was a function
template). Maybe something like:

error: can only access nested names on class types or namespaces, but
some_check is a function template.

This can probably be improved further.

[Bug c++/106176] New: Compiler diagnostic doesn't show where it's coming from in my code

2022-07-03 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106176

Bug ID: 106176
   Summary: Compiler diagnostic doesn't show where it's coming
from in my code
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following program, carefully reduced from real code:

#include 

// template  using which = std::map;
template  using which = T;

struct C
{
C();
~C() = default;

static C create();   

struct M
{
M(M&&) = default;
};

which member;
};

C C::create()
{
C c;
return c;
}

This, when compiled with gcc 12.1 -std=c++20 emits
(https://godbolt.org/z/YhfzWTjKq):

: In static member function 'static C C::create()':
:24:12: error: use of deleted function 'C::C(const C&)'
   24 | return c;
  |^
:6:8: note: 'C::C(const C&)' is implicitly deleted because the default
definition would be ill-formed:
6 | struct C
  |^
:6:8: error: use of deleted function 'constexpr C::M::M(const C::M&)'
:13:12: note: 'constexpr C::M::M(const C::M&)' is implicitly declared
as deleted because 'C::M' declares a move constructor or move assignment
operator
   13 | struct M
  |^
Compiler returned: 1

This diagnostic (a) points to the offending line in my code, precisely, and (b)
explains what the problem is. That's pretty good. It could be better: the real
problem here is that C's explicitly default destructor inhibited the
compiler-generated move constructor, why is why the copy is a problem to begin
with. 

If we change the definition of the member from M to std::map (by
changing which declaration of which is commented), nothing really changes about
this program - we still have a move-only member, so this is broken since C is
missing the move constructor, etc. However, the new diagnostic becomes
(https://godbolt.org/z/9TG3WK75G):

In file included from
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ext/alloc_traits.h:34,
 from
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:67,
 from
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/map:60,
 from :1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/alloc_traits.h: In
instantiation of 'static constexpr void
std::allocator_traits >::construct(allocator_type&, _Up*,
_Args&& ...) [with _Up = std::pair; _Args = {const
std::pair&}; _Tp = std::_Rb_tree_node >; allocator_type = std::allocator > >]':
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:595:32:  
required from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::_M_construct_node(_Link_type, _Args&& ...) [with _Args = {const
std::pair&}; _Key = int; _Val = std::pair;
_KeyOfValue = std::_Select1st >; _Compare =
std::less; _Alloc = std::allocator >;
_Link_type = std::_Rb_tree_node >*]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:612:21:  
required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const
std::pair&}; _Key = int; _Val = std::pair;
_KeyOfValue = std::_Select1st >; _Compare =
std::less; _Alloc = std::allocator >;
_Link_type = std::_Rb_tree_node >*]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:529:32:  
required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_Alloc_node::operator()(_Arg&&) const [with _Arg = const
std::pair&; _Key = int; _Val = std::pair;
_KeyOfValue = std::_Select1st >; _Compare =
std::less; _Alloc = std::allocator >;
std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type =
std::_Rb_tree_node >*]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:645:18:  
required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_M_clone_node(_Link_type, _NodeGen&) [with bool _MoveValue =
false; _NodeGen = std::_Rb_tree,
std::_Select1st >, std::less,
std::allocator > >::_Alloc_node; _Key = int; _Val =
std::pair; _KeyOfValue = std::_Select1st >; _Compare = std::less; _Alloc = std::allocator >; _Link_type = std::_Rb_tree_node >*]'
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/stl_tree.h:1895:47:  
required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_M_copy(_Link_type, _Base_ptr, _NodeGen&) [with bool
_MoveValues = false; _NodeGen = std::_Rb_tree,
std::_Select1st >, std::less,
std::allocator > >::_Alloc_node; _Key = int; _Val =
s

[Bug c++/106151] Inconsistent optimization when defaulting aggregate vs non-aggregate

2022-06-30 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106151

--- Comment #2 from Barry Revzin  ---
I guess that's like:

C++11/14: neither is an aggregate (base class).
C++17: both are aggregates.
C++20: Bar is an aggregate, but Foo is not (user-declared constructor).

But that really shouldn't affect the code-gen here? (right???)

[Bug c++/106151] New: Inconsistent optimization when defaulting aggregate vs non-aggregate

2022-06-30 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106151

Bug ID: 106151
   Summary: Inconsistent optimization when defaulting aggregate vs
non-aggregate
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

using size_t = decltype(sizeof(0));

struct string_view {
// string_view() : ptr(nullptr), len(0) { }
string_view() = default;

char const* ptr = nullptr;
size_t len = 0;
};

struct Fields
{
string_view a;
string_view b;
string_view c;
string_view d;
string_view e;
string_view f;
};

struct Foo : Fields
{
void clear();

Foo() = default;
};

void Foo::clear() {
*this = Foo{};
}

struct Bar : Fields
{
// No constructor, not even defaulted.

void clear();
};

void Bar::clear() {
*this = Bar{};
}


On gcc 12.1 -std=c++20 -O2 -mavx2, this emits:

Foo::clear():
mov QWORD PTR [rdi], 0
mov QWORD PTR [rdi+8], 0
mov QWORD PTR [rdi+16], 0
mov QWORD PTR [rdi+24], 0
mov QWORD PTR [rdi+32], 0
mov QWORD PTR [rdi+40], 0
mov QWORD PTR [rdi+48], 0
mov QWORD PTR [rdi+56], 0
mov QWORD PTR [rdi+64], 0
mov QWORD PTR [rdi+72], 0
mov QWORD PTR [rdi+80], 0
mov QWORD PTR [rdi+88], 0
ret
Bar::clear():
mov ecx, 12
xor eax, eax
rep stosq
ret

There are a lot of subtle changes you can make to change the generated code:

* if Fields has 3 members or fewer, it's a bunch of mov's either way
* if Fields has 4 or 5 members, Bar::clear uses vmov insead of mov. 
* if Fields has 6+ members, Bar::clear uses stosq
* if Fields has an array of string_view, Foo::clear and Bar::clear are
identical for sizes 2, 3, and >= 9.

If string_view uses the constructor I have commented out (with the member
initializer list, instead of defaulted and using the default member
initializers, then:
* if Fields holds an array of string_view with at least 4 string_views, both
Foo::clear and Bar::clear emit a loop.
* otherwise, it's always a bunch of mov's for both Foo and Bar, regardless of
how many members. 


Feels like something is up here.

[Bug c++/105903] New: Missed optimization for __synth3way

2022-06-08 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105903

Bug ID: 105903
   Summary: Missed optimization for __synth3way
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example:

#include 
#include 

inline constexpr auto synth3way = std::__detail::__synth3way;

struct Iterator {
std::vector::iterator it;

constexpr bool operator<(Iterator const& rhs) const {
return it < rhs.it;
}
constexpr bool operator>(Iterator const& rhs) const {
return it > rhs.it;
}
};

bool less(Iterator const& a, Iterator const& b) {
return a < b;
}

bool less3way(Iterator const& a, Iterator const& b) {
return synth3way(a, b) < 0;
}

Here, synth3way(a, b) < 0 produces identical code to a < b (compiling with gcc
12.1 --std=c++20 -O3), which is great. The compiler recognizes that it doesn't
have to do the second synthesized comparison. 

However, if we instead compared (sorry):

bool greater(Iterator const& a, Iterator const& b) {
return a > b;
}

bool greater3way(Iterator const& a, Iterator const& b) {
return synth3way(a, b) > 0;
}

This is now much worse:

greater(Iterator const&, Iterator const&):
mov rax, QWORD PTR [rdi]
cmp QWORD PTR [rsi], rax
setbal
ret
greater3way(Iterator const&, Iterator const&):
mov rdx, QWORD PTR [rdi]
mov rcx, QWORD PTR [rsi]
xor eax, eax
cmp rdx, rcx
jb  .L3
cmp rcx, rdx
setbal
.L3:
ret

Interestingly, if we write this out:

bool greater3way(Iterator const& a, Iterator const& b) {
auto const cmp = [&]{
if (a < b) return std::weak_ordering::less;
if (b < a) return std::weak_ordering::greater;
return std::weak_ordering::equivalent;
}();
return cmp > 0;
}

bool greater3way_fold(Iterator const& a, Iterator const& b) {
return [&]{
if (a < b) return false;
if (b < a) return true;
return false;
}();
}

The greater3way_fold implementation generates the same code as >, which
definitely suggests to me that the greater3way version is simply a missed
optimization. 

On compiler explorer: https://godbolt.org/z/1xvfsMrnf

Because synth3way is only used in contexts that require a weak ordering anyway,
it would be a valid optimization to replace synth3way(a, b) > 0 with b < a,
synth3way(a, b) <= 0 with !(b < a) and synth3way(a, b) >= 0 with !(a < b).
These replacements aren't generally true (because partial orders), but the
precondition on this type is that we have a weak order, so we should be able to
do better.

[Bug c++/105840] confusing diagnostic when naming the wrong class in a constructor

2022-06-03 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105840

--- Comment #2 from Barry Revzin  ---
I think something to this effect maybe?

:9:7: error: attempting to declare constructor for unrelated class 'A';
did you mean to use 'B'?
9 | A(int i);
  | ^~
  | B

[Bug c++/105840] New: confusing diagnostic when naming the wrong class in a constructor

2022-06-03 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105840

Bug ID: 105840
   Summary: confusing diagnostic when naming the wrong class in a
constructor
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

In this code:

template  struct X { };

struct A {
A(int i);
A(X x);
};

struct B {
A(int i);
A(X x);
};

I was copying the constructors from A into B, and forgot to change the name.
This is, indeed, ill-formed.

However, this is what gcc tells me:

:9:7: error: expected unqualified-id before 'int'
9 | A(int i);
  |   ^~~
:9:7: error: expected ')' before 'int'
9 | A(int i);
  |  ~^~~
  |   )
:10:14: error: invalid declarator before 'x'
   10 | A(X x);
  |  ^
:10:13: error: expected ')' before 'x'
   10 | A(X x);
  |  ~  ^~
  | )

Clang does at least point me to the A, but otherwise provides a
differently-confusing diagnostic about the parentheses?

:9:7: error: expected member name or ';' after declaration specifiers
A(int i);
~ ^
:9:7: error: expected ')'
:9:6: note: to match this '('
A(int i);
 ^
:10:14: error: expected ')'
A(X x);
 ^
:10:6: note: to match this '('
A(X x);
 ^
:10:7: error: member 'X' cannot have template arguments
A(X x);
  ^~

[Bug c++/53281] poor error message for calling a non-const method from a const object

2022-05-24 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53281

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #14 from Barry Revzin  ---
Following up on this (and a lot of the ideas presented here are I think better
than "passing [...] discards qualifiers")...

This:

struct B {
void f();
}; 

struct D : B {
void const_f() const {
f();
}
};

gives me that same error:

:8:10: error: passing 'const D' as 'this' argument discards qualifiers
[-fpermissive]
8 | f();
  | ~^~
:2:10: note:   in call to 'void B::f()'
2 | void f();
  |  ^

But this slight difference (D is now a template, though B is a non-dependent
base):

struct B {
void f();
}; 

template 
struct D : B {
void const_f() const {
f();
}
};

instead emits: 

:8:10: error: cannot convert 'const D*' to 'B*'
8 | f();
  | ~^~
:2:10: note:   initializing argument 'this' of 'void B::f()'
2 | void f();
  |  ^

Which is... technically correct, that is the problem, but now that I'm used to
seeing the "discards qualifiers" error, this one really threw me for a loop. 

It'd be nice at the very least if these two examples gave the same error

[Bug c++/105672] Print note when unable to convert between types with the same name but different scopes

2022-05-20 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105672

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #2 from Barry Revzin  ---
My suggestion is more to line up the fronts of the types:

vt.C:276:15: error: conversion requested
from: std::tuple
  to: tuple

And drop the "non-scalar type" part - does it add anything meaningful to the
diagnostic? I already know tuple<...> isn't a scalar (and if I didn't, would it
help?)

But what Mr. Wakely indicated also works - basically any presentation where the
'from' and 'to' types are on separate lines and similarly formatted makes it
easier to see what's up.

[Bug c++/102774] Stop showing "error: variable or field ‘f’ declared void" after an earlier error in a declarator

2022-05-18 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102774

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #1 from Barry Revzin  ---
Was just filing a bug for the same problem. Here's a short repro:

namespace A::B {
struct X { void use(); };
}

void f(B::X x, int j) {
x.use();
}

The error I get is:

:5:6: error: variable or field 'f' declared void
5 | void f(B::X x, int j) {
  |  ^
:5:8: error: 'B' has not been declared
5 | void f(B::X x, int j) {
  |^
:5:16: error: expected primary-expression before 'int'
5 | void f(B::X x, int j) {
  |^~~

The middle error is the real problem, the first and third are... quite
unhelpful! In some cases, the third error looks more like this:

:7:18: error: expected primary-expression before 'j'
7 | void f(B::X x, Y j) {
  |  ^

Which is equivalently unhelpful.

[Bug c++/105268] New: type/value mismatch when using variadic concept

2022-04-13 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105268

Bug ID: 105268
   Summary: type/value mismatch when using variadic concept
   Product: gcc
   Version: 11.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/71864544/2069064):

template concept C_one = true;
template concept C_many = true;

template struct S { };

template>> void f();  // ok
template>> void g(); // error

gcc rejects the declaration of g with:


:7:35: error: type/value mismatch at argument 1 in template parameter
list for 'template struct S'
7 | template>> void g();
  |   ^~
:7:35: note:   expected a constant of type 'bool', got
''

But C_many is a bool, so this should be fine. And template-parameter-1-1
isn't a very useful diagnostic anyway.

[Bug c++/105195] New: spurious warning label defined but not used with if constexpr

2022-04-07 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105195

Bug ID: 105195
   Summary: spurious warning label defined but not used with if
constexpr
   Product: gcc
   Version: 11.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Similar to other "if constexpr" related warnings, gcc warns on this example:

void g();
void h();

template 
void f() {
if constexpr (B) {
goto label;
}

g();

label:
h();
}

int main() {
f();
}

:12:1: warning: label 'label' defined but not used [-Wunused-label]
   12 | label:
  | ^

But the label is used, just not in this particular instantiation.

[Bug other/92396] -ftime-trace support

2022-03-29 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92396

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #11 from Barry Revzin  ---
+1 to supporting this. gcc's existing -ftime-report is useful for being able to
make statements like "gcc 11 is substantially more efficient at constraint
satisfaction than gcc 10 was" (nice job, folks!) but it isn't very useful for
being able to answer questions like "this translation unit takes 90 seconds to
compile, how can I improve that?" Clang's -ftime-trace, on the other hand,
gives me granular data per function -- which can help me determine what the hot
spots are, etc.

[Bug c++/105059] New: Inconsistency between paren- and brace-initialization of a union with anonymous struct

2022-03-25 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105059

Bug ID: 105059
   Summary: Inconsistency between paren- and brace-initialization
of a union with anonymous struct
   Product: gcc
   Version: 11.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

union U {
struct {
int x;
int y;
};
long all;
};

constexpr long parens() {
U u(42);
return u.all;
}
static_assert(parens() == 42);

constexpr int braces() {
U u{42};
return u.all;
}
static_assert(braces() == 42);

gcc currently considers parens() to be a valid constant expression with value
42 (i.e. U(42) initializes U::long) but considers braces() to be invalid
because of reading the wrong member of the union (i.e. U{42} initializes U::x).

clang currently considers parens() ill-formed by rejecting U(42) entirely (and
then rejects braces() for the same reason as gcc does, because it's u.x that
was initialized). 

The standard doesn't even talk about anonymous structs so it's hard to say what
the "right answer" here is, but it seems to me that either U(42) should do the
same thing as U{42} here or at the very least be ill-formed, but definitely not
do some different valid thing.

[Bug c++/95153] Arrays of 'const void *' should not be copyable in C++20

2022-03-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95153

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #5 from Barry Revzin  ---
Just to follow up, gcc trunk right now does this:

int main() {
int a[3]{};
void const* b[3](a);  // ok

void const* c[3]{};
void const* d[3](c);  // error: array must be initialized with a
brace-enclosed initializer
}

If 'd' is actually an error, then it's not because of that, so at the very
least, the diagnostic is wrong.

[Bug libstdc++/104858] New: ranges::minmax double dereferences first

2022-03-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104858

Bug ID: 104858
   Summary: ranges::minmax double dereferences first
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

In
https://github.com/gcc-mirror/gcc/blob/bded0d549fdfdc1328b2c0189dc5f8593b4cbe42/libstdc%2B%2B-v3/include/bits/ranges_algo.h#L3087:

the initial result is constructed as:

minmax_result> __result = {*__first, *__first};

If *__first performs actually does work (maybe it's a transformed iterator),
then this is wasteful. But more importantly, if *__first gives you an rvalue
reference, then this moves from that iterator twice.

I think the standard requires ranges::minmax(v | views::as_rvalue) to actually
be valid (assuming an as_rvalue adaptor that ensures that the reference type is
an rvalue).

[Bug c++/88061] section attributes of variable templates are ignored

2022-03-08 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88061

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #5 from Barry Revzin  ---
(In reply to Richard Biener from comment #1)
> Some things do not make very much sense for C++...

I disagree. This definitely makes sense for C++ and it is disappointing that it
doesn't work. 

For instance, this works:

[[gnu::used, gnu::section(".my_data")]] inline int data_int;
[[gnu::used, gnu::section(".my_data")]] inline double data_double;

int& get() {
return data_int;
}

The C++ analogue, necessary for contexts where I may not be able to spell the
type in advance, would be this (or a static data member of a class template,
same thing):

template 
[[gnu::used, gnu::section(".my_data")]] inline T data{};

int& get() {
return data;
}

Except the latter puts data into .bss.data, while the former puts it
into .my_data. clang respects the section attribute
(https://godbolt.org/z/7137EbxsW), gcc does not
(https://godbolt.org/z/548YKjhzn).

[Bug c++/104803] if consteval error from branch that isn't evaluated anyway

2022-03-07 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104803

--- Comment #6 from Barry Revzin  ---
Ugh, sorry. You guys are right. gcc is correct to reject the example. Bad bug
report.

[Bug c++/104803] if consteval error from branch that isn't evaluated anyway

2022-03-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104803

--- Comment #4 from Barry Revzin  ---
For instance, clang accepts this version:

consteval int p(int i) {
return i > 2;
}

constexpr auto none_of(int const* f, int const* l) -> bool {
for (; f != l; ++f) {
int i = *f;
if consteval {
if (p(i)) {
return false;
}
} else {
return false;
}
}
return true;
}

constexpr int vals[] = {1, 0, -1};
static_assert(none_of(vals, vals+3));

But not if you change none_of to be a template (in any way, e.g. taking f and l
as auto).

[Bug c++/104803] if consteval error from branch that isn't evaluated anyway

2022-03-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104803

--- Comment #3 from Barry Revzin  ---
clang is also wrong. p(i) doesn't have to be a constant expression there. The
rule (http://eel.is/c++draft/expr.const#13) is "An immediate invocation shall
be a constant expression." but an expression is only an immediate invocation if
it's not in an immediate function context, and the first branch of if consteval
is an immediate function context.

[Bug c++/104803] New: if consteval error from branch that isn't evaluated anyway

2022-03-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104803

Bug ID: 104803
   Summary: if consteval error from branch that isn't evaluated
anyway
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider this example. Yes, the body of none_of here looks... extremely
bizarre. Just bear with me.

template 
constexpr auto none_of(R&& r, P p) -> bool {
for (int i : r) {
if consteval {
if (p(i)) { // <== line 5
return false;
}
} else {
if (p(i)) { // <== line 9
return false;
}
}
}
return true;
}

constexpr int vals[] = {1, 0, -1};
static_assert(none_of(vals,
[](int i) consteval {
return i > 2;
}));

This does not compile, with the error (https://godbolt.org/z/dEq3381ac):

: In instantiation of 'constexpr bool none_of(R&&, P) [with R = const
int (&)[3]; P = ]':
:18:22:   required from here
:9:19: error: the value of 'i' is not usable in a constant expression
9 | if (p(i)) {
  |   ^
:3:14: note: 'int i' is not const
3 | for (int i : r) {
  |  ^
Compiler returned: 1

The error is on line 9. That's the second part of the if consteval, the "else"
part. That's not even supposed to be evaluated here, since we're in a
static_assert. If I replace it with 'return false':

template 
constexpr auto none_of(R&& r, P p) -> bool {
for (int i : r) {
if consteval {
if (p(i)) {
return false;
}
} else {
return false;
}
}
return true;
}

constexpr int vals[] = {1, 0, -1};
static_assert(none_of(vals,
[](int i) consteval {
return i > 2;
}));

This compiles (https://godbolt.org/z/od93dEMf8). If 'return false;' in the else
branch were executed, this would've failed. But it's (correctly) not.

Something about the if consteval machinery is incorrectly evaluating the wrong
branch and failing as a result.

[Bug c++/71283] Inconsistent location for C++ warning options in the manual

2022-03-04 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71283

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #17 from Barry Revzin  ---
(In reply to Andrew Pinski from comment #2)
> That is because this is C++ only option.  It is listed under
> https://gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/C_002b_002b-Dialect-Options.
> html#C_002b_002b-Dialect-Options :
> 
> -Wno-terminate (C++ and Objective-C++ only)
> Disable the warning about a throw-expression that will immediately result in
> a call to terminate.
> 
> This is exact location for all other C++ only options are located.
> 
> So not a bug.

Sure, but right now some warnings are under Warning Options and others are
under Dialect Options. I would never think to look for warnings under dialect
options, since my initial thought would be that the latter is for the kinds of
things that show up first on that page... -fabi-version, -fchar8_t, etc. You
have to go pretty far down that page to get to warnings. -Wsuggest-override
used to be under Warning Options, was recently moved to Dialect Options for
instance. 

I would like to request that either all the warning options are documented
under warning options, or that there is one page for all the C++ warning
options (as distinct from "dialect options"), or something else along those
lines. The current split is a bit confusing and makes it hard to find warnings.

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

2022-02-23 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68350

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #8 from Barry Revzin  ---
Here's an example:

struct A { int i; };
struct B { int i{}; };

Both are trivially copyable, A is additionally trivially default constructible
while B is not. This distinction is irrelevant in this case - we're copying,
and that does not involve default constructing an A or B (trivial or
otherwise).

But this means that __is_trivial(B) is false, so we don't go into std::copy, so
these do different things:

#include 

struct A { int i; };
struct B { int i{}; };

void copy_a(A* f, A* l, A* out) {
std::uninitialized_copy(f, l, out);
}

void copy_b(B* f, B* l, B* out) {
std::uninitialized_copy(f, l, out);
}

emits (with g++ 11.2, -std=c++20 -O3, https://godbolt.org/z/eG9hsbcTE):

copy_a(A*, A*, A*):
mov r8, rdi
mov rdi, rdx
cmp r8, rsi
je  .L1
mov rdx, rsi
mov rsi, r8
sub rdx, r8
jmp memmove
.L1:
ret
copy_b(B*, B*, B*):
cmp rdi, rsi
je  .L4
sub rsi, rdi
xor eax, eax
.L6:
mov ecx, DWORD PTR [rdi+rax]
mov DWORD PTR [rdx+rax], ecx
add rax, 4
cmp rax, rsi
jne .L6
.L4:
ret

Whereas the copy_b case could also use memmove.

[Bug libstdc++/103919] New: The basic_string(const T&, size_type, size_type) constructor is overconstrained

2022-01-05 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103919

Bug ID: 103919
   Summary: The basic_string(const T&, size_type, size_type)
constructor is overconstrained
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/70591571/2069064), with a clear
description of the problem.

This constructor:

  template>
_GLIBCXX20_CONSTEXPR
basic_string(const _Tp& __t, size_type __pos, size_type __n,
 const _Alloc& __a = _Alloc())
: basic_string(_S_to_string_view(__t).substr(__pos, __n), __a) { }

is constrained using:

  template
using _If_sv = enable_if_t<
  __and_,
 __not_>,
 __not_>>::value,
  _Res>;

But while the (const T&, const Allocator&) constructor does need that
additional requirement that const T& isn't convertible to const charT* (and is
specified to have this check), the original constructor I linked to does not -
since there wouldn't be any ambiguity there
(http://eel.is/c++draft/string.cons#5).

As such, a construction like:

string s("some string to test", 2, 3);

Instead of converting the literal to a string_view and doing a substr, instead
invokes this constructor:

  _GLIBCXX20_CONSTEXPR
  basic_string(const basic_string& __str, size_type __pos,
   const _Alloc& __a = _Alloc())

Which requires (unnecessarily) allocating a new string.

[Bug c++/103783] New: Ambiguous overload between constrained static member and unconstrained non-static member

2021-12-20 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103783

Bug ID: 103783
   Summary: Ambiguous overload between constrained static member
and unconstrained non-static member
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/70429541/2069064):

template
struct s {
void f() const;
static void f() requires b;
};

void g() {
s().f();
}

gcc rejects with:

: In function 'void g()':
:8:20: error: call of overloaded 'f()' is ambiguous
8 | s().f();
  | ~~~^~
:3:14: note: candidate: 'void s::f() const [with bool b = true]'
3 | void f() const;
  |  ^
:4:21: note: candidate: 'static void s::f() requires  b [with bool b
= true]'
4 | static void f() requires b;
  | ^

I don't think this is an instance of P2113 with non-equivalent templates, seems
like this case should compile. clang and msvc accept.

[Bug c++/103712] New: variable is not a constant expression because it is used in its own initializer

2021-12-14 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103712

Bug ID: 103712
   Summary: variable is not a constant expression because it is
used in its own initializer
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced from StackOverflow (https://stackoverflow.com/q/70342678/2069064):

struct selfref {
selfref* next = nullptr;
};

struct exec {
selfref mem = selfref{};

constexpr exec() {
mem.next = 
}
};

constexpr exec do_thing() {
return exec{};
}


constexpr exec ret = do_thing();
constexpr selfref* ptr = ret.mem.next;

I think this should compile - ret.mem.next points to ret.mem, which is okay
since ret has static storage duration. And then ptr should be pointing to
something that has static storage duration, which is a permitted result.

gcc currently rejects with:

:19:26: error: the value of 'ret' is not usable in a constant
expression
   19 | constexpr selfref* ptr = ret.mem.next;
  |  ^~~
:18:16: note: 'ret' used in its own initializer
   18 | constexpr exec ret = do_thing();
  |^~~

This seems vaguely related to CWG 2278, but do_thing() isn't doing copy
elision, so I think this should work.

[Bug c++/103663] New: Diagnostic is missing multiple instantiation frames to help point to where the problem happens

2021-12-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103663

Bug ID: 103663
   Summary: Diagnostic is missing multiple instantiation frames to
help point to where the problem happens
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

I'm sorry for how not-remotely-reduced these examples are, but I'm not sure how
to do better.

===

Consider this bug in range-v3 that we're trying to figure out how to solve
(this is a range-v3 library issue, not a gcc or libstdc++ issue):

#include 

struct Abstract {
virtual auto f() -> int = 0;
};

struct V {
auto begin() -> Abstract*;
auto end() -> Abstract*;
};

void use(V v) {
auto z = ranges::views::zip(v);
z.begin();
}

This code doesn't compile. With gcc 11.2 -std=c++20
(https://godbolt.org/z/h4d14jeMa), the diagnostics I get on compiler explorer
are:

In file included from
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/zip.hpp:17,
 from :1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple: In instantiation of
'struct std::_Head_base<0, Abstract, false>':
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:407:12:   required
from 'struct std::_Tuple_impl<0, Abstract>'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:599:11:   required
from 'class std::tuple'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/functional/invoke.hpp:138:40:
  required from 'constexpr decltype
((F&&)(f)((Args&&(ranges::invoke_fn::operator()::args))...))
ranges::invoke_fn::operator()(F&&, Args&& ...) const [with F =
ranges::detail::indirect_zip_fn_&; Args = {ranges::copy_tag, Abstract*};
decltype ((F&&)(f)((Args&&(ranges::invoke_fn::operator()::args))...)) =
std::tuple]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/functional/concepts.hpp:36:5:
  required by substitution of 'template  requires  Const &&
(and_v...>) && (zippable_with, const Rngs>::type ...>)
ranges::iter_zip_with_view >::cursor
ranges::iter_zip_with_view >::begin_cursor() const [with bool Const =
ranges::detail::indirect_zip_fn_]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/detail/range_access.hpp:85:31:
  required by substitution of 'template static constexpr decltype
(rng.begin_cursor()) ranges::range_access::begin_cursor(Rng&) [with Rng = const
ranges::iter_zip_with_view >]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/facade.hpp:39:39:
  required by substitution of 'template using facade_iterator_t
= ranges::basic_iterator()))>::type> [with Derived
= const ranges::iter_zip_with_view >]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/facade.hpp:106:24:
  required by substitution of 'template  requires  same_as
constexpr ranges::detail::facade_iterator_t
ranges::view_facade >, ranges::finite>::begin() const [with D =
ranges::iter_zip_with_view >]'
:14:12:   required from here
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:224:13: error:
cannot declare field 'std::_Head_base<0, Abstract, false>::_M_head_impl' to be
of abstract type 'Abstract'
  224 |   _Head _M_head_impl;
  | ^~~~
:3:8: note:   because the following virtual functions are pure within
'Abstract':
3 | struct Abstract {
  |^~~~
:4:18: note: 'virtual int Abstract::f()'
4 | virtual auto f() -> int = 0;
  |  ^

The instantiation stack points to tuple, invoke.hpp, concepts.hpp,
range_access.hpp, facade.hpp. But the problem comes from zip_with.hpp. This is
not really possible to track down from the diagnostic.

To help illustrate what I mean, this line:

/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/detail/range_access.hpp:85:31:
  required by substitution of 'template static constexpr decltype
(rng.begin_cursor()) ranges::range_access::begin_cursor(Rng&) [with Rng = const
ranges::iter_zip_with_view >]'

points us to here:

template
static constexpr auto CPP_auto_fun(begin_cursor)(Rng )
(
return rng.begin_cursor()
)

Which is a macro that expands to:

template
static constexpr auto begin_cursor (Rng )
noexcept(noexcept(rng.begin_cursor())) -> decltype(rng.begin_cursor()) { return
(rng.begin_cursor()); }

The next instantiation stack frame points us to here:

template
CPP_requires(invocable_,
requires(Fun && fn) //
(
invoke((Fun &&) fn, std::declval()...)
));


Which is a macro that expands to:

template
concept invocable__requires_

[Bug libstdc++/100795] ranges::sample should not use std::sample directly

2021-11-23 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100795

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #8 from Barry Revzin  ---
Related: https://stackoverflow.com/q/70076645/2069064

std::ranges::sort calls std::sort, which then uses std::iter_swap instead of
std::ranges::iter_swap.

[Bug libstdc++/101263] non-propagating-cache::emplace-deref missing constexpr

2021-10-14 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101263

--- Comment #6 from Barry Revzin  ---
The "real" answer is allowing constexpr placement new, but that obviously
doesn't help you right now.

But I think the helpful answer is that you can add a constructor to your
storage like storage(init_from_invoke_t, Args&&... args) that initializes the
underlying value from invoke((Args&&)args...), and then construct_at(,
init_from_invoke, [&]() -> decltype(auto) { return *i; }).

Something like that?

[Bug tree-optimization/95384] Poor codegen cause by using base class instead of member for Optional construction

2021-10-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95384

--- Comment #4 from Barry Revzin  ---
Here's another example of the same kind of issue
(https://godbolt.org/z/KWr9rMssj):

template 
struct tagged_union {
tagged_union(T t) : index(0), a(t) { }
tagged_union(U u) : index(1), b(u) { }


union {
T a;
U b;
};
char index;
};

struct X { int i; };
struct Y { int j; };

tagged_union as_tagged_union(X x) {
return x;
}

template 
struct tagged_union_wrapped : tagged_union {
using tagged_union::tagged_union;
};

auto as_tagged_union2(X x) {
return tagged_union_wrapped(x);
}

this on -O3 emits:

as_tagged_union(X):
mov eax, edi
ret
as_tagged_union2(X):
mov DWORD PTR [rsp-8], edi
mov BYTE PTR [rsp-4], 0
mov rax, QWORD PTR [rsp-8]
ret

If you change the index member from 'char' to 'int', causing the tail padding
to disappear, as_tagged_union2 improves to the same code gen as
as_tagged_union.

This is relevant for std::variant performance. std::variant behaves like
tagged_union_wrapped, whereas if you drop down to the implementation
details and directly use _Variant_storage_alias, that behaves like
tagged_union for these purposes.

[Bug c++/102644] New: deduction failure when having default non-type template parameters that are lambdas

2021-10-07 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102644

Bug ID: 102644
   Summary: deduction failure when having default non-type
template parameters that are lambdas
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

gcc trunk with -std=c++20 rejects this example as having no matching function
call:

template 
struct s {
template 
int foo() { return 0; }
};

int main() {
return s{}.foo();
}

gcc accepts if:

* foo()'s default argument is 1 instead of a lambda
* s is not a class template (but changing V1's default to be 0 while keeping V2
as a lambda is still an error)

[Bug c++/102529] New: ctad for aliases fails in the presence of constraints

2021-09-29 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102529

Bug ID: 102529
   Summary: ctad for aliases fails in the presence of constraints
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Here's an example:

template 
struct C {
template 
C(U);
};

template 
C(U) -> C;

template 
requires true
using A = C;

C ok(1);   // ok, a is a C
A bad(2);  // fails

The provided error on gcc 11.2 (and trunk as of this writing) is:

:15:8: error: class template argument deduction failed:
   15 | A bad(2);  // fails
  |^
:15:8: error: no matching function for call to 'C(int)'
:2:8: note: candidate: 'template C(C)-> C requires 
__is_same(A, C)'
2 | struct C {
  |^
:2:8: note:   template argument deduction/substitution failed:
:15:8: note:   mismatched types 'C' and 'int'
   15 | A bad(2);  // fails
  |^
:4:5: note: candidate: 'template C(U)-> C requires
 __is_same(A, C)'
4 | C(U);
  | ^
:4:5: note:   template argument deduction/substitution failed:
:15:8: note:   couldn't deduce template parameter 'T'
   15 | A bad(2);  // fails
  |^

If you drop the "requires true" part of the alias template A, then this works.
As far as I understand the rules, this should work. MSVC accepts the example.
clang does not yet implement class template argument deduction for alias
templates.

[Bug c++/102289] New: Concept declaration with multiple template-heads not diagnosed

2021-09-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102289

Bug ID: 102289
   Summary: Concept declaration with multiple template-heads not
diagnosed
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

gcc trunk accepts this:

template 
template 
concept C = true;

I'm not sure exactly what gcc does with it, but C does become a real concept,
and this leads to other strange things happening down the line (reduced from:
https://stackoverflow.com/q/69143991/2069064)

[Bug c++/102263] New: Requesting enhanced warning on returning pointer/reference to local

2021-09-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102263

Bug ID: 102263
   Summary: Requesting enhanced warning on returning
pointer/reference to local
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

gcc (and clang) both warn on both of these functions:

int* a() {
int i = 0;
return 
}

int& b() {
int i = 0;
return i;
}

Which is great. Both of these functions are bad. However, add an extra layer:

struct Ptr { int* p; };
struct Ref { int& r; };

Ptr c() {
int i = 0;
return Ptr{.p=};
}

Ref d() {
int i = 0;
return Ref{.r=i};
}

And now gcc (nor clang) warn on either of these two functions. But 'c' and 'd'
are just as much returning a pointer/reference to a local variable as 'a' and
'b' are, and it would be extremely helpful to warn on these cases.

More motivating example from C++20 would be something like this (which came up
in discussion of P2415):

std::vector get_ints();

auto doubled_ints() {
auto ints = get_ints();
return ints | std::views::transform([](int i){ return i * 2; });
}

This is returning an object that has a member that has a member that has a
pointer to a local variable. Which is bad, this dangles! It would be super cool
if such a function got a warning slapped onto it.

[Bug c++/102236] New: emplace_deref is not constexpr for join_view

2021-09-07 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102236

Bug ID: 102236
   Summary: emplace_deref is not constexpr for join_view
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

For instance:

#include 

constexpr std::string_view first_n_words(std::string_view str, size_t n) {
namespace rv = std::views;
auto first_n = str
| rv::split(' ')
| rv::take(n)
| rv::join;   

return std::string_view(&*first_n.begin(), std::ranges::distance(first_n));
}

constexpr std::string_view first4 = first_n_words("Hello to all you beautiful
libstdc++ developers", 4);

This doesn't compile because _M_emplace_deref isn't marked constexpr (probably
becase P2231 isn't implemented yet, but thought I'd file a bug report anyway).

[Bug libstdc++/101965] New: check in charconv is vacuously true

2021-08-18 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101965

Bug ID: 101965
   Summary: check in charconv is vacuously true
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: libstdc++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

When investigating PVS-Studio in our codebase, it flagged this check in
charconv:

   322template
   323  __detail::__integer_to_chars_result_type<_Tp>
   324  __to_chars_i(char* __first, char* __last, _Tp __value, int __base =
10)
   325  {
   326__glibcxx_assert(2 <= __base && __base <= 36);
   327
   328using _Up = __detail::__unsigned_least_t<_Tp>;
   329_Up __unsigned_val = __value;
   330
   331if (__first == __last) [[__unlikely__]]
   332  return { __last, errc::value_too_large };
   333
   334if (__value == 0)
   335  {
   336*__first = '0';
   337return { __first + 1, errc{} };
   338  }
   339
   340if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
   341  if (__value < 0)
   342{
   343  if (__builtin_expect(__first != __last, 1))
   344*__first++ = '-';
   345  __unsigned_val = _Up(~__value) + _Up(1);
   346}
   347
   348switch (__base)
   349{
   350case 16:

On line 343, __first is never equal to __last. If it were, we would've returned
on line 332.

[Bug c++/101883] New: class template argument deduction in non-type template parameter allows explicit deduction guide

2021-08-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101883

Bug ID: 101883
   Summary: class template argument deduction in non-type template
parameter allows explicit deduction guide
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced example:

template  struct C { constexpr C(int) {} };
explicit C(int) -> C;

template  struct X { };
X<1> x;

This should fail to compile, because the deduction guide is explicit and so
should not be a candidate, but gcc accepts this example.

gcc does correctly reject:

C y = 1;

Which is the same kind of thing.

[Bug c++/80943] Conversion function selected in list-initialization in C++1z mode

2021-08-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80943

--- Comment #3 from Barry Revzin  ---
This is CWG 2327
(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2327).

It's still active, but gcc/clang's behavior (printing 2) seems like the
superior choice.

[Bug c++/101006] New: Request diagnostic for likely concept syntax errors

2021-06-09 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101006

Bug ID: 101006
   Summary: Request diagnostic for likely concept syntax errors
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following:

template 
concept Thing = true;

template 
concept MemberThing = requires (T t) {
t.member() -> Thing;// #1
!requires { t.member(); };  // #2
};

These are likely intended to be (obviously not at the same time, this is just
an example):

template 
concept MemberThing = requires (T t) {
{ t.member() } -> Thing;

requires !requires { t.member(); };
};

But #1 is very likely to be a bug, and #2 is completely pointless as a
requirement since it's tautologically true. It would be nice if gcc could
produce warnings in such cases.

#2 is a similar case to the P2092 fixup of:

template 
concept MemberThing = requires (T t) {
requires { t.member(); };
};

which is now ill-formed. However, gcc's diagnostic here could be more helpful
too (perhaps including a fixup for an extra requires?)

:6:14: error: expected primary-expression before '{' token
6 | requires { t.member(); };
  |  ^

#1 might be harder to warn about since that could *theoretically* be intended,
but if unqualified lookup for Thing actually finds a concept, seems like a good
bet for a diagnostic maybe?

[Bug c++/100835] New: defaulted equality gives wrong answer, if constexpr

2021-05-30 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100835

Bug ID: 100835
   Summary: defaulted equality gives wrong answer, if constexpr
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Short example:

struct B {
int i;
CONSTEXPR bool operator==(B const&) const = default;
};

struct D : B {
CONSTEXPR bool operator==(D const&) const = default;
};

static_assert(D{0} == D{5});

When compiled with -DCONSTEXPR=constexpr, the static assertion passes. When
compiled with -DCONSTEXPR=, the static assertion fails.

For some reason, when the equality operator is declared constexpr, there is
just no work that happens for doing equality. For instance, the function

bool check(D a, D b) {
return a == b;
}

compiles to:

check(D, D):
mov eax, 1
ret

[Bug c++/100639] New: reverse_view::reference erroneously uses iterator_traits::reference instead of iter_reference_t

2021-05-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100639

Bug ID: 100639
   Summary: reverse_view::reference erroneously uses
iterator_traits::reference instead of
iter_reference_t
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Short example (from https://stackoverflow.com/q/67573305/2069064):

#include 

template  using iota = std::ranges::iota_view;
template  using iota_iter = std::ranges::iterator_t>;

static_assert(std::same_as<
std::reverse_iterator>::reference,
int64_t>);

This assertion fails when compiling with -std=c++20 (because the reference type
is 'void') but passes with -std=gnu++20. The direct reason is that the
difference_type of the iota_view iterator is __int128, which is considered a
signed_integral with gnu++20 but not c++20.

But the reason this matters is because std::reverse_iterator::reference is
defined as std::iterator_traits::reference (which checks that I satsifies
cpp17-input-iterator which has the signed_integral constraint) instead of being
defined as std::iter_reference_t (which has no such check). With the latter
implementation, the assertion above would pass on either version. 

The result is that reversing an iota_view isn't a range on
-std=c++20.

[Bug c++/100322] Switching from std=c++17 to std=c++20 causes performance regression in relationals

2021-04-28 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100322

--- Comment #5 from Barry Revzin  ---
Sorry meant to actually copy the reduction:

#include  

bool compare_count(int a, int b)
{
return a > b;
}

bool compare(int a, int b)
{
return (a <=> b) > 0;
}

which generates:

compare_count(int, int):
cmp r0, r1
ite le
movle   r0, #0
movgt   r0, #1
bx  lr
compare(int, int):
cmp r0, r1
beq .L4
blt .L5
movsr0, #1
.L3:
cmp r0, #0
ite le
movle   r0, #0
movgt   r0, #1
bx  lr
.L4:
movsr0, #0
b   .L3
.L5:
mov r0, #-1
b   .L3

[Bug c++/100322] Switching from std=c++17 to std=c++20 causes performance regression in relationals

2021-04-28 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100322

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #4 from Barry Revzin  ---
Reduced to avoid chrono: https://godbolt.org/z/o96oz9d6K

[Bug c++/100084] using enum lookup isn't type-only

2021-04-14 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100084

--- Comment #1 from Barry Revzin  ---
Also gcc accepts:

namespace A { enum A {}; };
using namespace A;
using enum A::A;

Which, apparently, this one should actually be ambiguous.

[Bug c++/100084] New: using enum lookup isn't type-only

2021-04-14 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100084

Bug ID: 100084
   Summary: using enum lookup isn't type-only
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From Stack Avarflaw (https://stackoverflow.com/q/67096550/2069064):

namespace A { enum A {}; };
using namespace A;
using enum A;

gcc trunk rejects this lookup as ambiguous, between the namespace A and the
enum A. But our lookup in this context should be type-only, so the namespace A
should not a candidate.

[Bug c++/100070] New: Standard library container iterator-pair constructors should check C++20 iterator concepts

2021-04-13 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100070

Bug ID: 100070
   Summary: Standard library container iterator-pair constructors
should check C++20 iterator concepts
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/67081354/2069064), a user was
benchmarking code that did this:

   int convert(int);

   std::vector foo(100,42);
   auto transform_range = foo | std::ranges::views::transform(convert);
   std::vector fooTimesTwo(transform_range.begin(),
transform_range.end());

And found it to be much slower than their initial implementation that did not
use ranges. This is because while transform_range is a C++20 random access
range, it is only a C++17 input range. 

libstdc++'s decision is based entirely on iterator_category
(https://github.com/gcc-mirror/gcc/blob/8084ab15a3e300e3b2c537e56e0f3a1b00778aec/libstdc%2B%2B-v3/include/bits/stl_vector.h#L652-L659)
which does the best you can with an input range: just loop and emplace.

But if it instead checked for forward_iterator and random_access_iterator (the
concept), this construction case could be handled efficiently (i.e. as a single
allocation). I think that should safe? Checking for random_access_iterator
checks the tag before checking for the validity of operator-?

[Bug c++/100054] [11 Regression] internal compiler error: in get_nsdmi

2021-04-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100054

--- Comment #2 from Barry Revzin  ---
In case it helps, here's a different example which on trunk ICEs in get_nsdmi,
but on gcc 10.2 and 10.3 ICEs on "unexpected expression '(F)()' of kind implicit_conv_expr" (and is accepted by 10.1)

struct F {
private:
  int cx;
};

template 
void find() {
struct H {
F o{};
};
using r = decltype([](auto) { return H{}; }(0));
}

void p() {
  find();
}

[Bug c++/100054] New: internal compiler error: in get_nsdmi

2021-04-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100054

Bug ID: 100054
   Summary: internal compiler error: in get_nsdmi
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced with creduce and then by hand:

template 
struct C {
  void find() {
struct H {
C c{};
};
(void)[](auto){ return H{}; };
  }
};

void f() {
  C().find();
}

This fails on gcc trunk -std=c++20 (but worked on gcc 10.3, 10.2, 10.1) with
(https://godbolt.org/z/heEKjMn91):

: In instantiation of 'void C::find() [with n = int]':
:12:16:   required from here
:5:14: internal compiler error: in get_nsdmi, at cp/init.c:598
5 | C c{};
  |  ^
0x1d01009 internal_error(char const*, ...)
???:0
0x6bb009 fancy_abort(char const*, int, char const*)
???:0
0x7fa161 get_nsdmi(tree_node*, bool, int)
???:0
0x97f2eb finish_compound_literal(tree_node*, tree_node*, int, fcl_t)
???:0
0x94ae62 tsubst_lambda_expr(tree_node*, tree_node*, int, tree_node*)
???:0
0x91699a tsubst_tree_list(tree_node*, tree_node*, int, tree_node*)
???:0
0x91d7ef instantiate_decl(tree_node*, bool, bool)
???:0
0x95f69b instantiate_pending_templates(int)
???:0
0x7cd039 c_parse_final_cleanups()
???: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.
ASM generation compiler returned: 1
: In instantiation of 'void C::find() [with n = int]':
:12:16:   required from here
:5:14: internal compiler error: in get_nsdmi, at cp/init.c:598
5 | C c{};
  |  ^
0x1d01009 internal_error(char const*, ...)
???:0
0x6bb009 fancy_abort(char const*, int, char const*)
???:0
0x7fa161 get_nsdmi(tree_node*, bool, int)
???:0
0x97f2eb finish_compound_literal(tree_node*, tree_node*, int, fcl_t)
???:0
0x94ae62 tsubst_lambda_expr(tree_node*, tree_node*, int, tree_node*)
???:0
0x91699a tsubst_tree_list(tree_node*, tree_node*, int, tree_node*)
???:0
0x91d7ef instantiate_decl(tree_node*, bool, bool)
???:0
0x95f69b instantiate_pending_templates(int)
???:0
0x7cd039 c_parse_final_cleanups()
???: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.
Execution build compiler returned: 1

[Bug c++/100037] New: lookup doesn't find class template parameter in default member initializer of forward declared nested class template

2021-04-11 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100037

Bug ID: 100037
   Summary: lookup doesn't find class template parameter in
default member initializer of forward declared nested
class template
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Issue title is a mouthful, but it's a very narrow case:

template  using always_int = int;

struct view {
template  struct iterator;

template 
struct iterator {
always_int inner = always_int();
};
};

This is rejected with:

:8:46: error: 'Const' was not declared in this scope
8 | always_int inner = always_int();
  |  ^
:8:51: error: template argument 1 is invalid
8 | always_int inner = always_int();
  |   ^

This compiles if we also name the template parameter in the forward
declaration. This fails only in the case of a nested class - if you change it
to namespace view from struct view, the example compiles fine.

[Bug c++/79070] Unhelpful error message for ambiguous type in template parameter

2021-03-29 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79070

Barry Revzin  changed:

   What|Removed |Added

 CC||barry.revzin at gmail dot com

--- Comment #3 from Barry Revzin  ---
Here are a few more cases, reduced from a larger example that took me a very
long time to understand. I'm adding as comments the compile error emitted for
each invalid use:

namespace N {
template  struct Something { };
template  concept C = true;
template  struct X { };
}

using namespace N;
template  struct Something { };

// parse error in template argument list
static_assert(C>);

// template argument 1 is invalid
X> x;

// reference to Something is ambiguous
using T = Something;

In the last case, the compiler error is super clear and it is obvious what the
error is. In the other two, not so much.

[Bug c++/99629] New: Misleading diagnostic when looking up rewritten candidate and failing

2021-03-17 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99629

Bug ID: 99629
   Summary: Misleading diagnostic when looking up rewritten
candidate and failing
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

>From StackOverflow (https://stackoverflow.com/q/66674463/2069064):

#include 

struct S {};

int operator<=>(S, int) { return 0;  }
S   operator<=>(S,   S) { return {}; }

auto x = S{} < S{};

gcc correctly rejects this code as ill-formed. However, the diagnostic provided
is:

:8:14: error: no match for 'operator<' (operand types are 'S' and
'int')
8 | auto x = S{} < S{};
  |  ^

This is technically correct (in the sense that the compiler should be looking
for, specifically, an operator< between S and 0 and fail because it does not
find such a thing) but it's quite a confusing diagnostic since (a) the
highlighted line is not comparing an S to an int and (b) it sure looks like
from the code that you can compare an S to an int. 

It would be nice if the diagnostic somehow made clear that having found
operator<=>(S, S) that it's trying to resolve S{} < S{} as (S{} <=> S{}) < 0
and that subsequent lookup doesn't consider rewritten candidates somehow. 

Not especially high priority (I don't expect this to be an especially common
idiom...), more of a nice to have.

[Bug c++/99566] New: designated initialization rejects explicit constructor

2021-03-12 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99566

Bug ID: 99566
   Summary: designated initialization rejects explicit constructor
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Reduced from StackOverflow (https://stackoverflow.com/q/66606143/2069064):

struct A {
explicit A(int);
};

struct B {
A a;
};

A a{10}; // ok
B b{.a{10}}; // error: converting from initializer list
 // would use explicit constructor

But the initialization of the "a" subobject of B should work the same was as
the initialization of the complete object "a".

[Bug c++/99091] New: constexpr variable evaluated at runtime

2021-02-13 Thread barry.revzin at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99091

Bug ID: 99091
   Summary: constexpr variable evaluated at runtime
   Product: gcc
   Version: 10.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: barry.revzin at gmail dot com
  Target Milestone: ---

Consider the following (link to compiler explorer:
https://godbolt.org/z/jWsxsK)

#include 

static constexpr auto doy = []{
std::array month_offset{};
for (int m=1; m<=12;++m) {
month_offset[m] = (153*(m > 2 ? m-3 : m+9) + 2)/5;
}
return month_offset;
}();

auto foo(int m) -> int {
#ifdef LOCAL
constexpr auto doy = []{
std::array month_offset{};
for (int m=1; m<=12;++m) {
month_offset[m] = (153*(m > 2 ? m-3 : m+9) + 2)/5;
}
return month_offset;
}();
#endif

return doy[m];
}

This is a fragment of code that does some calculation to figure out the date,
which isn't super important. If LOCAL is not defined (i.e. we declare the array
as a namespace-scope constexpr), the -O3 codegen of 'foo' is:

foo(int):
movsx   rdi, edi
mov eax, DWORD PTR doy[0+rdi*4]
ret

However, if we want to move the declaration of doy to be more local to the
calculation and compile with -DLOCAL, the codegen instead is (on -O3):

foo(int):
pxorxmm0, xmm0
mov rax, QWORD PTR .LC0[rip]
movsx   rdi, edi
mov DWORD PTR [rsp-24], 275
movaps  XMMWORD PTR [rsp-72], xmm0
movdqa  xmm0, XMMWORD PTR .LC1[rip]
mov QWORD PTR [rsp-68], rax
movaps  XMMWORD PTR [rsp-56], xmm0
movdqa  xmm0, XMMWORD PTR .LC2[rip]
movaps  XMMWORD PTR [rsp-40], xmm0
mov eax, DWORD PTR [rsp-72+rdi*4]
ret

This can be alleviated by marked the local variable doy as being static
constexpr. Except that this prevents 'foo' from being a constexpr function
(can't have static variables). 

This just seems like bad codegen, I'm not sure there's any reason that the
compiler needs to do work here. It would be nice if the codegen with a local
constexpr variable were the same as if it were a non-local constexpr variable.

  1   2   3   >