libstdc++: potential bug in specification of layouts.
Luc Grosheintz
luc.grosheintz@gmail.com
Thu May 15 15:49:38 GMT 2025
On 5/13/25 1:23 PM, Tomasz Kaminski wrote:
> On Tue, May 13, 2025 at 12:55 PM Jonathan Wakely <jwakely@redhat.com> wrote:
>
>> On Tue, 13 May 2025 at 10:54, Luc Grosheintz wrote:
>>>
>>> This email chain continues a discussion about potential bugs in the
>>> specification that was started here:
>>> https://gcc.gnu.org/pipermail/libstdc++/2025-May/061350.html
>>>
>>> For notational convenience, I'll write `layout_left` as shorthand for
>>> `layout_left::mapping`, e.g. layout_left::required_span_size, refers to
>>> layout_left::mapping<Extents>::required_span_size.
>>
>> Thanks for writing these up, Luc.
>>
>> Once the discussion concludes here you can submit one or more issues
>> to the LWG chair (which is, er, me) as documented at
>> https://cplusplus.github.io/LWG/lwg-active.html#submit_issue
>>
>>
>>> 1. operator==
>>>
>>> The observation is that for rank0 and rank1, two mappings, one of type
>>> layout_left<Extents> and the other layout_right<OExtents>, the
>>> operator== is ambiguous if `Extents == OExtents`; but not if the extents
>>> are convertible (because the convertability is only in one direction).
>>>
>>> Godbolt: https://godbolt.org/z/35TbMnc1e
>>>
>>> Resolution: It's not clear to me what to propose. Likely, something that
>>> fixes the ambiguity issue to allow comparing all rank 0 and rank 1
>>> instances of layout_left and layout_right. Help would be most welcome:
>>> either by collaboratively working on the proposed change; or if someone
>>> wants to take over completely that would also work.
>>
>> N.B. it's not necessary to have a resolution when reporting an issue.
>> Generally issues will get resolved sooner if there's a proposed
>> resolution (even if it's a bad one, because that might nerdsnipe
>> somebody into writing a better one!
>> https://meta.wikimedia.org/wiki/Cunningham%27s_Law applies here).
Thank you, that's good to know. I'll start with an easier one to get
familiar with the process.
>>
>>
>>>
>>>
>>> 2. Missing `noexcept` in layout_left.
>>>
>>> The specification (N4950 and as published on `eel.is`) consistently
>>> doesn't mention `noexcept` in both the Overview and Constructors
>>> sections for `layout_left(layout_stride)`.
>>>
>>> https://eel.is/c++draft/mdspan.layout.left#overview-1
>>>
>> https://eel.is/c++draft/mdspan.layout.left#lib:layout_left::mapping,constructor____
>>>
>>> Resolution: I suggest that I file an issue to add `noexcept`
>>> consistently. Can this be considered an editorial issue?
>>
>> Since it's *consistently* missing, I don't think we can consider it
>> editorial. What is in the standard matches what was approved by the
>> committee.
>>
> It is missing for layout_left, however the corresponding constructor for
> layout_right has noexcept
> specifier, despite the same argument applying to it.
> layout_left_padded, layout_right_padded also do not have noexcept here, so
> maye layout_right should
> be adjusted, but I believe these constructors should be consistent.
Tomasz is pointing out the important piece of context I failed to
include. If one looks at any of the C++23 (but not C++26) layouts,
all their methods and ctors are noexcept. Also if they have
Prerequisites.
Therefore, within layout_left the choice is consistent. However,
across layouts the choice looks inconsistent; and if we also consider
the C++26 layout it's very ambiguous.
The two other implementations seem to make it noexcept:
clang: https://godbolt.org/z/Ec6Mc8v7f
msvc: https://godbolt.org/z/439Y6WTq1
>
>>
>> And this seems to be an intentional application of the "Lakos rule"
>> which says that functions with narrow contracts (i.e. with
>> preconditions) should not be noexcept. We can strengthen that and add
>> noexcept in the implementation, if we know that our implementation
>> never throws exceptions as a result of precondition violations (and
>> will never do so in future, e.g. if we were to start using C++26
>> contracts to check preconditions, which would mean the constructors
>> could throw if the user provides a throwing contract violation
>> handler).
>>
>>
>>>
>>> 3. Inconsistency about `constexpr` in layout_right::required_span_size.
>>>
>>> The section Overview specifies that `required_span_size` must be
>>> constexpr. In the section Observers this keyword is missing.
>>>
>>> I believe this is considered an editorial issue; and I can fix it by
>>> submitting a PR to the text of the standard.
>>>
>>> https://eel.is/c++draft/mdspan.layout.right#overview-1
>>>
>> https://eel.is/c++draft/mdspan.layout.right.obs#lib:required_span_size,layout_right::mapping
>>>
>>> Resolution: I suggest that I file an editorial issue.
>>
>> I see you already filed that, thanks.
>>
>>>
>>> 4. Inconsistency about `noexcept` in `layout_left::stride`.
>>>
>>> The section Overview mentions it's `noexcept` but the section Observers
>>> doesn't. Again, I think this is an editorial issue.
>>>
>>> https://eel.is/c++draft/mdspan.layout.left#overview-1
>>>
>> https://eel.is/c++draft/mdspan.layout.left.obs#lib:stride,layout_left::mapping
>>>
>>> Resolution: I suggest that I file an editorial issue.
>>
>> That was recently fixed editorially:
>> https://github.com/cplusplus/draft/pull/7831
>> The unofficial HTML draft is out of date.
>>
>>>
>>>
>>> 5. At Rank 0 layout_stride is untypically convertible.
>>>
>>> Commonly, two layouts are considered convertible, if the underlying
>>> extent_types are convertible, e.g.
>>>
>>>
>> https://eel.is/c++draft/mdspan.layout.left.cons#lib:layout_left::mapping,constructor_
>>>
>> https://eel.is/c++draft/mdspan.layout.left.cons#lib:layout_left::mapping,constructor__
>>>
>> https://eel.is/c++draft/mdspan.layout.right.cons#lib:layout_right::mapping,constructor_
>>>
>> https://eel.is/c++draft/mdspan.layout.right.cons#lib:layout_right::mapping,constructor__
>>> https://eel.is/c++draft/mdspan.layout.stride.cons#9
>>>
>>> However, for the two ctors `layout_left(layout_stride)` and
>>> `layout_right(layout_stride)`, the condition is `rank > 0`. Therefore,
>>>
>>> using E1 = std::extents<int>;
>>> using E2 = std::extents<unsigned int>;
>>>
>>> static_assert(std::is_convertible_v<
>>> std::layout_stride::mapping<E2>,
>>> std::layout_right::mapping<E1>
>>> >);
>>>
>>> even though:
>>>
>>> static_assert(!std::is_convertible_v<E2, E1>);
>>>
>>>
>> https://eel.is/c++draft/mdspan.layout.left.cons#lib:layout_left::mapping,constructor____
>>>
>> https://eel.is/c++draft/mdspan.layout.right.cons#lib:layout_right::mapping,constructor____
>>>
>>> Moreover, for rank 0 layout_stride can be converted to any
>>> specialization of layout_left or layout_right; but not to every
>>> specialization of `layout_stride`.
>>>
>>> Godbolt: https://godbolt.org/z/MdbvafG7n
>>>
>>> Resolution: I suggest I create an non-editorial issue to propose adding
>>> the convertibility criterium to the explicitness condition.
>>>
>>
>>
>
I'm interpreting no comments on 5. as no objections to submitting a non-
editorial issue with the described content. I'd start with this one.
More information about the Libstdc++
mailing list