The manual tries very hard to mention corner cases since it's evolving into a proper spec. Calling printf is safe, it's C functions that take ownership of the char* pointer that are inherently unsafe.
> Maybe Nim should have an unsafe directive to make sure any unsafe user code is clearly marked?
That's a common misunderstanding, Nim doesn't need this. Instead of an ``unsafe`` keyword, Nim has ``addr`` and ``cast`` as keywords, these are the unsafe building blocks of the language. There are other corner cases that introduce unsafety, but they are all known and can be solved in time.
> I also coulda sworn there was some part of the manual or site that was discussing a feature with a limitation due to the difficulty of expressing it in C.
Well these things certainly are everywhere, but the issue here is not the difficulty of expressing it in C, but a desire to have very good C interop. Rust actually has all the same design constraints even though Rust builds on top of LLVM because the constraints come from the "systems programming" problem domain: Control over memory layouts, the stressed difference between heap and stack, etc. LLVM's IR is very close to C, so what is difficult to map to C is difficult to map to LLVM too.