4067. Inconsistency and potential infinity meta-recursion in std::chrono::zoned_time's constructors

Section: 30.11.7.2 [time.zone.zonedtime.ctor] Status: New Submitter: Jiang An Opened: 2024-04-14 Last modified: 2024-06-24

Priority: 3

View all other issues in [time.zone.zonedtime.ctor].

View all issues with New status.

Discussion:

Currently, there are no requirements on a program-defined std::chrono::zoned_traits specialization. So a zoned_traits<UserDefinedTzPtr>::locate_zone possibly returns a string_view, which leads to infinite meta-recursion when checking the constraints of zoned_time's constructors that take a string_view.

Also, the constructor of zoned_time taking only one string_view is inconsistent with others and even self-inconsistent. For other constructors taking string_view, it is expected that the return value of locate_zone is only implicitly converted to a TimeZonePtr. But the return value is permitted to be convertible to zoned_time or sys_time<Duration> in this constructor. And given the locate_name function may be an overload set that distinguishes lvalues and rvalues of string_view, the use of locate_time(string_view{}) in the constraints doesn't always reflect locate_time(name) in the effects as the return types can be different.

[2024-06-24; Reflector poll]

Set priority to 3 after reflector poll. "Such a UserDefinedTzPtr would be ridiculous and not useful, but it wouldn't hurt to tighten the spec a bit." "Would prefer a much simpler resolution saying 'dont do that'. I don't like that locatable-as-tzptr doesn't look like a dependent expression, but it is really. Saying 'TimeZonePtr is implicit convertible from its return type' should be phrased in terms of converting to, and should talk about conversion from an expression to a type (see LWG 3105)."

Proposed resolution:

This wording is relative to N4971.

  1. Modify 30.11.7.2 [time.zone.zonedtime.ctor] as indicated:

    [Drafting note: Add the following two paragraphs to the very beginning of subclause 30.11.7.2 [time.zone.zonedtime.ctor]]

    -?- Let locatable-as-tzptr be true if given an lvalue sv of type string_view, traits::locate_zone(sv) is well-formed and TimeZonePtr is implicitly convertible from its return type, and false otherwise. Only the validity of the immediate context of the invocation and conversion is considered.

    -?- In every constructor that takes a string_view parameter name, let converted-tzptr be a variable of type TimeZonePtr that is copy-initialized from traits::locate_zone(name).

    […]

    explicit zoned_time(string_view name);
    

    -7- Constraints: traits::locate_zone(string_view{}) is a well-formed expression and zoned_time is constructible from the return type of traits::locate_zone(string_view{}) locatable-as-tzptr is true.

    -8- Effects: Initializes zone_ with traits::locate_zone(name) and default constructs tp_.

    […]

    zoned_time(string_view name, const sys_time<Duration>& st);
    

    -13- Constraints: zoned_time is constructible from the return type of traits::locate_zone(name) and stlocatable-as-tzptr is true.

    -14- Effects: Equivalent to construction with {traits::locate_zone(name)std::move(converted-tzptr), st}.

    […]

    zoned_time(string_view name, const local_time<Duration>& tp);
    

    -18- Constraints: locatable-as-tzptr is true and zoned_time is constructible from the return type of traits::locate_zone(name)TimeZonePtr and tp.

    -19- Effects: Equivalent to construction with {traits::locate_zone(name)std::move(converted-tzptr), tp}.

    […]

    zoned_time(string_view name, const local_time<Duration>& tp, choose c);
    

    -23- Constraints: locatable-as-tzptr is true and zoned_time is constructible from the return type of traits::locate_zone(name)TimeZonePtr, local_time<Duration>, and choose.

    -24- Effects: Equivalent to construction with {traits::locate_zone(name)std::move(converted-tzptr), tp, c}.

    […]

    template<class Duration2, class TimeZonePtr2>
      zoned_time(string_view name, const zoned_time<Duration2, TimeZonePtr2>& y);
    

    -32- Constraints: locatable-as-tzptr is true and zoned_time is constructible from the return type of traits::locate_zone(name)TimeZonePtr and the type zoned_time<Duration2, TimeZonePtr2>.

    -33- Effects: Equivalent to construction with {traits::locate_zone(name)std::move(converted-tzptr), y}.

    template<class Duration2, class TimeZonePtr2>
      zoned_time(string_view name, const zoned_time<Duration2, TimeZonePtr2>& y, choose c);
    

    -34- Constraints: locatable-as-tzptr is true and zoned_time is constructible from the return type of traits::locate_zone(name)TimeZonePtr, the type zoned_time<Duration2, TimeZonePtr2>, and the type choose.

    -35- Effects: Equivalent to construction with {traits::locate_zone(name)std::move(converted-tzptr), y, c}.