-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Description
Since c65b4d6, https://reviews.llvm.org/D135462, some C++ code is miscompiled for the mingw/x86_64 target.
This breaks the libcxx testcase libcxx/test/std/ranges/range.factories/range.repeat.view/ctor.piecewise.pass.cpp
.
Noticing the issue is somewhat tricky since this testcase is rather new; the libcxx CI uses a prebuilt release with Clang 16 (where the testcase passes correctly). At the point of the regression, the testcase didn't exist yet (so a configuration that tests libcxx with latest git Clang didn't catch it immediately until long after the miscompilation was introduced); the test (and corresponding libc++ implementation) was added only later.
The issue can be reproduced with a reduced testcase like this:
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <ctype.h>
#include <wctype.h>
#include <stdio.h>
namespace std {
template <class, int b> struct c { static const bool f = b; };
template <bool d> using e = c<bool, d>;
template <class a, class g> using h = e<__is_same(a, g)>;
void ab();
inline namespace ad {
template <class, class> concept i = requires { ab; };
template <class a, class g> concept aa = h<a, g>::f;
template <class a, class g> concept j = aa<g, a>;
template <bool, class, class> using ah = int;
template <class, class> using ae = int;
template <class, class> using af = decltype(0);
template <class, class, class, class> struct ag;
template <class aj, class ai> using aq = af<ae<aj, ai>, ae<ai, aj>>;
template <class ak, class al, class aj, class ai> requires requires {
typename aq<aj, ai>;
}
struct ag<ak, al, aj, ai>;
template <class a> concept am = requires { a{}; };
template <class a> concept an = i<a, a>;
template <class a> concept ao = i<a, a>;
template <class a> constexpr bool ap = __is_object(a);
} // namespace ad
struct n {
template <class g> using k = g;
};
template <class, class g> using ar = n::k<g>;
template <class a> concept as = am<a>;
namespace ad {
template <class a> a *addressof(a &);
template <class at> concept au = requires(at aw) { aw; };
template <class at> concept ax = requires(at aw) { aw; };
struct {
template <class a> auto operator()(a &&ay) { return ay.az(); }
} az;
template <size_t...> struct o;
template <class ba, ba... bb> struct bc {
template <size_t> using l = o<bb...>;
};
template <size_t bd, size_t be>
using m = __make_integer_seq<bc, size_t, bd>::template l<be>;
template <class...> class tuple;
template <size_t...> struct o {};
template <size_t bd, size_t be = 0> struct q { typedef m<bd, be> ac; };
template <class...> struct bf {};
template <class> struct bg;
template <class... a> struct bg<tuple<a...>> : c<size_t, sizeof...(a)> {};
template <class, class> struct bh;
template <template <class...> class s, class... av, size_t... bi>
struct bh<s<av...>, o<bi...>> {
template <class a> using p = bf<ar<a, __type_pack_element<bi, av>>...>;
};
template <class a, size_t bd = bg<a>::f> struct bj {
using bk = a;
using r = bh<bk, typename q<bd>::ac>;
using ac = r::template p<a>;
};
int piecewise_construct;
template <size_t, class> class v {
public:
template <class a> v(a) {}
};
template <class...> struct w;
template <size_t... t, class... a> struct w<o<t...>, a...> : v<t, a>... {
template <size_t... x, class... y> w(o<x...>, bf<y...>) : v<x, y>(0)... {}
};
template <class... a> class tuple {
w<typename q<sizeof...(a)>::ac, a...> bl;
public:
template <class... g>
tuple(g...) : bl(typename q<sizeof...(g)>::ac(), typename bj<tuple>::ac()) {}
};
template <class... a> tuple(a...) -> tuple<a...>;
template <class a, class s> a bm(s) { return a(); }
template <class a, class s> a bn(s ay) { return bm<a>(ay); }
template <class a> concept bo = ax<a>;
template <class z> class bp {
z u() { return static_cast<z &>(*this); }
public:
template <bo bq> auto operator[](bq br) { return az(u())[br]; }
};
struct bs {
} unreachable_sentinel;
template <class a> concept bt = ap<a>;
namespace ranges {
template <bt> class bu;
template <class a> concept bv = ao<a>;
template <bt a> requires bv<a> class bu<a> {
a bw;
public:
bu(...) {}
a &operator*() { return bw; }
};
template <class a> concept bx = au<a>;
template <an a, as by = bs>
requires(ap<a> &&j<a, a> && (bx<by> || j<by, bs>)) class repeat_view
: public bp<repeat_view<a>> {
class bz;
public:
template <class... ca>
repeat_view(int, tuple<> cb, tuple<ca...> cc)
: ce(bn<a>(cb)), cf(bn<by>(cc)) {}
bz az() { return addressof(*ce); }
bu<a> ce;
[[__no_unique_address__]] by cf;
};
template <an a, as by>
requires(ap<a> &&j<a, a> &&
(bx<by> || j<by, bs>)) class repeat_view<a, by>::bz {
friend repeat_view;
using cg = ah<j<by, bs>, ptrdiff_t, by>;
bz(a *ch) : ce(ch) {}
public:
using cd = cg;
a operator*() { return *ce; }
a operator[](cd) { return **this; }
a *ce;
};
} // namespace ranges
} // namespace ad
} // namespace std
struct A {
int x = 111;
int y = 222;
constexpr A() = default;
constexpr A(int _x, int _y) : x(_x), y(_y) {}
};
int main(int, char**) {
std::ranges::repeat_view<A> rv(std::piecewise_construct, std::tuple{}, std::tuple{std::unreachable_sentinel});
printf("rv[0].x = %d - %s\n", rv[0].x, rv[0].x == 111 ? "ok" : "incorrect");
if (rv[0].x != 111)
return 1;
return 0;
}
(I'll rerun the reduction to try to retain the libc++ header names to keep it slightly more readable.)
If compiled with clang -target x86_64-w64-mingw32 -std=c++2b misopt.cpp -o misopt.exe
, the resulting binary outputs rv[0].x = 0 - incorrect
. If optimization is added with e.g. -O2
, it correctly outputs rv[0].x = 111 - ok
instead. If compiled with Clang 16, it runs correctly in both cases.
CC @asavonic
Metadata
Metadata
Assignees
Labels
Type
Projects
Status