I think the __attribute syntax is a good basis because it keeps the type expressions fully generic. It's a sound design principle to allow any type to be described with a self-contained type expression. You can always put in typedefs to make things easier to read anyway:
typedef __attribute(noreturn, void) noreturn; typedef __attribute(sprintf_format, string) sprintf_format; typedef __attribute(sprintf_args, mixed) sprintf_args;
noreturn error(string msg); string werror(sprintf_format fmt, sprintf_args ... args);
Along the same vein, I think the types written by the type checker in various error messages etc should have exactly the same syntax as the types that are possible to write in Pike, to avoid confusion. And I guess this __attribute(...) syntax still would occur in such messages.
Side note: I don't think it's correct to put a "noreturn" property on a void type. That's a concept that only can be applied to a function, not to a type. I.e. it would rather be like this using the __attribute syntax:
__attribute(noreturn, function(string:void))
It's unfortunately not syntactically possible to associate anything with the function itself in the normal function declaration syntax. In the long run it'd be nice to have a syntax for that, so we can add a whole lot of attributes to functions (or declarations in general, for that matter) without introducing new keywords for all of them.
I believe C# has a syntax for that which looks something like this:
[noreturn, synchronized, foo, bar, blah(attributes, can, take, args, too)] int my_little_function (int a) { ... }