[Bug c++/116696] function template not considered constexpr even with -fimplicit-constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116696 --- Comment #5 from Barry Revzin --- Thanks!
[Bug c++/116696] New: function template not considered constexpr even with -fimplicit-constexpr
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116696 Bug ID: 116696 Summary: function template not considered constexpr even with -fimplicit-constexpr Product: gcc Version: unknown 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 was trying to implement constexpr std::format as cheaply as possible — by using -fimplicit-constexpr instead of bothering to mark dozens (if not more) functions constexpr. That mostly worked quite well. Oddly, there was one function template that did not get marked constexpr implicitly, which was this one: https://github.com/gcc-mirror/gcc/blob/8c01976b8e34eaa2483ab37d1bd18ebc5c8ada95/libstdc%2B%2B-v3/include/std/format#L736 You can see this on compiler explorer here: https://godbolt.org/z/xq1zvqPWh (the function template in question is on line 733) The example fails with: :1355:42: error: call to non-'constexpr' function '_Out std::__format::__write_padded(_Out, std::basic_string_view<_CharT>, _Align, std::size_t, char32_t) [with _Out = _Sink_iter; _CharT = char; std::size_t = long unsigned int]' 1355 | return __format::__write_padded(std::move(__out), __str, | ^ 1356 | __align, __nfill, __fill_char); | ~~ :734:5: note: '_Out std::__format::__write_padded(_Out, std::basic_string_view<_CharT>, _Align, std::size_t, char32_t) [with _Out = _Sink_iter; _CharT = char; std::size_t = long unsigned int]' declared here 734 | __write_padded(_Out __out, basic_string_view<_CharT> __str, | ^~ Notably, there are lots of other function templates not marked constexpr in this header that work just fine with -fimplicit-constexpr. Not sure what's special about this one.
[Bug c++/115163] New: Requesting better diagnostic for explicit constructor failure
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>>
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
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 &val; } #ifdef SIMPLE auto end() const -> T const* { return &val + (has_val ? 1 : 0); } #else auto end() const -> T const* { return has_val ? &val + 1 : &val; } #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 &val + 1 or &val, 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
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 = &A::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
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
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
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
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
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
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
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 = &v; Empty* obj = &std::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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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(&lhs, &rhs, 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
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
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
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
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
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
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
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
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
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
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 _Mov
[Bug c++/106151] Inconsistent optimization when defaulting aggregate vs non-aggregate
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 = &mem; } }; 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
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 &rng) ( return rng.begin_cursor() ) Which is a macro that expands to: template static constexpr auto begin_cursor (Rng &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 &&am
[Bug libstdc++/100795] ranges::sample should not use std::sample directly
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
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(&storage, 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
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
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
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
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
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 &i; } 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=&i}; } 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.