4 ms·
Can you give an example of non-C++ code that a modern compiler (MSVC, clang, g++ or something) successfully compiles with no diagnostics? I’m genuinely curious.
by _gabe_ 3y ago
Can you give an example of non-C++ code that a modern compiler (MSVC, clang, g++ or something) successfully compiles with no diagnostics? I’m genuinely curious. If not, this just sounds like more C++ FUD because the spec doesn’t define everything under the sun and allows a certain amount of leeway to compilers for things like emitting different error diagnostics.
- LegionMammal978 3y agoConsider: #define _FOO int main() {} Per the C++ standard ([lex.name]/3), this program is ill-formed: > In addition, some identifiers appearing as a token or preprocessing-token are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required. [...] Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. Thus, the compiler theoretically has the liberty to emit whatever it wants for this program. Neither GCC nor Clang produces a warning under -std=c++20 -Wall -Wextra (Clang only produces a -Wreserved-macro-identifier under -Weverything), and MSVC doesn't produce a warning under /std:c++20 /Wall. In practice, most examples of ill-formed programs where compilers issue no warnings occur with discrepancies between different source files that are linked together; e.g., declaring a function as inline in one file but non-inline in another, or declaring a function with two different sets of default arguments in different files, or defining the same non-inline variable or function in different files, or defining the same inline function differently in different files.
- tialaramex 3y agoDon't forget since C++ 20 all programs which rely on a concept but don't fulfill the (unchecked) semantic constraints of that concept are ill-formed. This allows C++ to truthfully say that C++ programs have the same properties as Rust programs in this regard, because although most real world C++ may fail those constraints and they aren't checked, as a result those aren't technically C++ programs at all so the fact they're broken and don't do what their programmers expected is magically not the fault of C++ even though the compiler seemed fine with it.
- _gabe_ 3y ago> Thus, the compiler theoretically has the liberty to emit whatever it wants for this program. In theory, sure. In practice, what does it do? We can look and see.[0][1][2] (I don't know of any compiler that emits garbage in the example you listed). For some reason, there's this sentiment that's arisen that treats undefined behavior as some sort of bugaboo that's capable of anything and everything (including summoning nasal demons). Here's a question that I can't find an answer to. Is machine code well-defined (as in, can it contain undefined behavior)? If the answer is yes, then all Rust programs can also contain undefined behavior, because they eventually turn into machine code after all. If the answer is no, then that means once a C++ program is compiled into machine code, the executable is a well-defined program. This whole nasal demon garbage was a good hyperbole at the time to explain that, yes, undefined behavior is bad. But it's been taken to this extreme where people will use arguments like this to try and convince others that if your program has undefined behavior, then it could summon a nasal demon, because who knows what could happen. In reality, that won't happen. In reality, a signed integer overflow can result in a meaningless program, or a security vulnerability, or many other bad things, but it doesn't mean that the compiled machine code is all of a sudden inventing new instructions at random that the CPU will happily accept. It doesn't mean that your program will turn your OS into a pac-man game. It doesn't mean that it's impossible to find the root cause of the issue and remove the undefined behavior. In practice, undefined behavior means that your program is broken, but you can look at the compiled program and trace exactly what it does. Computers are machines, they behave predictably (for the most part). They fetch an instruction, execute the instruction, and read/store results to memory. If you look at the instruction and memory (the cache stored on the specific core that the processor is using), you can reliably predict what the CPU will do after executing that instruction. And yes, multithreading exacerbates the effects undefined behavior and makes it more difficult to debug. But you can debug the issue, even if it means you have to look at the machine code directly. So while, yes, a compiler can emit garbage when it encounters the example program you gave, using that as an argument for why undefined behavior is bad is dumb. Because in reality, compilers will do something that makes sense, and if it doesn't, you can just look at what it produced. In all the examples you listed, I'm sure that if you created a small example illustrating those situations, the compiled program would do what you expect it to. (Like in the case of having different default args, it will probably just throw an error like this[4]). Sorry for the rant, it just annoys me that we can't discuss undefined behavior without somebody making an argument that doesn't matter in virtually every case. Undefined behavior is bad! But there are good, real, common examples that show why it's bad! Use those instead instead of talking about how compilers are technically permitted to spew trash when they encounter a program that looks normal, because I'd be very surprised if any modern compiler exists that does spew trash for a normal looking program. This talk by Chandler Carruth seems pretty good on explaining the nuance of undefined behavior[5]. [0]: https://godbolt.org/z/zv4GhPK5E https://godbolt.org/z/zv4GhPK5E [1]: https://godbolt.org/z/6obn7134G https://godbolt.org/z/6obn7134G [2]: https://godbolt.org/z/33cKcx5xs https://godbolt.org/z/33cKcx5xs [3]: https://en.cppreference.com/w/cpp/language/ub https://en.cppreference.com/w/cpp/language/ub [4]: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-2/compiler-error-c2572?view=msvc-170 https://learn.microsoft.com/en-us/cpp/error-messages/compile... [5]: https://www.youtube.com/watch?v=yG1OZ69H_-o https://www.youtube.com/watch?v=yG1OZ69H_-o