You can put the function in a !#[no_std] crate without any allocator. How would you propose to detect which functions allocate, except to declare a function to be allocating? There's no such declaration on Vec::push...
You could just use a deny lint and then wrap every function that allocates in the thing you're denying. (#![deny(while_true)] might be a good candidate.)
But even then, I doubt you'd really be willing to go through that effort. Someone could get around any annotation you provide by just not annotating an allocation they want to do. And if you can trust people to not do that, you can trust them to not allocate in the first place.
The most practical solution is @skysch's suggestion of putting your code in a crate that doesn't link to an allocator or the alloc crate. After all, if you don't have access to an allocator you can't allocate memory.
Alternatively, I don't think it already exists, but I'm sure you could make a custom static analysis tool which checks the body of a function and marks anything which calls std::alloc::alloc() either directly or transitively. It could even be implemented as part of a clippy lint.
I'm kinda curious as to the use case here, though. Why do you want to forbid all allocations?
I'm not the original asker, but one thought that comes to mind is if you're doing unsafe stuff and you want to compile to webassembly. I came across a function needed in webgl that's unsafe, but it's okay as long as you don't allocate while you're holding the reference it gives you. If you accidentally cause the web assembly environment to reallocate the chunk of memory that it gave you then the unsafe pointer would point to the wrong place. Maybe they want to do this because they're doing some cool unsafe stuff like that.
I was coming at this from a runtime perspective since I've been interested in figuring out if I used Vec::with_capacity in the right places. So I was definitely planning on allocating, but I was trying to minimize the allocations by doing them upfront.
I've seen nice improvements in performance by preallocating strings and vectors to have roughly the right capacity from the start. An example is a simple indent function in my Textwrap library where preallocating the output saved about 20%:
This will of course depend a lot on the kind of function you're optimizing: in this example, the function is tiny and the work done is mostly about copying string slices around. So having a few unnecessary reallocations can take up a proportionally large amount of time — even though the whole thing runs in microseconds.