Skip to content

Implement clamp_to#150075

Open
Kyuuhachi wants to merge 1 commit into
rust-lang:mainfrom
Kyuuhachi:limit_to
Open

Implement clamp_to#150075
Kyuuhachi wants to merge 1 commit into
rust-lang:mainfrom
Kyuuhachi:limit_to

Conversation

@Kyuuhachi

@Kyuuhachi Kyuuhachi commented Dec 16, 2025

Copy link
Copy Markdown
Contributor

View all comments

Implements the revised version of #147781. Supersedes #147786.

Currently I restrict the ClampBounds trait using a second, perma-unstable feature. I don't know if that's the usual way to deal with this kind of traits, I'd be happy to change it if not.

I currently define NaN as equal to no bound. This is consistent with max and min, but is inconsistent with clamp, which panics.

Changed so that the float versions panic if any bound is NaN, just like clamp does.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 16, 2025
@rustbot

rustbot commented Dec 16, 2025

Copy link
Copy Markdown
Collaborator

r? @ibraheemdev

rustbot has assigned @ibraheemdev.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Comment thread library/core/src/cmp/clamp.rs Outdated
fn clamp(self, value: $t) -> $t {
let (start, end) = self.into_inner();
// Deliberately avoid using `clamp` to handle NaN consistently
value.max(start).min(end)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be very surprised if x.clamp_to(a..=b) were to behave differently at all from x.clamp(a, b), regardless of the various values for x, a, and b.

Isn't clamp moving toward making its NaN behaviour consistent, anyway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but imo it's worse if x.clamp_to(a..) and x.clamp_to(a..=b) handle nan differently. Making all of them panic on nan would be a plausible choice though. It's listed as an unresolved question on the tracking issue.

@clarfonthey clarfonthey Dec 18, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the current code, it does appear that clamp simply panics on NaN, so, I would say that it's reasonable to always panic on NaN for these methods to match that behaviour. But I guess we can discuss that in the tracking issue instead of blocking this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Side note: after a lot of poking around the changes to clamp and its original RFC, it appears that the panicking behaviour was explicitly decided as the best, and it was not an accident. So, I do think that panicking on NaN bounds like clamp does is the best behaviour.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, if it's named like clamp it should behave like clamp. I'm leaving the question as unresolved, though it's pretty likely that it'll end up this way.

I don't currently have any tests that it does panic on nan; should I add that, and if so where?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly would just look at whatever clamp's tests are and try to match them. Could even use some macros to just run the same tests on both functions to make sure the output matches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's some clamp tests in coretests, but I don't know how that system works. Should I just duplicate all the tests for clamp and adjust them for the different shapes of clamp_to? Or just not do that and leave as-is?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kyuuhachi Please do add tests for clamp_to that match the tests for clamp.

Comment thread library/core/src/num/f64.rs Outdated
Comment thread library/core/src/num/f32.rs Outdated
Comment thread library/core/src/num/f16.rs Outdated
Comment thread library/core/src/num/f128.rs Outdated
Comment thread library/core/src/cmp/clamp.rs Outdated
Comment on lines +70 to +79
assert!(!self.start.is_nan(), "min was NaN");
value.max(self.start)
}
}

