Skip to content

Conversation

@vapdrs
Copy link
Contributor

@vapdrs vapdrs commented Jun 24, 2025

Add a new guidlelines disallowing ArithmeticExpressions to use integer divisors. This is the "MISRA" style counterpart to #132

@netlify
Copy link

netlify bot commented Jun 24, 2025

Deploy Preview for scrc-coding-guidelines ready!

Name Link
🔨 Latest commit e9cdb3b
🔍 Latest deploy log https://app.netlify.com/projects/scrc-coding-guidelines/deploys/68ac79f105e40b000737f964
😎 Deploy Preview https://deploy-preview-136--scrc-coding-guidelines.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vapdrs
Copy link
Contributor Author

vapdrs commented Jun 24, 2025

The check_typos job seems to have encountered a false positive looking at one of the ids

These correspond to the unique ID's for each section.
@vapdrs vapdrs changed the title Add checked arithmetic guidelines [Guideline] Add checked arithmetic guidelines Jun 25, 2025
Comment on lines 106 to 127
.. non_compliant_example::
:id: non_compl_ex_0XeioBrgfh5z
:status: draft

When the division is performed, the right operand is evaluated to zero and the program panics.

.. code-block:: rust
let x = 0;
let x = 5 / x;
.. compliant_example::
:id: compl_ex_k1CD6xoZxhXb
:status: draft

If an overflow occurs, it is explicit that the addition should wrap.

.. code-block:: rust
let y = 135u8
let x = 200u8.wrapping_add(y);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the document allowed to have more than one non-compliant and more than one compliant example?

Since this guideline covers both the divide-by-zero and the arithmetic-overflow cases, I think it's only natural that it would have an example for both :)

Choose a reason for hiding this comment

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

you should have a compliant solution corresponding to each noncompliant example. For example, how do I deal with divide by zero on a compliant solution. Also show the incorrect version of the wrapping example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm unsure if multiple examples are allowed, but these are small and related so I just put both in one code block in 752ba7a

Copy link
Contributor

Choose a reason for hiding this comment

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

We are still at the point where these things can be discussed. If we'd like to have a number of compliant and non-compliant examples, this is possible likely in Sphinx Needs. Opened #141 to track.

Copy link
Contributor

@PLeVasseur PLeVasseur Jul 12, 2025

Choose a reason for hiding this comment

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

Question to @vapdrs, @rcseacord, @felix91gr -- is this something which we think should be addressed as a blocking concern for this PR or mark this as resolved since we have #141 and move on for now?

Copy link
Collaborator

@felix91gr felix91gr Jul 13, 2025

Choose a reason for hiding this comment

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

@PLeVasseur I would much prefer it if we had multiple examples, one for each specific case. Whenever I've read guidelines, having "atomic" (ie indivisible / minimal) examples has been essential for me to understand them quickly and without needing to ask for further help. I think we can benefit a lot if each example addresses a single concern.

So yeah, I think it's best if we block until we have this capability. Sorry, @vapdrs, I'm asking you to wait until we've sorted this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries here. I don't mind waiting.

@vapdrs vapdrs requested review from felix91gr and rcseacord June 27, 2025 20:34
@felix91gr
Copy link
Collaborator

Resolves #20

@felix91gr felix91gr self-assigned this Jun 29, 2025
@felix91gr felix91gr added decidability: decidable A coding guideline which can be checked automatically chapter: expressions labels Jun 29, 2025
@PLeVasseur PLeVasseur linked an issue Jul 5, 2025 that may be closed by this pull request
Copy link
Contributor

@PLeVasseur PLeVasseur left a comment

Choose a reason for hiding this comment

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

Hey @vapdrs -- appreciate this addition! I've left a few suggestions and comments ☺️

vapdrs and others added 3 commits July 14, 2025 17:24
Additionally the code block formatting was updating, and a link was added.

Co-authored-by: Pete LeVasseur <[email protected]>
@felix91gr felix91gr linked an issue Aug 7, 2025 that may be closed by this pull request
@felix91gr felix91gr mentioned this pull request Aug 11, 2025
@felix91gr
Copy link
Collaborator

Damn, I thought the PR would fix itself after a non-conflicting change to main was made. But alas, git's commits are snapshots of the directory, and not changes. It seems like git believes your copy of the spec lock file to be part of your changes, or something.

Because when looking at this branch, the spec lock_file is outdated.

