authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-05-09 10:19:02+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-05-11 21:27:58+02:00
log917bd4192d4586fb2e8f3855d9e2e2eb0bf45921
tree5be550bc04692c738056d94116733275787fdadb
parent6cf7fb1177848c2f2a20c1f4093b1e003c477911

Validate enum tag for extern enum

The C specification mandates the enum to be compatible with signed char, signed int or unsigned int.

1 files changed, 33 insertions(+), 1 deletions(-)

src/analyze.cpp+33-1
......@@ -1908,6 +1908,30 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
19081908 return ErrorNone;
19091909}
19101910
1911static bool type_is_int_compatible(ZigType *t1, ZigType *t2) {
1912 assert(t1->id == ZigTypeIdInt);
1913 assert(t2->id == ZigTypeIdInt);
1914
1915 if (t1 == t2)
1916 return true;
1917
1918 return (t1->data.integral.bit_count == t2->data.integral.bit_count &&
1919 t1->data.integral.is_signed == t2->data.integral.is_signed);
1920}
1921
1922static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {
1923 // According to the ANSI C standard:
1924 // Each enumerated type shall be compatible with char, a signed integer
1925 // type, or an unsigned integer type.
1926 ZigType *c_uint_type = get_c_int_type(g, CIntTypeInt);
1927 ZigType *c_int_type = get_c_int_type(g, CIntTypeInt);
1928 ZigType *c_schar_type = g->builtin_types.entry_i8;
1929
1930 return (type_is_int_compatible(ty, c_schar_type) ||
1931 type_is_int_compatible(ty, c_int_type) ||
1932 type_is_int_compatible(ty, c_uint_type));
1933}
1934
19111935static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
19121936 assert(enum_type->id == ZigTypeIdEnum);
19131937
......@@ -1965,7 +1989,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
19651989 enum_type->abi_size = tag_int_type->abi_size;
19661990 enum_type->abi_align = tag_int_type->abi_align;
19671991
1968 // TODO: Are extern enums allowed to have an init_arg_expr?
19691992 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
19701993 ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
19711994 if (type_is_invalid(wanted_tag_int_type)) {
......@@ -1974,6 +1997,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
19741997 enum_type->data.enumeration.is_invalid = true;
19751998 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
19761999 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
2000 } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern &&
2001 !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) {
2002 enum_type->data.enumeration.is_invalid = true;
2003 ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr,
2004 buf_sprintf("'%s' is not a valid tag type for an extern union",
2005 buf_ptr(&wanted_tag_int_type->name)));
2006 add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr,
2007 buf_sprintf("valid types are 'i8', 'c_int' and 'c_uint' or compatible types"));
19772008 } else if (wanted_tag_int_type->data.integral.is_signed) {
19782009 enum_type->data.enumeration.is_invalid = true;
19792010 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
......@@ -1987,6 +2018,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
19872018 tag_int_type = wanted_tag_int_type;
19882019 }
19892020 }
2021
19902022 enum_type->data.enumeration.tag_int_type = tag_int_type;
19912023 enum_type->size_in_bits = tag_int_type->size_in_bits;
19922024 enum_type->abi_size = tag_int_type->abi_size;