All languages I know (e.g. Haskell) make concessions to pragmatism. For example, even pure function can somehow create debug output. Every memory allocation does mutate global state.
The weakly pure class of functions is useful. It limits the potential side-effects to stuff reachable from mutable arguments. For example, a image filter function can be weakly pure while it mutates the image provided as an argument. It removes the need allocate a return image or wrap computations in monads and thunks.
To get really strong guarantees in D, you declare your functions pure, nothrow, and @safe. The nothrow means no exceptions are thrown and @safe means all the low-level tricks (casts,assembly,etc) to break type safety are disabled.