New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use a builtin enum for calling conventions instead of keywords #661

andrewrk opened this Issue Dec 19, 2017 · 7 comments


None yet
5 participants

andrewrk commented Dec 19, 2017

right now we have these keywords for function calling conventions:

  • extern - must have C ABI. Also used to indicate C ABI on structs, enums, and unions.
  • stdcallcc
  • coldcc - cold calling convention is a thing, but this might be better off as an optimizer hint that the function is cold rather than specifying a calling convention. Currently the line is blurred.
  • nakedcc - used for entry points like _start and when inline assembly defines the whole function.

If no calling convention is specified, then the calling convention is selected automatically (and currently defaults to the "fast calling convention" that LLVM has available.) Related issue: #105 when mixing automatic calling convention with specified calling conventions.
Any function can be exported, and if the calling convention of an exported function is not specified, then extern is chosen.

This proposal is to make a builtin enum:

pub const CC = enum {

And instead of keywords, the fn keyword has optional brackets and then a calling convention, like this:

export fn[builtin.CC.Naked] _start() {
    // ...

If a calling convention is not specified, builtin.CC.Auto is the default. This is similar to the endianness in pointers proposal (see #649). When displaying a fn type, the calling convention only has to be specified if it is not builtin.CC.Auto.

Then it becomes easier to add reflection such as @fnCallingConvention(_start).

It would probably serve this proposal to automatically import the builtin package into the top level namespace of everything.

Other keywords such as union and enum support an argument with parentheses (and maybe soon a packed struct #307), but we could change those to brackets for consistency with this syntax.

const Foo = enum[u5] { A, B, C };
const Bar = union[Foo] { A: i32, B: f32, C: void};

@andrewrk andrewrk added the proposal label Dec 19, 2017

@andrewrk andrewrk added this to the 0.2.0 milestone Dec 19, 2017


This comment has been minimized.

kyle-github commented Dec 20, 2017

I like this. Extra keywords can come back and bite you later.

Java has annotations. Nim has odd looking pragmas etc. It seems like a good idea to have some way to apply metadata/modifiers to things without cluttering up the keyword set.

I like where you are going with this.


This comment has been minimized.

phase commented Dec 20, 2017

I like where this is going, but I don't see what other uses an enum annotation has for functions other than the calling convention. If you're going to introduce the notion of "you can annotate functions with enums", it better have more than one use case.

I think this can be applicable to other function attributes, such as noreturn and always_inline. Having something that encapsulates all of these would be cleaner than having separate systems for each subcategory of attribute.


This comment has been minimized.


tiehuis commented Dec 20, 2017

This was something I was wondering about a little while back so I generally like the proposal.

I think it'd be wise as @phase mentioned on looking at the __attribute__ system in GCC/LLVM and what specific things are exposed. This system is pretty flexible and custom compilers (for example embedded gcc forks) add extra attributes necessary for their custom architectures if needed. I don't expect us to copy verbatim or anything, but just to keep in mind the extensibility as an example.

We already expose some of these at the language level (such as align) and others aren't applicable to zig, (i.e. non-null). I can see more attribute like functionality wanted in the future, in which case we would need a system to handle many attributes.


This comment has been minimized.


andrewrk commented Dec 20, 2017

Extra keywords can come back and bite you later.

How so?


This comment has been minimized.

kyle-github commented Dec 20, 2017

How so?

The more keywords you have the more you have to watch your variable names etc. If you have multiple namespaces (i.e. struct field names do not collide with other names), then it is not so bad. Translating C to C++ can be "fun" sometimes because of the reserved words.


This comment has been minimized.


andrewrk commented Dec 20, 2017

In zig you can use @"keyword" to name any identifier that collides with a keyword. For example if you import an .h file that has a struct with a field called align (a zig keyword) then you can access it like this: foo.@"align"

andrewrk added a commit that referenced this issue Jan 23, 2018

add new kind of test: generating .h files. and more
 * docgen supports obj_err code kind for demonstrating
   errors without explicit test cases
 * add documentation for `extern enum`. See #367
 * remove coldcc keyword and add @setIsCold. See #661
 * add compile errors for non-extern struct, enum, unions
   in function signatures
 * add .h file generation for extern struct, enum, unions

@andrewrk andrewrk modified the milestones: 0.2.0, 0.3.0 Feb 28, 2018

andrewrk added a commit that referenced this issue Mar 21, 2018

change async function call syntax
 * instead of `async(allocator) call()`, now it is
   `async<allocator> call()`.
 * Fixes syntax ambiguity when leaving off the allocator
 * Fixes parse failure when call is a field access

This sets a precedent for using `<` to pass arguments
to a keyword. This will affect `enum`, `union`, and
`fn` (see #661)

@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Aug 10, 2018

@andrewrk andrewrk added the accepted label Aug 23, 2018


This comment has been minimized.

hryx commented Nov 14, 2018

I'm into it. If you do it, I'd definitely support using this bracket notation over parentheses for struct/union modifiers too, for consistency and intuitiveness. It's cool that whatever is inside the brackets is a comptime expression.

Java has annotations. Nim has odd looking pragmas etc.

Just to add to that list for inspiration, Rust has attributes, which have some usability drawbacks in my opinion:

  • Many different forms. #thing vs. #!thing vs. #!thing(option) vs. #!thing(option = "ok")
  • Visual locality. A Rust attribute affects "whatever is on the next line" or "whatever I'm inside of". It's nice that these zig brackets could be glued to the keyword to which they relate.

Nitpick: this should probably be builtin.Cc instead of builtin.CC to match the casing style of acronyms-as-words (Os, Xml, etc.).

@andrewrk andrewrk added the breaking label Nov 15, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment