Title
Overflow cannot be ill-formed for chrono::duration integer literals
Status
open
Section
[time.duration.literals]
Submitter
Jonathan Wakely

Created on 2014-05-16.00:00:00 last changed 2 weeks ago

Messages

Date: 2026-06-16.13:04:35

Proposed resolution:

This wording is relative to N5046.

Three options are presented, choose only one.
Option A
  1. Modify [time.duration.literals] as indicated:

    -1- This subclause describes literal suffixes for constructing duration literals. The suffixes `h`, `min`, `s`, `ms`, `us`, `ns` denote duration values of the corresponding types `hours`, `minutes`, `seconds`, `milliseconds`, `microseconds`, and `nanoseconds` respectively if they are applied to integer-literals.

    -2- If any of these suffixes are is applied to a floating-point-literal the result is a `chrono::duration` literal with an unspecified floating-point representation.

    -3- If any of these suffixes are is applied to an integer-literal and the parameter cannot be represented in the `rep` type of the return type, the resulting `chrono::duration` value cannot be represented in the result type because of overflow, the program is ill-formed.

    -4- [Example 1: The following code shows some duration literals.

    using namespace std::chrono_literals;
    auto constexpr aday=24h;
    auto constexpr lesson=45min;
    auto constexpr halfanhour=0.5h;
    
    end example]

    constexpr consteval chrono::hours                                 operator""h(unsigned long long hours);
    constexpr consteval chrono::duration<unspecified, ratio<3600, 1>> operator""h(long double hours);
    

    -5- Returns: A `duration` literal value representing `hours` hours.

    constexpr consteval chrono::minutes                             operator""min(unsigned long long minutes);
    constexpr consteval chrono::duration<unspecified, ratio<60, 1>> operator""min(long double minutes);
    

    -6- Returns: A `duration` literal value representing `minutes` minutes.

    constexpr consteval chrono::seconds               operator""s(unsigned long long seconds);
    constexpr consteval chrono::duration<unspecified> operator""s(long double seconds);
    

    -7- Returns: A `duration` literal value representing `seconds` seconds.

    -8- [Note 1: The same suffix `s` is used for `basic_string` but there is no conflict, since duration suffixes apply to numbers and string literal suffixes apply to character array literals. — end note]

    constexpr consteval chrono::milliseconds                operator""ms(unsigned long long msec);
    constexpr consteval chrono::duration<unspecified, milli> operator""ms(long double msec);
    

    -9- Returns: A `duration` literal value representing `msec` milliseconds.

    constexpr consteval chrono::microseconds                operator""us(unsigned long long usec);
    constexpr consteval chrono::duration<unspecified, micro> operator""us(long double usec);
    

    -10- Returns: A `duration` literal value representing `usec` microseconds.

    constexpr consteval chrono::nanoseconds                operator""ns(unsigned long long nsec);
    constexpr consteval chrono::duration<unspecified, nano> operator""ns(long double nsec);
    

    -11- Returns: A `duration` literal value representing `nsec` nanoseconds.

  2. Add [diff.cpp26.duration] to Annex C:

    C.1.? Clause [time]: Time library

    Affected subclause: [time.duration.literals]

    Change: Literal operators for `duration` literals are immediate functions.

    Rationale: Allow checking for overflow.

    Effect on original feature: Valid C++ 2026 code that used function call syntax and non-constant arguments to create duration literals is ill-formed in this document.

    [Example ?:

    int n = 60;
    auto t = std::chrono::literals::operator""s(n); // ill-formed; previously well-formed
    
    end example]

Option B
  1. Modify [time.duration.literals] as indicated:

    -1- This subclause describes literal suffixes for constructing duration literals. The suffixes `h`, `min`, `s`, `ms`, `us`, `ns` denote duration values of the corresponding types `hours`, `minutes`, `seconds`, `milliseconds`, `microseconds`, and `nanoseconds` respectively if they are applied to integer-literals.

    -2- If any of these suffixes are is applied to a floating-point-literal the result is a `chrono::duration` literal with an unspecified floating-point representation.

    -3- If any of these suffixes are is applied to an integer-literal and the parameter cannot be represented in the `rep` type of the return type, the resulting `chrono::duration` value cannot be represented in the result type because of overflow, the program is ill-formed.

    -?- It is unspecified whether the literal operators below are usable only as the suffix of a user-defined-literal ([lex.ext]), or whether they can also be called using function call notation. If they can be called using function call notation, using `unsigned long long` parameters that cannot be represented in the `rep` type of the return type is ill-formed, no diagnostic required.

    Option B should also do the "`duration` literal value" drive-by fix, and probably update Annex C as well.
Option C
  1. Modify [time.duration.literals] as indicated:

    -1- This subclause describes literal suffixes for constructing duration literals. The suffixes `h`, `min`, `s`, `ms`, `us`, `ns` denote duration values of the corresponding types `hours`, `minutes`, `seconds`, `milliseconds`, `microseconds`, and `nanoseconds` respectively if they are applied to integer-literals.

    -2- If any of these suffixes are is applied to a floating-point-literal the result is a `chrono::duration` literal with an unspecified floating-point representation.

    -3- If any of these suffixes are applied to an integer-literal and the resulting `chrono::duration` value cannot be represented in the result type because of overflow, the program is ill-formed.

Date: 2026-06-15.00:00:00

[ 2026-06-16; Jonathan adds wording. ]

The library has no way to distinguish the case where a suffix is "applied to an integer literal", as opposed to using function call notation like `operator""s(123)`. There is never overflow, because converting `unsigned long long` to a `rep` such as `signed long long` is always well-formed, just not value-preserving. Unless it is used as a constant subexpression, a user-defined-literal such as `123s` is not constant evaluated, so in general checking the value at compile-time is unimplementable.

If we made these operators `consteval` then using them as the suffix of a user-defined-literal would always be a constant expression. It would make it ill-formed to call `operator""s(some_variable)` but I consider that perfectly acceptable. Such uses are absurd, and the existing wording is all specified in terms of suffixes anyway, not in terms of function calls to those operators. P3931R0 proposes making these (and other literal operators) consteval, which would resolve this issue by making it implementable.

Alternatively, we could permit the integral literal operators to be implemented as literal operator templates, i.e. template<char... Digits>, as this makes it possible to check for overflow. This is what libstdc++ has done since the duration literals were first implemented.

Alternatively, we could just remove the rule saying that overflow is detected. Neither libc++ nor MSVC implements the overflow check, so if it was a problem that affects many users we'd have heard about it.

Date: 2014-11-08.16:43:57

[ Urbana 2014-11-07: Move to Open ]

Date: 2014-05-16.00:00:00

[time.duration.literals] p3 says:

If any of these suffixes are applied to an integer literal and the resulting chrono::duration value cannot be represented in the result type because of overflow, the program is ill-formed.

Ill-formed requires a diagnostic at compile-time, but there is no way to detect the overflow from unsigned long long to the signed duration<>::rep type.

Overflow could be detected if the duration integer literals were literal operator templates, otherwise overflow can either be undefined or a run-time error, not ill-formed.

History
Date User Action Args
2026-06-16 11:40:48adminsetmessages: + msg16479
2026-06-16 11:40:48adminsetmessages: + msg16478
2014-11-08 16:43:57adminsetmessages: + msg7173
2014-11-08 16:43:57adminsetstatus: new -> open
2014-05-16 00:00:00admincreate