@vapdrs can I ask you to re-merge the latest commits from main into your branch? Sorry for the bother.

With those changes, it should build and I'll be able to give a reasonable final review :3

Copy link
Collaborator

@felix91gr felix91gr left a comment

Choose a reason for hiding this comment

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

I hope I'm not boring you 🫶

This is mostly details - the content and structure itself all look good to me.

Comment on lines 124 to 125
The developer must explicitly indicate the intended behavior when a division by zero occurs, or use a
type for which it is invalid to have a value of zero.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Like in my first comment, I don't think the description here of "explicitly indicate the intended behavior" makes sense now that the PR is focusing uniquely on the division-by-zero scenario.

I'd also change the second point, since it's not that a NonZero<T> with an inner value of zero is invalid.

It's more like it's impossible to have a NonZero<T> with an inner value of zero - unless the user constructs one using unsafe and uses the unchecked_ constructor, which like everything regarding unsafe, probably merits its own entire guideline series. Though in that case, if the user does construct a NonZero<T> using a T of value zero through the unchecked_ method, that's Undefined Behavior.

Anyway. I'm thinking of something like this:

The developer must explicitly:

* Use checked division functions, which make sure a zero divisor is handled separately, or
* To first create divisors using :std:`std::num::NonZero`, which let the programmer prove the divisor is not zero. 

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, I rephrased the suggestion though

@felix91gr
Copy link
Collaborator

Something funny I just realized is that using checked_div and checked_rem should have no less runtime performance than using / and %.

Since in / and % the compiler has to always compare the divisor's value against zero (in order to panic in case it is zero), and checked_div and checked_rem's implementations also have to compare the divisor's value against zero, both pay 1 comparison regardless of the value of the divisor.

And since comparisons tend to be the most expensive of the basic CPU instructions... the big picture in performance is that checked_div and checked_rem are at least as performant as doing the vanilla operations.

Hm. I shall do some codegen testing, I guess.


The alternative scenario is that the compiler can prove the divisor is not zero. In that case, the zero-check and panic branch can be elided from the / and % operations. But if the compiler can prove the divisor is not zero, then the zero-check and the None branch can also be elided from the checked_div and checked_rem operations.

Therefore... both are basically the same in performance, unless the programmer can prove their divisors are not zero using outside information (some domain-specific info the compiler cannot see). And if the programmer can prove their divisors to not be zero, then they could eek some more performance out of unchecked_div or unchecked_rem. But that's only reasonable if they can prove the non-zero-ness: unchecked_div and unchecked_rem give Undefined Behavior whenever the divisor is zero.

@felix91gr
Copy link
Collaborator

felix91gr commented Aug 12, 2025

Indeed! Dividing by NonZero<T> produces a faster assembly than regular / and checked_div: https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=c8fc94e2335fcba5921220be63542786 (instead of Run, select "Show LLVM IR"

@vapdrs
Copy link
Contributor Author

vapdrs commented Aug 12, 2025

Indeed! Dividing by NonZero<T> produces a faster assembly than regular / and checked_div: https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=c8fc94e2335fcba5921220be63542786 (instead of Run, select "Show LLVM IR"

I added a small note to the Rationale about that as well

Copy link
Collaborator

@felix91gr felix91gr left a comment

Choose a reason for hiding this comment

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

I've finally learned how to suggest changes directly.

Just some polish and one typo :)

vapdrs and others added 2 commits August 15, 2025 09:48
Spelling and word choice from review

Co-authored-by: Félix Fischer <[email protected]>
Copy link
Collaborator

@felix91gr felix91gr left a comment

Choose a reason for hiding this comment

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

Beyond these changes, I have nothing more to ask. The PR is done.

Great job, @vapdrs! And thank you for your patience :)

Co-authored-by: Félix Fischer <[email protected]>
@felix91gr felix91gr enabled auto-merge August 25, 2025 16:30
Copy link
Contributor

@PLeVasseur PLeVasseur left a comment

Choose a reason for hiding this comment

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

@vapdrs -- thanks for working with us as we reviewed ☺️

@felix91gr felix91gr added this pull request to the merge queue Aug 25, 2025
Merged via the queue into rustfoundation:main with commit 4a507dc Aug 25, 2025
6 checks passed
@felix91gr
Copy link
Collaborator

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

Labels

chapter: expressions decidability: decidable A coding guideline which can be checked automatically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std::i32::MIN % -1 and related

8 participants