#[unstable(feature = "clamp_bounds", issue = "147781")]
#[rustc_const_unstable(feature = "clamp_bounds", issue = "147781")]
impl const ClampBounds<$t> for RangeToInclusive<$t> {
fn clamp(self, value: $t) -> $t {
assert!(!self.end.is_nan(), "max was NaN");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, but since these are ranges, you should probably use the start/end naming instead.

Note that std::range::RangeToInclusive uses the name last to represent an inclusive end instead of end, but since these are just for the regular ops ranges, we should match the actual field name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These messages are consistent with clamp though. What is more important, consistency with clamp or with ranges?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kyuuhachi I'd suggest being consistent with ranges, and later we could potentially modify clamp to be consistent with this.

@reddevilmidzy

Copy link
Copy Markdown
Member

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 24, 2026
@rustbot

rustbot commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@Kyuuhachi

Copy link
Copy Markdown
Contributor Author

Oops, didn't realize this was still waiting for action from me. Do all the comments need to be resolved or what?

@joshtriplett

Copy link
Copy Markdown
Member

@Kyuuhachi I responded in the two threads that remain open. With those two addressed, r=me.

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@Kyuuhachi

Copy link
Copy Markdown
Contributor Author

@bors r=joshtriplett

@rust-bors

rust-bors Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

@Kyuuhachi: 🔑 Insufficient privileges: not in review users

@Kyuuhachi

Copy link
Copy Markdown
Contributor Author

@joshtriplett Did I do that wrong?

@conradludgate

Copy link
Copy Markdown
Contributor

Did I do that wrong?

I think you need to:

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 27, 2026
@Kyuuhachi

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@ChrisDenton

Copy link
Copy Markdown
Member

Maybe squish your commits? I'm uncertain if one or two commits would be better it'd be nice to merge some of them at least.

Remove trivial bounds

Panic on NaN

Make assert messages consistent with field names

Add clamp_to coretests

Update to fmt style
@rustbot

rustbot commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@ChrisDenton

Copy link
Copy Markdown
Member

I don't think the reviewer is currently active. I'll add this to my review queue so if nobody reviews this first I'll do it (I think it was more or less approved before, I just need to take a minute to double check).

r? @ChrisDenton

@ChrisDenton

Copy link
Copy Markdown
Member

Thanks!

@bors r=joshtriplett,ChrisDenton

@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

📌 Commit f31860e has been approved by joshtriplett,ChrisDenton

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 1, 2026
@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

⌛ Testing commit f31860e with merge 1c882cc...

Workflow: https://github.com/rust-lang/rust/actions/runs/28521960546

rust-bors Bot pushed a commit that referenced this pull request Jul 1, 2026
Implement clamp_to





Implements the revised version of #147781. Supersedes #147786.

Currently I restrict the ClampBounds trait using a second, perma-unstable feature. I don't know if that's the usual way to deal with this kind of traits, I'd be happy to change it if not.

~~I currently define NaN as equal to no bound. This is consistent with `max` and `min`, but is inconsistent with `clamp`, which panics.~~

Changed so that the float versions panic if any bound is NaN, just like `clamp` does.
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jul 1, 2026
…,ChrisDenton

Implement clamp_to

Implements the revised version of rust-lang#147781. Supersedes rust-lang#147786.

Currently I restrict the ClampBounds trait using a second, perma-unstable feature. I don't know if that's the usual way to deal with this kind of traits, I'd be happy to change it if not.

~~I currently define NaN as equal to no bound. This is consistent with `max` and `min`, but is inconsistent with `clamp`, which panics.~~

Changed so that the float versions panic if any bound is NaN, just like `clamp` does.
@JonathanBrouwer

Copy link
Copy Markdown
Contributor

@bors yield
Yielding to enclosing rollup

@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Auto build was cancelled. Cancelled workflows:

The next pull request likely to be tested is #158660.

rust-bors Bot pushed a commit that referenced this pull request Jul 1, 2026
…uwer

Rollup of 8 pull requests

Successful merges:

 - #150075 (Implement clamp_to)
 - #158169 (Fix debuginfo compression in bootstrap)
 - #158397 (delegation: support simplest output `Self` mapping)
 - #158613 (Fix getrandom fallback test on platforms with `panic=abort`)
 - #158620 (Remove skip_norm_w/i/p().def_id with a helper)
 - #158633 (Remove unnecessary `Clone` derives on resolver types)
 - #158634 (Add missing `needs_drop` check to `DroplessArena`.)
 - #158647 (Document `strip_circumfix` behavior on overlapping prefix and suffix.)
@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

⌛ Testing commit f31860e with merge 8cd0b7c...

Workflow: https://github.com/rust-lang/rust/actions/runs/28524103392

rust-bors Bot pushed a commit that referenced this pull request Jul 1, 2026
Implement clamp_to





Implements the revised version of #147781. Supersedes #147786.

Currently I restrict the ClampBounds trait using a second, perma-unstable feature. I don't know if that's the usual way to deal with this kind of traits, I'd be happy to change it if not.

~~I currently define NaN as equal to no bound. This is consistent with `max` and `min`, but is inconsistent with `clamp`, which panics.~~

Changed so that the float versions panic if any bound is NaN, just like `clamp` does.
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jul 1, 2026
…,ChrisDenton

Implement clamp_to

Implements the revised version of rust-lang#147781. Supersedes rust-lang#147786.

Currently I restrict the ClampBounds trait using a second, perma-unstable feature. I don't know if that's the usual way to deal with this kind of traits, I'd be happy to change it if not.

~~I currently define NaN as equal to no bound. This is consistent with `max` and `min`, but is inconsistent with `clamp`, which panics.~~

Changed so that the float versions panic if any bound is NaN, just like `clamp` does.
@JonathanBrouwer

Copy link
Copy Markdown
Contributor

@bors yield
Yielding to enclosing rollup

@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Auto build was cancelled. Cancelled workflows:

The next pull request likely to be tested is #158661.

rust-bors Bot pushed a commit that referenced this pull request Jul 1, 2026
…uwer

Rollup of 8 pull requests

Successful merges:

 - #150075 (Implement clamp_to)
 - #156716 (tests: fix: parallel frontend test failures: different alloc ids)
 - #158397 (delegation: support simplest output `Self` mapping)
 - #158613 (Fix getrandom fallback test on platforms with `panic=abort`)
 - #158620 (Remove skip_norm_w/i/p().def_id with a helper)
 - #158633 (Remove unnecessary `Clone` derives on resolver types)
 - #158634 (Add missing `needs_drop` check to `DroplessArena`.)
 - #158647 (Document `strip_circumfix` behavior on overlapping prefix and suffix.)
@JonathanBrouwer

Copy link
Copy Markdown
Contributor

💔 I suspect this PR failed tests as part of a rollup
@bors r-

After fixing the problem, consider running a try job for the failed job before re-approving.

Link to failure: #158661 (comment)

@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jul 1, 2026
@rust-bors

rust-bors Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This PR was contained in a rollup (#158661), which was unapproved.

View changes since this unapproval

@clarfonthey

Copy link
Copy Markdown
Contributor

The output is weird, but it appears that cfg(target_has_reliable_f128) didn't always mean the maximum intrinsic was available? Otherwise, I don't understand why this would happen:

---- library/core/src/num/f128.rs - f128::f128::clamp_to (line 1475) stdout ----
unexpected runtime library name: fmaximum_numl
UNREACHABLE executed at /checkout/src/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp:952!
Couldn't compile the test.
\ (no newline at end of output)

@Kyuuhachi

Copy link
Copy Markdown
Contributor Author

That's a fun one. Any idea what to do about it? Could always use the naive if a > b { a } else { b } I guess...

@ChrisDenton

Copy link
Copy Markdown
Member

Seeing as it's wasm32-wasip1 and has_reliable_f128 defaults to true, my first thought is maybe the target spec is wrong? cc @alexcrichton

@alexcrichton

Copy link
Copy Markdown
Member

I wouldn't be surprised if f128 isn't well supported on wasm, and it looks like wasm is hitting the fall-through here and I think it'd be reasonable to disable that for wasm.

Comment on lines +1475 to +1482
/// ```
/// #![feature(f128, clamp_to)]
/// assert_eq!((-3.0f128).clamp_to(-2.0..=1.0), -2.0);
/// assert_eq!(0.0f128.clamp_to(-2.0..=1.0), 0.0);
/// assert_eq!(2.0f128.clamp_to(..=1.0), 1.0);
/// assert_eq!(5.0f128.clamp_to(7.0..), 7.0);
/// assert!(f128::NAN.clamp_to(1.0..=2.0).is_nan());
/// ```

@tgross35 tgross35 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requires a gate behind #[cfg(target_has_reliable_f128_math)] (see the above tests, excluding clamp_magnitude which apparently hasn't gotten updated)

View changes since the review

Comment on lines +1462 to +1467
/// #![feature(f16, clamp_to)]
/// assert_eq!((-3.0f16).clamp_to(-2.0..=1.0), -2.0);
/// assert_eq!(0.0f16.clamp_to(-2.0..=1.0), 0.0);
/// assert_eq!(2.0f16.clamp_to(..=1.0), 1.0);
/// assert_eq!(5.0f16.clamp_to(7.0..), 7.0);
/// assert!(f16::NAN.clamp_to(1.0..=2.0).is_nan());

@tgross35 tgross35 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar with #[cfg(target_has_reliable_f16_math)]

View changes since the review

Comment on lines +1362 to +1402
float_test! {
name: clamp_to_min_greater_than_max,
attrs: {
const: #[cfg(false)],
f16: #[should_panic, cfg(target_has_reliable_f16)],
f32: #[should_panic],
f64: #[should_panic],
f128: #[should_panic, cfg(target_has_reliable_f128)],
},
test {
let _ = Float::ONE.clamp_to(3.0..=1.0);
}
}

float_test! {
name: clamp_to_min_is_nan,
attrs: {
const: #[cfg(false)],
f16: #[should_panic, cfg(target_has_reliable_f16)],
f32: #[should_panic],
f64: #[should_panic],
f128: #[should_panic, cfg(target_has_reliable_f128)],
},
test {
let _ = Float::ONE.clamp_to(Float::NAN..=1.0);
}
}

float_test! {
name: clamp_to_max_is_nan,
attrs: {
const: #[cfg(false)],
f16: #[should_panic, cfg(target_has_reliable_f16)],
f32: #[should_panic],
f64: #[should_panic],
f128: #[should_panic, cfg(target_has_reliable_f128)],
},
test {
let _ = Float::ONE.clamp_to(3.0..=Float::NAN);
}
}

@tgross35 tgross35 Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these require libcalls, they need to be gated under target_has_reliable_fX_math rather than the non-_math version.

View changes since the review

@tgross35

tgross35 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

I wouldn't be surprised if f128 isn't well supported on wasm, and it looks like wasm is hitting the fall-through here and I think it'd be reasonable to disable that for wasm.

It is supported reasonably well on wasm, but everything with LLVM and f128 libm functions is borked right now on all platforms except in specific circumstances (basically only glibc) llvm/llvm-project#44744. The target_has_reliable_f128_math gate is meant to guard this, as opposed to target_has_reliable_f128 for the basic functionality which works well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.