4

We discovered recently that compilers (for us it is GCC) can optimize some code in conjunction with asserts set by developers.

This code for example:

#include <cassert>
int getBatteryLevel(){
    return 0;
}
int process(int level);
int main() {
    [[maybe_unused]] const auto level = getBatteryLevel();
    assert(level > 0);
    process(level);
}

Will link with -O2 even if process has no implementation. It does not link without optimizations.

Is this documented anywhere?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Nicolas
  • 598
  • 3
  • 15
  • 4
    not sure if this is documented anywhere explicitly. It is just the compiler noticing that there is no way `process` gets called. Note that you get the same effect when you replace the assert with `if (level == 0) std::terminate();`. https://godbolt.org/z/sW6sod7jb so this isnt specific to `assert` – 463035818_is_not_an_ai Aug 17 '21 at 14:03
  • @463035818_is_not_a_number yes you're write, that was not the code I wanted to post. I changed it. – Nicolas Aug 17 '21 at 14:07
  • 1
    it is an interesting observation, but I am afraid the answer is (almost?) trivial: The linker only complains about missing definition when the function is actually called. When no optimizations are turned on the compiler does not bother to remove dead code – 463035818_is_not_an_ai Aug 17 '21 at 14:08
  • 2
    I believe this should answer why this is allowed to work: https://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule – NathanOliver Aug 17 '21 at 14:10
  • 1
    your example is quite different now, but still the compiler can see that the program terminates before calling the function. – 463035818_is_not_an_ai Aug 17 '21 at 14:11
  • 1
    fwiw, also in your new example you can replace the `assert` with equivalent call to `terminate` to see the same effect: https://godbolt.org/z/v5aEq6M4Y – 463035818_is_not_an_ai Aug 17 '21 at 14:12
  • The key to why this optimization is interesting, is because it uses information from a macro (assert) which should have been removed by the the preprocessor, isn't it? – Yun Aug 17 '21 at 14:33
  • 1
    @Yun `assert`s are only removed if `NDEBUG` macro is defined which is often not the case even in optimized builds. – yugr Aug 17 '21 at 17:43
  • I see, thank you. I was able to confirm this using Compiler Explorer as well. That makes the question's optimization not anything special. – Yun Aug 17 '21 at 17:50
  • [Undefined behavior can result in time travel](https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633) – Eljay Aug 17 '21 at 18:39
  • [What Every C Programmer Should Know About Undefined Behavior](http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html) ... and C++ programmer. – Eljay Aug 17 '21 at 18:42

1 Answers1

1

Is this documented anywhere?

The documentation of optimisations isn't very thorough. The optimisations that are probably used here are "inline expansion", "constant folding" and "dead code elmination".

Where can I learn about compilers

Books are a good place to start, unless you intend to invent computing from ground up. Academic papers can also contain good information, but filtering out irrelevant stuff, and figuring out required preliminary knowledge can be a lot of work. Plus, they tend to be quite expensive per unit of information.


P.S. If you don't define the function that is odr-used, then the program is ill-formed. Language implementations are allowed to accept ill-formed programs, but are not required to. Usually, they are required to diagnose such bugs, but this particular case is where implementations are not required to diagnose.

eerorika
  • 232,697
  • 12
  • 197
  • 326