There is no way to do this in a single Cargo build. You will have to patch the crate source to change the version number of one (and I'd change the name too to avoid confusion). toml_edit can help you automate this.
It might also be possible to dynamically load two separately compiled cdylibs and invoke them individually, but that makes Rust testing harder.
By a strict interpretation of semver, this is not true— As soon as a crate is published with some behavior, you have to assume that downstream code may depend on that behavior, however erroneous it may be.
Changing that behavior (even to correct it) may break those downstream users' code. In practice, this is most likely to happen if they've written their own mitigation for the erroneous behavior which breaks when the original function starts working properly.
This interpretation of semver is more-or-less useless. Because everything can be observed in a language which allows you to turn pointer-to-function into pointer-to-data. You can just look on the generated code and use it to calculate very-important-seed for your program.
At this point we are entering realm of “that would be rather stupid use of API” and we are start discussion about what breaking change is semver-compatible and what is not semver-compatible.
Don't do that, then. Make temporary git-fork of the crate if everything else fails. Or stick with fixed version of crate till your would be ready to remove your workaround.
But don't expect that upstream would support bugs of old versions just to make your workarounds work. That's not how semver works. It literally couldn't work that way.
P.S. BTW these “let's look on the code of function and pull something from it” are not even hyphotetical issues. I worked on a project which needed to do that to work with mutexes on MacOS in the context where stack may not be available. Specifically because runtime needed to ensure that attempt to get fresh stack for
a task wouldn't race with another such attempt in another task. Since the only way to lock or unlock mutex on MacOS is to call a function… we disassembled libc function and used data from it. But we never expected that Apple wouldn't ever change that function, we needed test which verified that new version of MacOS still used code which we could disassemble and understand.
I gave very practical example when it may make very practical sense. You may deicide whether your want to support it or not, but if you declare that everything should be compatible then it's unclear why tricks like what I described should be excluded.
Yes, semver is, to some degree, social thingie, not purely technical. And that's normal because it tries to facilitate cooperative development which is very much a social activity.
error: failed to select a version for `rand`.
... required by package `rusttest v0.0.1`
versions that meet the requirements `=0.8.4` are: 0.8.4
all possible versions conflict with previously selected packages.
previously selected package `rand v0.8.5`
... which satisfies dependency `rand = "=0.8.5"` of package `rusttest v0.0.1`
failed to select a version for `rand` which could resolve this conflict
Which like, idk, maybe isn't the best. Everything else in cargo treats semver as a thing that is useful but has no concrete restrictions. Maybe it's a bug, even?