Classes that use `[[no_unique_address]]` may have different layout depending on compiler used
Open
Nobody has claimed this yet.
bug
compiler
high priority
- Dominant language
- C++
- Stars
- 11.1k
- Forks
- 1.7k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 22
Description
As in title. Repro:
#include <mdspan>
#include <ranges>
using namespace std;
class DummyAccessor {
public:
using element_type = int;
using reference = int;
using offset_policy = DummyAccessor;
struct data_handle_type {};
reference access(data_handle_type, size_t);
data_handle_type offset(data_handle_type, size_t);
};
class DummyIterator {
public:
using value_type = int;
using difference_type = ptrdiff_t;
DummyIterator() = default;
DummyIterator &operator++();
DummyIterator operator++(int);
value_type operator*() const;
bool operator==(const DummyIterator &) const;
};
using MDS = mdspan<int, dextents<int, 1>, layout_left, DummyAccessor>;
using View = decltype(declval<ranges::subrange<DummyIterator>>() |
views::enumerate | views::chunk(2));
static_assert(sizeof(MDS) == sizeof(int)); // single dynamic extent
static_assert(sizeof(ranges::iterator_t<View>) == 3 * sizeof(ptrdiff_t)); // three pointers
EDG and Clang interpret [[no_unique_address]] differently from MSVC. Command line:
PS E:\no_unique_address> cl /Zs /nologo /std:c++23preview .\bug.cpp
bug.cpp
PS E:\no_unique_address> clang-cl /Zs /nologo /std:c++23preview .\bug.cpp
.\bug.cpp(33,15): error: static assertion failed due to requirement 'sizeof(std::mdspan<int, std::extents<int, 18446744073709551615>,
std::layout_left, DummyAccessor>) == sizeof(int)'
33 | static_assert(sizeof(MDS) == sizeof(int));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
.\bug.cpp(33,27): note: expression evaluates to '8 == 4'
33 | static_assert(sizeof(MDS) == sizeof(int));
| ~~~~~~~~~~~~^~~~~~~~~~~~~~
.\bug.cpp(34,15): error: static assertion failed due to requirement
'sizeof(std::ranges::chunk_view<std::ranges::enumerate_view<std::ranges::subrange<DummyIterator, DummyIterator,
std::ranges::subrange_kind::unsized>>>::_Iterator<true>) == 3 * sizeof(long long)'
34 | static_assert(sizeof(ranges::iterator_t<View>) == 3 * sizeof(ptrdiff_t));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\bug.cpp(34,48): note: expression evaluates to '32 == 24'
34 | static_assert(sizeof(ranges::iterator_t<View>) == 3 * sizeof(ptrdiff_t));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.
PS E:\no_unique_address> cl /Zs /nologo /std:c++23preview .\bug.cpp /BE
bug.cpp
".\bug.cpp", line 33: error: static assertion failed
static_assert(sizeof(MDS) == sizeof(int));
^
".\bug.cpp", line 33: note: the final comparison was 8 == 4
static_assert(sizeof(MDS) == sizeof(int));
^
".\bug.cpp", line 34: error: static assertion failed
static_assert(sizeof(ranges::iterator_t<View>) == 3 * sizeof(ptrdiff_t));
^
".\bug.cpp", line 34: note: the final comparison was 32 == 24
static_assert(sizeof(ranges::iterator_t<View>) == 3 * sizeof(ptrdiff_t));
Introduced in #4960.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the supplied bug.cpp with both cl and clang-cl, then trace the mdspan and ranges::enumerate/chunk implementations involved in the two static assertions. Compare how [[no_unique_address]] affects their layouts across the reported compilers. Done means the layout behavior is resolved or clearly covered by tests for both cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100