Skip to content

Commit

Permalink
Merge pull request #975 from zig-lang/none-pure-enums
Browse files Browse the repository at this point in the history
Added better support for none pure enums in translate-c
  • Loading branch information
andrewrk committed May 2, 2018
2 parents 86a428a + 1a9403f commit 6f002e7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/ast_render.cpp
Expand Up @@ -728,7 +728,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_grouped(ar, field_node->data.struct_field.type);
}
if (field_node->data.struct_field.value != nullptr) {
fprintf(ar->f, "= ");
fprintf(ar->f, " = ");
render_node_grouped(ar, field_node->data.struct_field.value);
}
fprintf(ar->f, ",\n");
Expand Down
108 changes: 39 additions & 69 deletions src/translate_c.cpp
Expand Up @@ -3744,6 +3744,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
}


bool pure_enum = true;
uint32_t field_count = 0;
for (auto it = enum_def->enumerator_begin(),
Expand All @@ -3755,84 +3756,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
pure_enum = false;
}
}

AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());
assert(tag_int_type);

if (pure_enum) {
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}

enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
for (auto it = enum_def->enumerator_begin(),
it_end = enum_def->enumerator_end();
it != it_end; ++it, i += 1)
{
const EnumConstantDecl *enum_const = *it;

Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
Buf *field_name;
if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
} else {
field_name = enum_val_name;
}

AstNode *field_node = trans_create_node(c, NodeTypeStructField);
field_node->data.struct_field.name = field_name;
field_node->data.struct_field.type = nullptr;
enum_node->data.container_decl.fields.items[i] = field_node;

// in C each enum value is in the global namespace. so we put them there too.
// at this point we can rely on the enum emitting successfully
if (is_anonymous) {
AstNode *lit_node = trans_create_node_unsigned(c, i);
add_global_var(c, enum_val_name, lit_node);
} else {
AstNode *field_access_node = trans_create_node_field_access(c,
trans_create_node_symbol(c, full_type_name), field_name);
add_global_var(c, enum_val_name, field_access_node);
}
}

if (is_anonymous) {
c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node);
return enum_node;
} else {
AstNode *symbol_node = trans_create_node_symbol(c, full_type_name);
add_global_weak_alias(c, bare_name, full_type_name);
add_global_var(c, full_type_name, enum_node);
c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
return enum_node;
}
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}

// TODO after issue #305 is solved, make this be an enum with tag_int_type
// as the integer type and set the custom enum values
AstNode *enum_node = tag_int_type;


// add variables for all the values with enum_node
enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
for (auto it = enum_def->enumerator_begin(),
it_end = enum_def->enumerator_end();
it != it_end; ++it)
it != it_end; ++it, i += 1)
{
const EnumConstantDecl *enum_const = *it;

Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal());
AstNode *var_node = add_global_var(c, enum_val_name, int_node);
var_node->data.variable_declaration.type = tag_int_type;
Buf *field_name;
if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
} else {
field_name = enum_val_name;
}

AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal());
AstNode *field_node = trans_create_node(c, NodeTypeStructField);
field_node->data.struct_field.name = field_name;
field_node->data.struct_field.type = nullptr;
field_node->data.struct_field.value = int_node;
enum_node->data.container_decl.fields.items[i] = field_node;

// in C each enum value is in the global namespace. so we put them there too.
// at this point we can rely on the enum emitting successfully
if (is_anonymous) {
Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
add_global_var(c, enum_val_name, int_node);
} else {
AstNode *field_access_node = trans_create_node_field_access(c,
trans_create_node_symbol(c, full_type_name), field_name);
add_global_var(c, enum_val_name, field_access_node);
}
}

if (is_anonymous) {
Expand All @@ -3843,7 +3813,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
add_global_weak_alias(c, bare_name, full_type_name);
add_global_var(c, full_type_name, enum_node);
c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
return symbol_node;
return enum_node;
}
}

Expand Down
22 changes: 22 additions & 0 deletions test/translate_c.zig
Expand Up @@ -53,6 +53,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
\\pub const Foo = enum_Foo;
);

cases.add("enums",
\\enum Foo {
\\ FooA = 2,
\\ FooB = 5,
\\ Foo1,
\\};
,
\\pub const enum_Foo = extern enum {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
\\};
,
\\pub const FooA = enum_Foo.A;
,
\\pub const FooB = enum_Foo.B;
,
\\pub const Foo1 = enum_Foo.@"1";
,
\\pub const Foo = enum_Foo;
);

cases.add("restrict -> noalias",
\\void foo(void *restrict bar, void *restrict);
,
Expand Down

0 comments on commit 6f002e7

Please sign in to comment.