Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time units #52556

Closed
wants to merge 12 commits into from

Conversation

Projects
None yet
@newpavlov
Copy link
Contributor

newpavlov commented Jul 20, 2018

This PR adds NANOSECOND, MICROSECOND, MILLISECOND, SECOND constants to time module for both std and core. Instead of sleep(Duration::from_millis(10)) it will allow us to write:

use std::time::MILLISECOND as MS;

sleep(10*MS);

As was discussed in #51610 adding constants for common durations will make creation of Duration significantly more ergonomic. This PR is a draft which can be changed upon discussion. Small explanation of the choice made in this PR:

  • Why NANOSECOND and not NS? While I think the latter is usually more ergonomic, abbreviation confuses error messages and can be ambiguous in some situations. Full names can be shortened via aliasing as was shown in the example earlier. Additionally this naming will be similar to the other languages (in particular to Go and C++).
  • Why not use a separate module time::units? I think that a separate module will be redundant, currently time module has only one constant UNIX_EPOCH, thus they will not be lost in the documentation, and it will help with teaching existence of those constants.
  • Why implement Mul<Duration> for u32? This will allow us to write thread::sleep(10*M + 20*S) instead of less pleasant thread::sleep(M*10 + S*20). Ideally I would like to have a way to describe commutative property of multiplication in this case to the type system, but oh well...
  • Why no MINUTE, HOUR and DAY? While as units accepted for use with the SI they are strictly defined in number of seconds, there is caveats to those units if UTC is considered, e.g. hour can be 3,599–3,601 seconds long, depending on conditions. Thus to avoid confusion some argue its probably better to be conservative and not include them. (see #47097 for more context) Though we probably could use prefixes like SI_ or STD_ for those units to highlight the difference from UTC units. UPD: they are included back. Final decision can be made on feature stabilization.
  • No RFC? I think this change is too small for a separate RFC. Although it could be useful to link this PR on reddit and internals forum.

UPD: PR was updated based on replies.
UPD2: It looks like the prevalent opinion is that custom suffixes will be a better solution, i.e. an ability to write something like this:

use std::time::literals::{s, ms};
sleep(1s + 1ms);

So even if this feature will get merged, it will probably will not be stabilized and removed at some point.

@rust-highfive

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

r? @Kimundi

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive

This comment was marked as outdated.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:03:46]    Compiling build_helper v0.1.0 (file:///checkout/src/build_helper)
[00:03:50] error[E0544]: multiple stability levels
[00:03:50]   --> libcore/time.rs:42:1
[00:03:50]    |
[00:03:50] 42 | #[unstable(feature = "time_units", issue = "0")]
[00:03:50] 
[00:03:52]    Compiling compiler_builtins v0.0.0 (file:///checkout/src/rustc/compiler_builtins_shim)
[00:03:52]    Compiling cmake v0.1.31
[00:03:52]    Compiling alloc_jemalloc v0.0.0 (file:///checkout/src/liballoc_jemalloc)
---
[00:04:00] warning: build failed, waiting for other jobs to finish...
[00:04:09] error: build failed
[00:04:09] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind jemalloc backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "--message-format" "json"
[00:04:09] expected success, got: exit code: 101
[00:04:09] thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1119:9
[00:04:09] travis_fold:end:stage0-std

[00:04:09] travis_time:end:stage0-std:start=1532047805421941556,finish=1532047828482829589,duration=23060888033


[00:04:09] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap build
[00:04:09] Build completed unsuccessfully in 0:00:24
[00:04:09] Makefile:28: recipe for target 'all' failed
[00:04:09] make: *** [all] Error 1

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:1a399f84
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
travis_time:end:2578e501:start=1532047828950354602,finish=1532047828956191404,duration=5836802
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:0c1ea860
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:1bb205d8
travis_time:start:1bb205d8
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:02ba2d0c
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 20, 2018

Hm, what will be the best approach to solve the issue with #[unstable(..)] attribute?

@@ -501,6 +524,15 @@ impl Mul<u32> for Duration {
}
}

#[unstable(feature = "time_units", issue = "0")]
impl Mul<Duration> for u32 {

This comment has been minimized.

@kennytm

kennytm Jul 20, 2018

Member

This impl is going to be insta-stable unfortunately.

This comment has been minimized.

@newpavlov

newpavlov Jul 20, 2018

Author Contributor

Should I keep the attribute or use instead something like #[stable(feature = "time_units", since = "1.29.0")]?

This comment has been minimized.

@kennytm

kennytm Jul 20, 2018

Member

@newpavlov The latter (with a different feature name, otherwise tidy will reject it).

This comment has been minimized.

@newpavlov

newpavlov Jul 20, 2018

Author Contributor

Hm, what should I use for feature then? With time_units it can not be built.

UPD: Ah, haven't noticed your update. :)

const H: Duration = Duration::from_secs(60*60);
/// 1 day `Duration`
#[unstable(feature = "time_units", issue = "0")]
const D: Duration = Duration::from_secs(24*60*60);

This comment has been minimized.

@kennytm

kennytm Jul 20, 2018

Member

Similar to #47097, I doubt we want to support hours and days.

Abbreviating minutes to M is also confusing (months? meters?). The SI standard short form MIN conflicts in meaning with "minimum". I would like to leave this out as well, keeping only S, MS, US and NS.

@@ -30,6 +30,7 @@ use sys_common::FromInner;

#[stable(feature = "time", since = "1.3.0")]
pub use core::time::Duration;
pub use core::time::{NS, US, MS, S, M, H, D};

This comment has been minimized.

@kennytm

kennytm Jul 20, 2018

Member

This line needs an #[unstable] attribute.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 20, 2018

Prior art: C++ spells the types out in full, https://en.cppreference.com/w/cpp/header/chrono#Convenience_Typedefs, though the literal suffixes abbreviate.

The consts are a bit awkward since they encourage things like d+S, and the casing convention is unfortunate, as S is siemens and H is henrys, and M is 106.

The types in C++ are often used as functions; what if these became function instead? The reading order is admittedly backwards, but sleep(hours(1)); feels pretty good to me.

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:03:50]    Compiling unwind v0.0.0 (file:///checkout/src/libunwind)
[00:03:55] error[E0544]: multiple stability levels
[00:03:55]   --> libcore/time.rs:42:1
[00:03:55]    |
[00:03:55] 42 | #[unstable(feature = "time_units", issue = "0")]
[00:03:55] 
[00:03:56]    Compiling compiler_builtins v0.0.0 (file:///checkout/src/rustc/compiler_builtins_shim)
[00:03:56]    Compiling cmake v0.1.31
[00:03:56]    Compiling alloc_jemalloc v0.0.0 (file:///checkout/src/liballoc_jemalloc)
---
travis_time:end:1badcc2e:start=1532079468001998045,finish=1532079468008235608,duration=6237563
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:089ca73e
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:0cf67578
travis_time:start:0cf67578
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 20, 2018

For now I've removed minute, hour and day. Personally I don't have a strong need for them, so I guess it could be added later if someone will push for it. Although I'll note that #47097 the main issue was with dasy, not with hours and minutes, plus Go has hour and minutes as well (but not days).

@scottmcm
I think no one will think about S in sleep(10*S) as of siemens. Plus as was noted you always can use time::S. I think that sleep(10*M + 20*S) is a better option than sleep(minutes(10) + seconds(20)). An alternative solution (and probably the most ergonomic) will be to use (imported) custom literals, so we could write sleep(10m + 20s), but I don't know about proposal which have an implementation chance in the near future.

BTW if Duration::new will become const fn we could probably consider deprecation of Duration::from_* methods.

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:04:02]    Compiling rustc_tsan v0.0.0 (file:///checkout/src/librustc_tsan)
[00:04:09] warning: constant item is never used: `NS`
[00:04:09]   --> libcore/time.rs:36:1
[00:04:09]    |
[00:04:09] 36 | const NS: Duration = Duration::from_nanos(1);
[00:04:09]    |
[00:04:09]    = note: #[warn(dead_code)] on by default
[00:04:09] 
[00:04:09] warning: constant item is never used: `US`
[00:04:09] warning: constant item is never used: `US`
[00:04:09]   --> libcore/time.rs:39:1
[00:04:09]    |
[00:04:09] 39 | const US: Duration = Duration::from_micros(1);
[00:04:09] 
[00:04:09] warning: constant item is never used: `MS`
[00:04:09]   --> libcore/time.rs:42:1
[00:04:09]    |
[00:04:09]    |
[00:04:09] 42 | const MS: Duration = Duration::from_millis(1);
[00:04:09] 
[00:04:09] warning: constant item is never used: `S`
[00:04:09]   --> libcore/time.rs:45:1
[00:04:09]    |
[00:04:09]    |
[00:04:09] 45 | const S: Duration = Duration::from_secs(1);
[00:04:09] 
[00:04:09] error: This node does not have a stability attribute
[00:04:09]    --> libcore/time.rs:517:1
[00:04:09]     |
[00:04:09]     |
[00:04:09] 517 | / impl Mul<Duration> for u32 {
[00:04:09] 518 | |     type Output = Duration;
[00:04:09] 519 | |
[00:04:09] 520 | |     fn mul(self, rhs: Duration) -> Duration {
[00:04:09] 521 | |         rhs.checked_mul(self).expect("overflow when multiplying scalar by duration")
[00:04:09] 523 | | }
[00:04:09]     | |_^
[00:04:09] 
[00:04:10] error: aborting due to previous error

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:04:08]    Compiling rustc_msan v0.0.0 (file:///checkout/src/librustc_msan)
[00:04:14] error: This node does not have a stability attribute
[00:04:14]    --> libcore/time.rs:517:1
[00:04:14]     |
[00:04:14] 517 | / impl Mul<Duration> for u32 {
[00:04:14] 518 | |     type Output = Duration;
[00:04:14] 519 | |
[00:04:14] 520 | |     fn mul(self, rhs: Duration) -> Duration {
[00:04:14] 521 | |         rhs.checked_mul(self).expect("overflow when multiplying scalar by duration")
[00:04:14] 523 | | }
[00:04:14]     | |_^
[00:04:14] 
[00:04:17] error: build failed
[00:04:17] error: build failed
[00:04:17] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind jemalloc backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "--message-format" "json"
[00:04:17] expected success, got: exit code: 101
[00:04:17] thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1119:9
[00:04:17] travis_fold:end:stage0-std

[00:04:17] travis_time:end:stage0-std:start=1532081533014968808,finish=1532081558199578374,duration=25184609566


[00:04:17] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap build
[00:04:17] Build completed unsuccessfully in 0:00:26
[00:04:17] make: *** [all] Error 1
[00:04:17] Makefile:28: recipe for target 'all' failed

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:04:13]    Compiling panic_unwind v0.0.0 (file:///checkout/src/libpanic_unwind)
[00:04:14] error[E0432]: unresolved import `core::time::M`
[00:04:14]   --> libstd/time.rs:34:37
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |                                     ^ no `M` in `time`. Did you mean to use `MS`?
[00:04:14] error[E0432]: unresolved import `core::time::H`
[00:04:14]   --> libstd/time.rs:34:40
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |                                        ^ no `H` in `time`. Did you mean to use `S`?
[00:04:14] error[E0432]: unresolved import `core::time::D`
[00:04:14]   --> libstd/time.rs:34:43
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |                                           ^ no `D` in `time`. Did you mean to use `S`?
[00:04:14] error[E0658]: use of unstable library feature 'time_units'
[00:04:14]   --> libstd/time.rs:34:22
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |
[00:04:14]    |
[00:04:14]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:14] error[E0658]: use of unstable library feature 'time_units'
[00:04:14]   --> libstd/time.rs:34:26
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |
[00:04:14]    |
[00:04:14]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:14] error[E0658]: use of unstable library feature 'time_units'
[00:04:14]   --> libstd/time.rs:34:30
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |
[00:04:14]    |
[00:04:14]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:14] error[E0658]: use of unstable library feature 'time_units'
[00:04:14]   --> libstd/time.rs:34:34
[00:04:14]    |
[00:04:14]    |
[00:04:14] 34 | pub use core::time::{NS, US, MS, S, M, H, D};
[00:04:14]    |
[00:04:14]    |
[00:04:14]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:16] error: aborting due to 7 previous errors
[00:04:16] 
[00:04:16] Some errors occurred: E0432, E0658.
[00:04:16] For more information about an error, try `rustc --explain E0432`.
[00:04:16] For more information about an error, try `rustc --explain E0432`.
[00:04:16] error: Could not compile `std`.
[00:04:16] 
[00:04:16] Caused by:
[00:04:16]   process didn't exit successfully: `/checkout/obj/build/bootstrap/debug/rustc --crate-name std libstd/lib.rs --color always --error-format json --crate-type dylib --crate-type rlib --emit=dep-info,link -C prefer-dynamic -C opt-level=2 --cfg feature="alloc_jemalloc" --cfg feature="backtrace" --cfg feature="jemalloc" --cfg feature="panic-unwind" --cfg feature="panic_unwind" -C metadata=38eda8139e25afc6 -C extra-filename=-38eda8139e25afc6 --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps --target x86_64-unknown-linux-gnu -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/release/deps --extern alloc=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/liballoc-0fa369be6843d38b.rlib --extern alloc_jemalloc=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/liballoc_jemalloc-d44ab1cdae3c5d5f.rlib --extern alloc_system=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/liballoc_system-61125bfca7e472f5.rlib --extern compiler_builtins=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libcompiler_builtins-b64848753b7b1fae.rlib --extern core=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libcore-13801a3823f081b4.rlib --extern libc=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/liblibc-6b8b73430c4ddfaf.rlib --extern panic_abort=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libpanic_abort-6dd09c3866f99ef9.rlib --extern panic_unwind=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libpanic_unwind-8ca8a77f92241276.rlib --extern rustc_asan=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/librustc_asan-c00ded6ab9dc527a.rlib --extern rustc_lsan=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/librustc_lsan-0045e7e201e984fa.rlib --extern rustc_msan=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/librustc_msan-8f8910030c71780d.rlib --extern rustc_tsan=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/librustc_tsan-06bfec7617605ba9.rlib --extern std_unicode=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libstd_unicode-ea8c3e35572b37f6.rlib --extern unwind=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-std/x86_64-unknown-linux-gnu/release/deps/libunwind-ff87cc4f36401518.rlib -L native=/checkout/obj/build/x86_64-unknown-linux-gnu/native/libbacktrace/ -L nati

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:04:12]    Compiling panic_unwind v0.0.0 (file:///checkout/src/libpanic_unwind)
[00:04:13] error[E0658]: use of unstable library feature 'time_units'
[00:04:13]   --> libstd/time.rs:34:22
[00:04:13]    |
[00:04:13] 34 | pub use core::time::{NS, US, MS, S};
[00:04:13]    |
[00:04:13]    |
[00:04:13]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:13] error[E0658]: use of unstable library feature 'time_units'
[00:04:13]   --> libstd/time.rs:34:26
[00:04:13]    |
[00:04:13]    |
[00:04:13] 34 | pub use core::time::{NS, US, MS, S};
[00:04:13]    |
[00:04:13]    |
[00:04:13]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:13] error[E0658]: use of unstable library feature 'time_units'
[00:04:13]   --> libstd/time.rs:34:30
[00:04:13]    |
[00:04:13]    |
[00:04:13] 34 | pub use core::time::{NS, US, MS, S};
[00:04:13]    |
[00:04:13]    |
[00:04:13]    = help: add #![feature(time_units)] to the crate attributes to enable
[00:04:13] error[E0658]: use of unstable library feature 'time_units'
[00:04:13]   --> libstd/time.rs:34:34
[00:04:13]    |
[00:04:13]    |
[00:04:13] 34 | pub use core::time::{NS, US, MS, S};
[00:04:13]    |
[00:04:13]    |
[00:04:13]    = help: add #![feature(time_units)] to the crate attributes to enable

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive

This comment was marked as resolved.

Copy link
Collaborator

rust-highfive commented Jul 20, 2018

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:43:04] ....................................................................................................
[00:43:09] i........................................................................i..........................
[00:43:11] ....................................................................................................
[00:43:14] ....................................................................................................
[00:43:16] ...F................................................................................................
[00:43:21] ....................................................................................................
[00:43:24] ....................................................................................................
[00:43:27] ..........................................................................i.........................
[00:43:29] .............................................................................i......................
---
[00:43:43] ....................................................................................................
[00:43:47] ....................................................................................................
[00:43:50] .......................................i............................................................
[00:43:53] .............................i......................................................................
[00:43:57] .........................................F..........................................................
[00:44:04] ................................................i...................................................
[00:44:06] ..................................i....
[00:44:06] failures:
[00:44:06] 
[00:44:06] 
[00:44:06] ---- [ui] ui/error-codes/E0423.rs stdout ----
[00:44:06] diff of stderr:
[00:44:06] 
[00:44:06] 30    |
[00:44:06] 31 LL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
[00:44:06] 32    |                                ^ did you mean `(S { /* fields */ })`?
[00:44:06] + help: possible better candidate is found in another module, you can import it into scope
[00:44:06] +    |
[00:44:06] + LL | use std::time::S;
[00:44:06] 33 
[00:44:06] 33 
[00:44:06] 34 error[E0423]: expected value, found struct `T`
[00:44:06] 35   --> $DIR/E0423.rs:25:8
[00:44:06] 
[00:44:06] The actual stderr differed from the expected stderr.
[00:44:06] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0423/E0423.stderr
[00:44:06] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0423/E0423.stderr
[00:44:06] To update references, rerun the tests and pass the `--bless` flag
[00:44:06] To only update this specific test, also pass `--test-args error-codes/E0423.rs`
[00:44:06] error: 1 errors occurred comparing output.
[00:44:06] status: exit code: 1
[00:44:06] status: exit code: 1
[00:44:06] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/error-codes/E0423.rs" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0423/a" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0423/auxiliary" "-A" "unused"
[00:44:06] ------------------------------------------
[00:44:06] 
[00:44:06] ------------------------------------------
[00:44:06] stderr:
[00:44:06] stderr:
[00:44:06] ------------------------------------------
[00:44:06] {"message":"expected type, found `1`","code":null,"level":"error","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":670,"byte_end":671,"line_start":22,"line_end":22,"column_start":39,"column_end":40,"is_primary":true,"text":[{"text":"    if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!(\"Ok\"); }","highlight_start":39,"highlight_end":40}],"label":"expecting a type here because of type ascription","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: expected type, found `1`\n  --> /checkout/src/test/ui/error-codes/E0423.rs:22:39\n   |\nLL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!(\"Ok\"); }\n   |                                       ^ expecting a type here because of type ascription\n\n"}
[00:44:06] {"message":"expected expression, found `==`","code":null,"level":"error","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423. as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":521,"byte_end":524,"line_start":14,"line_end":14,"column_start":13,"column_end":16,"is_primary":true,"text":[{"text":"    let f = Foo(); //~ ERROR E0423","highlight_start":13,"highlight_end":16}],"label":"did you mean `foo`?","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":521,"byte_end":524,"line_start":14,"line_end":14,"column_start":13,"column_end":16,"is_primary":true,"text":[{"text":"    let f = Foo(); //~ ERROR E0423","highlight_start":13,"highlight_end":16}],"label":"did you mean `Foo { /* fields */ }`?","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0423]: expected function, found struct `Foo`\n  --> /checkout/src/test/ui/error-codes/E0423.rs:14:13\n   |\nLL |     let f = Foo(); //~ ERROR E0423\n   |             ^^^\n   |             |\n   |             did you mean `foo`?\n   |             did you mean `Foo { /* fields */ }`?\n\n"}
[00:44:06] {"message":"expected value, found struct `S`","code":{"code":"E0423","explanation":"\nAn identifier was used like a function name or a value was expected and the\nidentifier exists but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":663,"byte_end":664,"line_start":22,"line_end":22,"column_start":32,"column_end":33,"is_primary":true,"text":[{"text":"    if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!(\"Ok\"); }","highlight_start":32,"highlight_end":33}],"label":"did you mean `(S { /* fields */ })`?","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"possible better candidate is found in another module, you can import it into scope","code":null,"level":"help","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":467,"byte_end":467,"line_start":11,"line_end":11,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main () {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::time::S;\n\n","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0423]: expected value, found struct `S`\n  --> /checkout/src/test/ui/error-codes/E0423.rs:22:32\n   |\nLL |     if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!(\"Ok\"); }\n   |                                ^ did you mean `(S { /* fields */ })`?\nhelp: possible better candidate is found in another module, you can import it into scope\n   |\nLL | use std::time::S;\n   |\n\n"}
[00:44:06] {"message":"expected value, found struct `T`","code":{"code":"E0423","explanation":"\nAn identifier was used like a function name or a value was expected and the\nidentifier exists but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfu":"E0423","explanation":"\nAn identifier was used like a function name or a value was expected and the\nidentifier exists but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/error-codes/E0423.rs","byte_start":891,"byte_end":906,"line_start":31,"line_end":31,"column_start":14,"column_end":29,"is_primary":true,"text":[{"text":"    for _ in std::ops::Range { start: 0, end: 10 } {}","highlight_start":14,"highlight_end":29}],"label":"did you mean `(std::ops::Range { /* fields */ })`?","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0423]: expected value, found struct `std::ops::Range`\n  --> /checkout/src/test/ui/error-codes/E0423.rs:31:14\n   |\nLL |     for _ in std::ops::Range { start: 0, end: 10 } {}\n   |              ^^^^^^^^^^^^^^^ did you mean `(std::ops::Range { /* fields */ })`?\n\n"}
[00:44:06] {"message":"aborting due to 7 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 7 previous errors\n\n"}
[00:44:06] {"message":"For more information about this error, try `rustc --explain E0423`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0423`.\n"}
[00:44:06] ------------------------------------------
[00:44:06] 
[00:44:06] thread '[ui] ui/error-codes/E0423.rs' panicked at 'explicit panic', tools/compiletest/src/runtest.rs:3137:9
[00:44:06] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[00:44:06] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[00:44:06] 
[00:44:06] ---- [ui] ui/resolve/privacy-struct-ctor.rs stdout ----
[00:44:06] diff of stderr:
[00:44:06] 
[00:44:06] 16    |
[00:44:06] 17 LL |     S;
[00:44:06] 18    |     ^ constructor is not visible here due to private fields
[00:44:06] - help: possible better candidate is found in another module, you can import it into scope
[00:44:06] + help: possible better candidates are found in other modules, you can import them into scope
[00:44:06] 20    |
[00:44:06] 21 LL | use m::S;
[00:44:06] 
[00:44:06] 
[00:44:06] + LL | use std::time::S;
[00:44:06] 23 
[00:44:06] 24 error[E0423]: expected value, found struct `S2`
[00:44:06] 25   --> $DIR/privacy-struct-ctor.rs:48:5
[00:44:06] 
[00:44:06] 
[00:44:06] 32    |
[00:44:06] 33 LL |     xcrate::S;
[00:44:06] 34    |     ^^^^^^^^^ constructor is not visible here due to private fields
[00:44:06] - help: possible better candidate is found in another module, you can import it into scope
[00:44:06] + help: possible better candidates are found in other modules, you can import them into scope
[00:44:06] 36    |
[00:44:06] 37 LL | use m::S;
[00:44:06] +    |
[00:44:06] + LL | use std::time::S;
[00:44:06] 39 
[00:44:06] 39 
[00:44:06] 40 error[E0603]: tuple struct `Z` is private
[00:44:06] 
[00:44:06] The actual stderr differed from the expected stderr.
[00:44:06] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/resolve/privacy-struct-ctor/privacy-struct-ctor.stderr
[00:44:06] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/resolve/privacy-struct-ctor/privacy-struct-ctor.stderr
[00:44:06] To update references, rerun the tests and pass the `--bless` flag
[00:44:06] To only update this specific test, also pass `--test-args resolve/privacy-struct-ctor.rs`
[00:44:06] error: 1 errors occurred comparing output.
[00:44:06] status: exit code: 1
[00:44:06] status: exit code: 1
[00:44:06] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/resolve/privacy-struct-ctor.rs" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/resolve/privacy-struct-ctor/a" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/resolve/privacy-struct-ctor/auxiliary" "-A" "unused"
[00:44:06] ------------------------------------------
[00:44:06] 
[00:44:06] ------------------------------------------
[00:44:06] stderr:
[00:44:06] stderr:
[00:44:06] ------------------------------------------
[00:44:06] {"message":"expected value, found struct `Z`","code":{"code":"E0423","explanation":"\nAn identifier was used like a function name or a value was expected and the\nidentifier exists but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":821,"byte_end":822,"line_start":30,"line_end":30,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"        Z;","highlight_startame or a value was expected and the\nidentifier exists but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1109,"byte_end":1110,"line_start":43,"line_end":43,"column_start":5,"column_end":6,"is_primary":true,"text":[{"text":"    S;","highlight_start":5,"highlight_end":6}],"label":"constructor is not visible here due to private fields","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"possible better candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_nams but it belongs to a different namespace.\n\nFor (an erroneous) example, here a `struct` variant name were used as a\nfunction:\n\n```compile_fail,E0423\nstruct Foo { a: bool };\n\nlet f = Foo();\n// error: expected function, found `Foo`\n// `Foo` is a struct name, but this expression uses it like a function name\n```\n\nPlease verify you didn't misspell the name of what you actually wanted to use\nhere. Example:\n\n```\nfn Foo() -> u32 { 0 }\n\nlet f = Foo(); // ok!\n```\n\nIt is common to forget the trailing `!` on macro invocations, which would also\nyield this error:\n\n```compile_fail,E0423\nprintln(\"\");\n// error: expected function, found macro `println`\n// did you mean `println!(...)`? (notice the trailing `!`)\n```\n\nAnother case where this error is emitted is when a value is expected, but\nsomething else is found:\n\n```compile_fail,E0423\npub mod a {\n    pub const I: i32 = 1;\n}\n\nfn h1() -> i32 {\n    a.I\n    //~^ ERROR expected value, found module `a`\n    // did you mean `a::I`?\n}\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1340,"byte_end":1349,"line_start":53,"line_end":53,"column_start":5,"column_end":14,"is_primary":true,"text":[{"text":"    xcrate::S;","highlight_start":5,"highlight_end":14}],"label":"constructor is not visible here due to private fields","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"possible better candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":885,"byte_end":885,"line_start":35,"line_end":35,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"use m::S; // OK, only the type is imported","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use m::S;\n","suggestion_applicability":"Unspecified","expansion":null},{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":885,"byte_end":885,"line_start":35,"line_end":35,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"use m::S; // OK, only the type is imported","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::time::S;\n","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0423]: expected value, found struct `xcrate::S`\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:53:5\n   |\nLL |     xcrate::S;\n   |     ^^^^^^^^^ constructor is not visible here due to private fields\nhelp: possible better candidates are found in other modules, you can import them into scope\n   |\nLL | use m::S;\n   |\nLL | use std::time::S;\n   |\n\n"}
[00:44:06] {"message":"tuple struct `Z` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":760,"byte_end":764,"line_start":28,"line_end":28,"column_start":9,"column_end":13,"is_primary":true,"text":[{"text":"        n::Z;","highlight_start":9,"highlight_end":13}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0603]: tuple struct `Z` is private\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:28:9\n   |\nLL |         n::Z;\n   |         ^^^^\n\n"}
[00:44:06] {"message":"tuple struct `S` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":989,"byte_end":993,"line_start":39,"line_end":39,"column_start":5,"column_end":9,"is_primary":true,"text":[{"text":"    m::S;","highlight_start":5,"highlight_end":9}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0603]: tuple struct `S` is private\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:39:5\n   |\nLL |     m::S;\n   |     ^^^^\n\n"}
[00:44:06] {"message":"tuple struct `S` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1053,"byte_end":1057,"line_start":41,"line_end":41,"column_start":16,"column_end":20,"is_primary":true,"text":[{"text":"    let _: S = m::S(2);","highlight_start":16,"highlight_end":20}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0603]: tuple struct `S` is private\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:41:16\n   |\nLL |     let _: S = m::S(2);\n   |                ^^^^\n\n"}
[00:44:06] {"message":"tuple struct `Z` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1164,"byte_end":1171,"line_start":45,"line_end":45,"column_start":5,"column_end":12,"is_primary":true,"text":[{"text":"    m::n::Z;","highlight_start":5,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0603]: tuple struct `Z` is private\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:45:5\n   |\nLL |     m::n::Z;\n   |     ^^^^^^^\n\n"}
[00:44:06] {"message":"tuple struct `S` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1279,"byte_end":1291,"line_start":51,"line_end":51,"column_start":5,"column_end":17,"is_primary":true,"text":[{"text":"    xcrate::m::S;","highlight_start":5,"highlight_end":17}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0603]: tuple struct `S` is private\n  --> /checkout/src/test/ui/resolve/privacy-struct-ctor.rs:51:5\n   |\nLL |     xcrate::m::S;\n   |     ^^^^^^^^^^^^\n\n"}
[00:44:06] {"message":"tuple struct `Z` is private","code":{"code":"E0603","explanation":"\nA private item was used outside its scope.\n\nErroneous code example:\n\n```compile_fail,E0603\nmod SomeModule {\n    const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we\n                                            // can't use it outside of the\n                                            // `SomeModule` module.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // error: constant `PRIVATE`\n                                                  //        is private\n```\n\nIn order to fix this error, you need to make the item public by using the `pub`\nkeyword. Example:\n\n```\nmod SomeModule {\n    pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the\n                                                // `pub` keyword.\n}\n\nprintln!(\"const value: {}\", SomeModule::PRIVATE); // ok!\n```\n"},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/resolve/privacy-struct-ctor.rs","byte_start":1411,"byte_end":1426,"line_start":55,"line_end":55,"column_start":5,"column_end":20,"is_primary":true,"text":[{"text":"    xcrate::m::n::Z;","highlight_start":5,"highlight_end":20}],"label"own-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-5.0/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zunstable-options " "--target-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "5.0.0\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always"
[00:44:06] 
[00:44:06] 
[00:44:06] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[00:44:06] Build completed unsuccessfully in 0:01:40
[00:44:06] Build completed unsuccessfully in 0:01:40
[00:44:06] make: *** [check] Error 1
[00:44:06] Makefile:58: recipe for target 'check' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:04d370f0
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
---
143676 ./obj/build/x86_64-unknown-linux-gnu/stage1-std
133184 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu
133180 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release
130536 ./obj/build/bootstrap/debug/incremental/bootstrap-2fbxwhl9tnp02
130532 ./obj/build/bootstrap/debug/incremental/bootstrap-2fbxwhl9tnp02/s-f32tyfis2o-aq09rl-2iqfvo5raelnm
128724 ./obj/build/x86_64-unknown-linux-gnu/stage0-bootstrap-tools/x86_64-unknown-linux-gnu/release
122252 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/deps
121712 ./obj/build/x86_64-unknown-linux-gnu/stage0-bootstrap-tools/x86_64-unknown-linux-gnu/release/deps
107600 ./src/llvm/test/CodeGen
---
30728 ./.git/modules/src/tools/lld/objects/pack
lure.4
travis_fold:start:after_failure.5
travis_time:start:158fe464
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:062ba022
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@varkor

This comment has been minimized.

Copy link
Member

varkor commented Jul 20, 2018

I think spelling out unit names would be a better idea (I don't have a strong opinion about functions vs constants), for the two reasons @scottmcm states (case sensitivity and name collisions) as well as the awkwardness of non-ASCII symbols (for microseconds, for instance). If we just pick the ASCII character that visually looks most similar to a particular non-ASCII character, it's going to exacerbate the other issues and can't necessarily be immediately guessed by a user, which isn't a problem if the full name is used.

You can always alias when you import.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 20, 2018

@varkor
I've updated the PR with renaming. In addition to your arguments S apparently confuses some error messages.

@kennytm
How about using SI_HOUR and SI_DAY? And maybe rename MINUTE to SI_MINUTE as well? They are strictly defined in number seconds without any leap seconds, thus this naming should solve the caveats issue.

@kennytm

This comment has been minimized.

Copy link
Member

kennytm commented Jul 20, 2018

@newpavlov Those SI_ prefix gives it feel of C-style API 😛

IMO 620*S is not really worse than 10*M + 20*S, so I still prefer to not include units above seconds.

@kennytm

This comment has been minimized.

Copy link
Member

kennytm commented Jul 20, 2018

Using u as a substitute of µ is pretty standard in programming (e.g. usleep, see also https://en.wikipedia.org/wiki/Micro-#Symbol_encoding_in_character_sets), although the name US looks funny (🇺🇸).

I'm OK with either abbreviation or spelling out:

  1. S, MS, US, NS, or
  2. SECS, MILLIS, MICROS, NANOS, or
  3. SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS
@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 20, 2018

And what about 93600*S instead of D + 2*H? :P Personally I don't see much reason not to include hour and minute (and day by extension, as it is accepted for use with the SI), especially considering that they are present in other languages. For now I've removed them, lets hear other opinions.

As for SECS, MILLIS and etc., I don't think it will be a good choice, as they will be read as plurals, which they are not. It works for from_* methods because it's implied you will usually call those methods not with 1.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 21, 2018

I've returned MINUTE, HOUR and DAY constants for now. I hope the relevant documentation will be enough to prevent some of the mistakes associated with leap seconds and DST. Final decision can be made on feature stabilization. I think we can stop at day, because week is not accepted as unit which can be used with SI.

@sunjay

This comment has been minimized.

Copy link
Member

sunjay commented Jul 21, 2018

It will be quite strange to find seconds() method in u32 documentation and it will have serious discoverability problems.

The methods could be added on an extension trait in the right module which could be imported whenever these special methods are needed. I'm not saying this as someone for or against the proposal, I just wanted to help with a potential solution to this particular concern.

I actually like both the constant and the method approach and would be totally fine with either.

@matthieu-m

This comment has been minimized.

Copy link

matthieu-m commented Jul 21, 2018

@scottmcm:

The types in C++ are often used as functions; what if these became function instead? The reading order is admittedly backwards, but sleep(hours(1)); feels pretty good to me.

@newpavlov

As I wrote on internals forum, ideal solution for me will be custom literal suffixes à la C++, so we could write code like this:

It would be possible to create a trait SiTimeUnits, implement it for u32, and get:

3.d() + 6.h() + 19.s() + 273.us();

Slightly more verbose (extraneous parentheses), but pretty idiomatic: traits have been used to provide method extensions in Rust forever (SliceExt?).

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 21, 2018

@matthieu-m
I think that constants are much easier to find and explain. And instead of such ad-hoc trait IMO we better push for custom literals functionality.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 21, 2018

a trait SiTimeUnits

I quite like that, actually. Especially because then you import the one trait and it doesn't pollute the namespace the way that importing a bunch of constants does. And fixes the casing issue.

@HeroicKatora

This comment has been minimized.

Copy link

HeroicKatora commented Jul 21, 2018

@matthieu-m I'm not sure about long or short form. I slightly favor the long form similar to the current interfaces (secs, millis, micros, nanos, etc.). In no case would I like a trait with cryptic names such as s in the prelude, but I would be okay with it being an usable trait for those favoring the established definitions of SI units.

@newpavlov In my opinion, traits and being able to introduce new methods provide superior functionality and consistency compared to custom literals. In particular, the tradeoff of complicating the language when we could solve this with existing features does not sound worth here. It is also a little unclear to me what that would specifically accomplish here. Custom literals should give you power to reinterpret the literal in the code, it feels wrong to also use them if one simply wants to convert a conventionally parsed primitive into another type. Keep in mind, C++ has to resort to this style only because it does not have methods on primitive types.

@flexera-cnixon

This comment has been minimized.

Copy link

flexera-cnixon commented Jul 22, 2018

It seems there are enough opinions on this PR that it could make sense for this to be an RFC?

The embedded-hal ecosystem is also thinking about things in this area rust-embedded/embedded-hal#59

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 22, 2018

@HeroicKatora
There is also a cost with "noisiness" of the language. (and Rust already has reputation of being noisy) And I want to see custom literals regardless of why C++ initially introduced them. I think it's a cool feature, learning which will be an improvement for Rust. Custom literals and extending primitives methods will look and feel quite differently. Compare:

sleep(1s + 100ms)
sleep(1.s() + 100.ms())

The latter variant is more noisy, more surprising for beginners (what? is it a method on primitive integer?), more annoying to write and read, while the former takes minimum amount of characters and explicitly shows that you are not dealing with primitive integers, but with something else. Also if we take other units into consideration (which can be implemented by third-party crates, see e.g. embedded-hal link earlier) I think seeing and reading 1m/5s in the code will be more pleasant than 1.m()/5.s().

@HeroicKatora

This comment has been minimized.

Copy link

HeroicKatora commented Jul 22, 2018

@newpavlov You mean noise as in there are three extra characters per suffix? I think I see where you are getting at. But the alternative is additional complexity in language, syntax and all the way down to the grammar. And I'd argue that the parts which you qualified as noise actually help process the code mentally in many cases, especially since it does not necessitate teaching and learning a new kind of rule but simply generalizes being able to call methods on values.

In any case, it now appears that the original proposal does not seem like the best solution to either of us. So I would follow @flexera-cnixon by opening an RFC. I would also extend on my comment above about advantages and disadvantages for literal suffixes there.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 22, 2018

I've published pre-RFC for custom literals on internals forum. Let's continue discussion about them vs trait based approach there.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 23, 2018

I agree with @flexera-cnixon; it seems there's enough of a design space here that this PR should be closed in favour of a discussion on IRLO and/or a full RFC on that repo.

@WiSaGaN

This comment has been minimized.

Copy link
Contributor

WiSaGaN commented Jul 23, 2018

For constants, however, I think it could be very beneficial for these to be associated constants of Duration instead of module constants of time. It adds more context so you know exactly what type it is. Compare time::SECOND versus Duration::SECOND.

I agree with this. We recently stabilized UNIX_EPOCH as associative const of SystemTime. We probably should do the same by adding these units as associative consts of Duration.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 24, 2018

@scottmcm
I agree that ideal solution for this problem is custom literal suffixes, but probably we will not get them in a mid-term. Can't this PR be merged as a stop-gap Nightly-only solution until custom suffixes will be introduced?

@WiSaGaN
Note, that currently you can't write use std::time::Duration::SECOND as S;, so you'll have to write sleep(2*Duration::SECOND) instead of just sleep(2*S) which is obviously unergonomic. And BTW I do not agree with the motivation for associated UNIX_EPOCH which was "it's not very discoverable as a separate const in the module". For me personally it probably would've been harder to find. Though it indeed improves use of UNIX_EPOCH a bit, as you don't have to use a separate import for it any more.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 24, 2018

merged as a stop-gap Nightly-only solution

Why would this be valuable over putting things in a crate? This feature needs no special access to duration internals, nor does it need internal-only features (like intrinsics or similar), so why not just do use duration_consts::S; instead of use std::time::consts::S;, and use it on stable?

(This isn't a method on a prelude trait, so there's no future-conflict hazard with a crate import.)

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 24, 2018

You are right, I guess it can be in a separate crate. But convenience impl Mul<Duration> for u32 must be in the std. Should I create a separate PR for it?

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 24, 2018

@newpavlov Scalar multiplication of durations definitely sounds useful and separable. At least for myself, I've certainly wanted things like 2 * d before, And since trait impls are insta-stable so must be FCP'd, it's probably worth splitting out regardless. (Maybe include scalar division too? Like d += d/2;...)

Oh, impl Mul<u32> for Duration (and Div) already exist. Then I think the symmetric impl is a bug fix.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 24, 2018

Maybe include scalar division too?

I am not sure if I understood you, we already have impl Div<u32> for Duration and result of 2/duration can not have Duration type.

@WiSaGaN

This comment has been minimized.

Copy link
Contributor

WiSaGaN commented Jul 25, 2018

@newpavlov

Note, that currently you can't write use std::time::Duration::SECOND as S;

Is this something not yet implemented or something we shouldn't do? If it is the former, then should we fix that instead?

For me personally it probably would've been harder to find.

UNIX_EPOCH is actually quite unique to SystemTime, so it does not make as much of an impact to the crowdness of std::time. However, we may have many constants like SECOND, HOUR, DAY. Putting them all under std::time can quickly make the namespace messy.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Jul 25, 2018

should we fix that instead?

FWIW, I'd be in support of an RFC to allow useing associated things. I've often thought use Default::default; would be nice, and I like use Duration::SECOND as S; better than forcing S on everyone, without being materially longer.

@kennytm

This comment has been minimized.

Copy link
Member

kennytm commented Jul 25, 2018

If namespace pollution is the only problem we could introduce std::time::consts::{NANOSECOND, ...} just like std::f32::consts::*.

@WiSaGaN

This comment has been minimized.

Copy link
Contributor

WiSaGaN commented Jul 25, 2018

@kennytm

If namespace pollution is the only problem we could introduce std::time::consts::{NANOSECOND, ...} just like std::f32::consts::*.

This was actually discussed in #24915 (comment) where a deprecation of std::f32 module was mentioned, but I am not sure what is the current situation. Maybe we would not have introduced a module or consts if we had associated consts at the time?
Specifically std::f32::consts to me seems more about mathematical constants not const as a language concept.

Overall, I feel it would be beneficial to discuss the general treatment of introducing consts in std as this probably wouldn't be the only time we want to add commonly used consts of a specific type. Some of the questions may be:

  • What should be the general criterion to introduce them in std (comparing to an external crate, etc.)?
  • Where should we put it?
  • Is it worth it to introduce additional language level change to these library types?
@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 26, 2018

BTW what do you think about adding division and multiplication by f32 (or f64)? It has a slight risk of small imprecision, due to how floats work, but I think it will an ergonomic improvement to be able to write 1.25*SECOND.

@newpavlov

This comment has been minimized.

Copy link
Contributor Author

newpavlov commented Jul 28, 2018

I am closing this PR and will create a separate one which will contain only additional impls.

Also I've published durations crate, it will be less pleasant to use than std constants, but I guess it's better than nothing.

@newpavlov newpavlov closed this Jul 28, 2018

@newpavlov newpavlov deleted the newpavlov:time_units branch Jul 28, 2018

bors added a commit that referenced this pull request Sep 19, 2018

Auto merge of #52813 - newpavlov:duration_mul_div_extras, r=alexcrichton
Duration div mul extras

Successor of #52556.

This PR adds the following `impl`s:
- `impl Mul<Duration> for u32` (to allow `10*SECOND` in addition to `SECOND*10`)
- `impl Mul<f64> for Duration` (to allow `2.5*SECOND` vs `2*SECOND + 500*MILLISECOND`)
- `impl Mul<Duration> for f64`
- `impl MulAssign<f64> for Duration`
- `impl Div<f64> for Duration`
- `impl DivAssign<f64> for Duration`
- `impl Div<Duration> for Duration` (`Output = f64`, can be useful e.g. for `duration/MINUTE`)

`f64` is chosen over `f32` to minimize rounding errors. (52 bits fraction precision vs `Duration`'s ~94 bit)

kennytm added a commit to kennytm/rust that referenced this pull request Sep 20, 2018

Rollup merge of rust-lang#52813 - newpavlov:duration_mul_div_extras, …
…r=alexcrichton

Duration div mul extras

Successor of rust-lang#52556.

This PR adds the following `impl`s:
- `impl Mul<Duration> for u32` (to allow `10*SECOND` in addition to `SECOND*10`)
- `impl Mul<f64> for Duration` (to allow `2.5*SECOND` vs `2*SECOND + 500*MILLISECOND`)
- `impl Mul<Duration> for f64`
- `impl MulAssign<f64> for Duration`
- `impl Div<f64> for Duration`
- `impl DivAssign<f64> for Duration`
- `impl Div<Duration> for Duration` (`Output = f64`, can be useful e.g. for `duration/MINUTE`)

`f64` is chosen over `f32` to minimize rounding errors. (52 bits fraction precision vs `Duration`'s ~94 bit)

@stjepang stjepang referenced this pull request Jan 6, 2019

Merged

Add duration constants #57375

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.