I like the idea of a native string datatype, but wonder how it may be implemented without run-time support.
The problem with many of the structural features is that they need heap support - i.e. a malloc/free pair. You can't sanely pass strings over the stack, and the same goes for continuations and passing datatypes by value.
From what I've seen with my FreeBasic porting efforts where runtime involves a significant portion but occasionally has unwanted dependencies, you will probably want to cut the language in three parts:
1: The largest subset of the language that needs no runtime except for things like a functional stack and known processor state. This should be enough to implement...
2: The largest subset of the language that can be compiled provided a functional implementation of malloc/free and nothing else (read: a functional heap). You need this to support all non-linear data flows in the language semantics, as well as dynamic array types and native string types.
3: The entire language, including all features that depend on a hosted environment.
C is so simplistic that there's no part 2. C++ does, but yet you don't have a properly defined mechanic to limit the language subset to the items you can use, and instead you have to manually disable individual language features. For a proper systems development language these separations should be defined and enforceable by the compiler. FreeBasic is troublesome here since it makes a bit of a mess here to include references to hosted features (diagnostics and such) in runtime functions where you wouldn't expect anything but a heap allocation. Plus, you don't want to stick with the choice of having to implement dummies for pretty much everything (and not be ticked off by the compiler in advance) to get the libc working.
There was an interesting discussion on forum.dlang.org and no definitive conclusion if inline assembler in D were a good idea.
Interfacing with assembly is not
inline assembly. Besides, since it is platform-dependent, it's very hard to specify it as part of the language standard.
The operating systems developed at ETH Zürich have been written in languages with GC since the 80's and were actually in daily use until this millennium. So I would not outright exclude a GC.
Just because it's possible doesn't make it a good idea. Having a GC takes away your control over memory and puts it in a black box. If you wrote the thing, you know how the black box works and you can use it to force allocation semantics when you need them, but it'll make it hard to maintain for everyone that doesn't know how the system works. Also, if the garbage collector gets changed, memory allocation semantics change as well with all the effects thereof.
Could you please elaborate what you mean with continuations,
Full-thread continuations are harder and in some contexts the wrong solution, but the core idea involves that instead of just being able to pass a function pointer, you pass a code reference
with arbitrary amounts of auxiliary data. The typical C construct for doing anything close to this is a tuple of ( type(*)(void*), void* ) which allows you to pass a function and data separately, and toss the data as the argument of the function. It works but it's not typesafe, the called function has no idea on how to manage the memory in the data side, and you have to write a struct, as well as the marshalling and demarshalling explicitly when the compiler can easily automate it for you. Doing this for entire threads and creating an continuation is impossible in C without doing platform-specific tricks. C does allow you to pull off its little brother the closure in its verbose and unsafe form, although there are fixes for that
(example). Both closures and continuations are extremely powerful mechanics if made accessible.