C doesn't allow you specify what goes on the stack or heap, either. The "stack" in C is called automatic memory. What differentiates automatic memory is that it's automatically released when it falls out of scope. But it can very well be allocated using the same machinery as malloc. Yes, it behaves in some sense like a logical stack, but it needn't reside in some sequentially allocated storage, and the order of allocation or deallocation of objects in the same scope is completely undefined. Indeed, clang supports a mode with two "stacks", so that buffer overflows of automatic array variables can't easily overwrite function invocation bookkeeping.
Go is a fully GCd language with lexical closures. All memory is automatically released when it's no longer _referenced_. So the distinction is irrelevant.
As for volatile, it doesn't really do what most people think it does. volatile prevents _logical_ loads and stores from being moved. What that means for when you're dipping into assembly can vary from compiler to compiler. For typical code the volatile qualifier is only relevant when using setjmp/longjmp, for signal handlers, and in the C11 standard, for some kinds of threading.
In design and spirit I think Go is very much the successor to C. Though, I've never written a line of Go in my life and code primarily in C most days, so I'm only half informed. But if you look at the history of both C and Unix, they were never about performance, per se. What distinguishes them is ease of implementation, ease of portability, and a philosophy of achieving _easy_ performance gains by shifting a subset of hard problems onto the caller (the so-called "Worse is Better" theory). Thus, C was designed so that it could be compiled in a single pass (without an AST). Similarly, one of the reasons the Go compiler is so fast is because of very intentional language design decisions. Those approaches result in all manner of unintended consequences in addition to the intended consequences, and it's important not to conflate the two.