authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 03:00:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 03:00:13-05:00
log8d5c4a67a7dfe2e1fc07f84515d59405c4100b5c
tree9e0a7501730d34fd8fe0dafdadb172733008e162
parent1ab84a27d374e666463c606dc1cd1c4972b52a74
parente745544dacc5bda010fc65e5c8b81cb3b5249223

Merge branch 'dimenus-c-field-expr'


5 files changed, 160 insertions(+), 50 deletions(-)

src/c_tokenizer.cpp+5-3
...@@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {...@@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {
120 case CTokIdLParen:120 case CTokIdLParen:
121 case CTokIdRParen:121 case CTokIdRParen:
122 case CTokIdEOF:122 case CTokIdEOF:
123 case CTokIdDot:
123 break;124 break;
124 }125 }
125}126}
...@@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {...@@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
216 buf_append_char(&ctok->buf, '0');217 buf_append_char(&ctok->buf, '0');
217 break;218 break;
218 case '.':219 case '.':
219 begin_token(ctok, CTokIdNumLitFloat);220 begin_token(ctok, CTokIdDot);
220 ctok->state = CTokStateFloat;221 end_token(ctok);
221 buf_init_from_str(&ctok->buf, "0.");
222 break;222 break;
223 case '(':223 case '(':
224 begin_token(ctok, CTokIdLParen);224 begin_token(ctok, CTokIdLParen);
...@@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {...@@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
238 break;238 break;
239 case CTokStateFloat:239 case CTokStateFloat:
240 switch (*c) {240 switch (*c) {
241 case '.':
242 break;
241 case 'e':243 case 'e':
242 case 'E':244 case 'E':
243 buf_append_char(&ctok->buf, 'e');245 buf_append_char(&ctok->buf, 'e');
src/c_tokenizer.hpp+1
...@@ -21,6 +21,7 @@ enum CTokId {...@@ -21,6 +21,7 @@ enum CTokId {
21 CTokIdLParen,21 CTokIdLParen,
22 CTokIdRParen,22 CTokIdRParen,
23 CTokIdEOF,23 CTokIdEOF,
24 CTokIdDot,
24};25};
2526
26enum CNumLitSuffix {27enum CNumLitSuffix {
src/ir.cpp+2-1
...@@ -6302,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char...@@ -6302,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char
6302 buf_appendf(name, ")");6302 buf_appendf(name, ")");
6303 return name;6303 return name;
6304 } else {6304 } else {
6305 //Note: C-imports do not have valid location information
6305 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,6306 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
6306 buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);6307 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
6307 }6308 }
6308 }6309 }
6309}6310}
src/translate_c.cpp+114-46
...@@ -23,11 +23,6 @@...@@ -23,11 +23,6 @@
2323
24using namespace clang;24using namespace clang;
2525
26struct MacroSymbol {
27 Buf *name;
28 Buf *value;
29};
30
31struct Alias {26struct Alias {
32 Buf *new_name;27 Buf *new_name;
33 Buf *canon_name;28 Buf *canon_name;
...@@ -44,7 +39,6 @@ struct Context {...@@ -44,7 +39,6 @@ struct Context {
44 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;39 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;
45 SourceManager *source_manager;40 SourceManager *source_manager;
46 ZigList<Alias> aliases;41 ZigList<Alias> aliases;
47 ZigList<MacroSymbol> macro_symbols;
48 AstNode *source_node;42 AstNode *source_node;
49 bool warnings_on;43 bool warnings_on;
5044
...@@ -351,8 +345,7 @@ static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf...@@ -351,8 +345,7 @@ static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf
351 return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node);345 return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node);
352}346}
353347
354348static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) {
355static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) {
356 AstNode *fn_def = trans_create_node(c, NodeTypeFnDef);349 AstNode *fn_def = trans_create_node(c, NodeTypeFnDef);
357 AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);350 AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);
358 fn_proto->data.fn_proto.visib_mod = c->visib_mod;351 fn_proto->data.fn_proto.visib_mod = c->visib_mod;
...@@ -363,7 +356,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n...@@ -363,7 +356,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n
363 fn_def->data.fn_def.fn_proto = fn_proto;356 fn_def->data.fn_def.fn_proto = fn_proto;
364 fn_proto->data.fn_proto.fn_def_node = fn_def;357 fn_proto->data.fn_proto.fn_def_node = fn_def;
365358
366 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name));359 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
367 AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);360 AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
368 fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;361 fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
369362
...@@ -3517,7 +3510,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {...@@ -3517,7 +3510,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
3517 }3510 }
35183511
3519 const char *raw_name = decl_name(record_decl);3512 const char *raw_name = decl_name(record_decl);
3520
3521 const char *container_kind_name;3513 const char *container_kind_name;
3522 ContainerKind container_kind;3514 ContainerKind container_kind;
3523 if (record_decl->isUnion()) {3515 if (record_decl->isUnion()) {
...@@ -3809,6 +3801,83 @@ static void render_aliases(Context *c) {...@@ -3809,6 +3801,83 @@ static void render_aliases(Context *c) {
3809 }3801 }
3810}3802}
38113803
3804static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node);
3805
3806static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) {
3807 if (type_node == nullptr) {
3808 return nullptr;
3809 } else if (type_node->type == NodeTypeContainerDecl) {
3810 return type_node;
3811 } else if (type_node->type == NodeTypePrefixOpExpr) {
3812 return type_node;
3813 } else if (type_node->type == NodeTypeSymbol) {
3814 AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol);
3815 if (existing_node == nullptr)
3816 return nullptr;
3817 if (existing_node->type != NodeTypeVariableDeclaration)
3818 return nullptr;
3819 return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr);
3820 } else if (type_node->type == NodeTypeFieldAccessExpr) {
3821 AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr);
3822 if (container_node == nullptr)
3823 return nullptr;
3824 if (container_node->type != NodeTypeContainerDecl)
3825 return container_node;
3826
3827 for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
3828 AstNode *field_node = container_node->data.container_decl.fields.items[i];
3829 if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) {
3830 return trans_lookup_ast_container(c, field_node->data.struct_field.type);
3831 }
3832 }
3833 return nullptr;
3834 } else {
3835 return nullptr;
3836 }
3837}
3838
3839static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) {
3840 if (ref_node->type == NodeTypeSymbol) {
3841 AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol);
3842 if (existing_node == nullptr)
3843 return nullptr;
3844 if (existing_node->type != NodeTypeVariableDeclaration)
3845 return nullptr;
3846 return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type);
3847 } else if (ref_node->type == NodeTypeFieldAccessExpr) {
3848 AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr);
3849 if (container_node == nullptr)
3850 return nullptr;
3851 if (container_node->type != NodeTypeContainerDecl)
3852 return container_node;
3853 for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
3854 AstNode *field_node = container_node->data.container_decl.fields.items[i];
3855 if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) {
3856 return trans_lookup_ast_container(c, field_node->data.struct_field.type);
3857 }
3858 }
3859 return nullptr;
3860 } else {
3861 return nullptr;
3862 }
3863}
3864
3865static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
3866 AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node);
3867 if (prefix_node == nullptr)
3868 return nullptr;
3869 if (prefix_node->type != NodeTypePrefixOpExpr)
3870 return nullptr;
3871 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
3872 return nullptr;
3873
3874 AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
3875 if (fn_proto_node->type != NodeTypeFnProto)
3876 return nullptr;
3877
3878 return fn_proto_node;
3879}
3880
3812static void render_macros(Context *c) {3881static void render_macros(Context *c) {
3813 auto it = c->macro_table.entry_iterator();3882 auto it = c->macro_table.entry_iterator();
3814 for (;;) {3883 for (;;) {
...@@ -3816,9 +3885,16 @@ static void render_macros(Context *c) {...@@ -3816,9 +3885,16 @@ static void render_macros(Context *c) {
3816 if (!entry)3885 if (!entry)
3817 break;3886 break;
38183887
3888 AstNode *proto_node;
3819 AstNode *value_node = entry->value;3889 AstNode *value_node = entry->value;
3820 if (value_node->type == NodeTypeFnDef) {3890 if (value_node->type == NodeTypeFnDef) {
3821 add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node);3891 add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node);
3892 } else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) {
3893 // If a macro aliases a global variable which is a function pointer, we conclude that
3894 // the macro is intended to represent a function that assumes the function pointer
3895 // variable is non-null and calls it.
3896 AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node);
3897 add_top_level_decl(c, entry->key, inline_fn_node);
3822 } else {3898 } else {
3823 add_global_var(c, entry->key, value_node);3899 add_global_var(c, entry->key, value_node);
3824 }3900 }
...@@ -3869,9 +3945,33 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {...@@ -3869,9 +3945,33 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
3869 return parse_ctok_num_lit(c, ctok, tok_i, false);3945 return parse_ctok_num_lit(c, ctok, tok_i, false);
3870 case CTokIdSymbol:3946 case CTokIdSymbol:
3871 {3947 {
3872 *tok_i += 1;3948 bool need_symbol = false;
3949 CTokId curr_id = CTokIdSymbol;
3873 Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);3950 Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);
3874 return trans_create_node_symbol(c, symbol_name);3951 AstNode *curr_node = trans_create_node_symbol(c, symbol_name);
3952 AstNode *parent_node = curr_node;
3953 do {
3954 *tok_i += 1;
3955 CTok* curr_tok = &ctok->tokens.at(*tok_i);
3956 if (need_symbol) {
3957 if (curr_tok->id == CTokIdSymbol) {
3958 symbol_name = buf_create_from_buf(&curr_tok->data.symbol);
3959 curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name));
3960 parent_node = curr_node;
3961 need_symbol = false;
3962 } else {
3963 return nullptr;
3964 }
3965 } else {
3966 if (curr_tok->id == CTokIdDot) {
3967 need_symbol = true;
3968 continue;
3969 } else {
3970 break;
3971 }
3972 }
3973 } while (curr_id != CTokIdEOF);
3974 return curr_node;
3875 }3975 }
3876 case CTokIdLParen:3976 case CTokIdLParen:
3877 {3977 {
...@@ -3885,6 +3985,7 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {...@@ -3885,6 +3985,7 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
3885 *tok_i += 1;3985 *tok_i += 1;
3886 return inner_node;3986 return inner_node;
3887 }3987 }
3988 case CTokIdDot:
3888 case CTokIdEOF:3989 case CTokIdEOF:
3889 case CTokIdRParen:3990 case CTokIdRParen:
3890 // not able to make sense of this3991 // not able to make sense of this
...@@ -3920,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch...@@ -3920,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
3920 if (buf_eql_buf(name, symbol_name)) {4021 if (buf_eql_buf(name, symbol_name)) {
3921 return;4022 return;
3922 }4023 }
3923 c->macro_symbols.append({name, symbol_name});
3924 } else {
3925 c->macro_table.put(name, result_node);
3926 }
3927}
3928
3929static void process_symbol_macros(Context *c) {
3930 for (size_t i = 0; i < c->macro_symbols.length; i += 1) {
3931 MacroSymbol ms = c->macro_symbols.at(i);
3932
3933 // Check if this macro aliases another top level declaration
3934 AstNode *existing_node = get_global(c, ms.value);
3935 if (!existing_node || name_exists_global(c, ms.name))
3936 continue;
3937
3938 // If a macro aliases a global variable which is a function pointer, we conclude that
3939 // the macro is intended to represent a function that assumes the function pointer
3940 // variable is non-null and calls it.
3941 if (existing_node->type == NodeTypeVariableDeclaration) {
3942 AstNode *var_type = existing_node->data.variable_declaration.type;
3943 if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr &&
3944 var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe)
3945 {
3946 AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr;
3947 if (fn_proto_node->type == NodeTypeFnProto) {
3948 AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node);
3949 c->macro_table.put(ms.name, inline_fn_node);
3950 continue;
3951 }
3952 }
3953 }
3954
3955 add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value));
3956 }4024 }
4025 c->macro_table.put(name, result_node);
3957}4026}
39584027
3959static void process_preprocessor_entities(Context *c, ASTUnit &unit) {4028static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
...@@ -4170,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch...@@ -4170,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
41704239
4171 process_preprocessor_entities(c, *ast_unit);4240 process_preprocessor_entities(c, *ast_unit);
41724241
4173 process_symbol_macros(c);
4174 render_macros(c);4242 render_macros(c);
4175 render_aliases(c);4243 render_aliases(c);
41764244
test/translate_c.zig+38
...@@ -1046,6 +1046,44 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1046,6 +1046,44 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1046 \\ return x + 13;1046 \\ return x + 13;
1047 \\}1047 \\}
1048 );1048 );
1049
1050 cases.add("macros with field targets",
1051 \\typedef unsigned int GLbitfield;
1052 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
1053 \\typedef void(*OpenGLProc)(void);
1054 \\union OpenGLProcs {
1055 \\ OpenGLProc ptr[1];
1056 \\ struct {
1057 \\ PFNGLCLEARPROC Clear;
1058 \\ } gl;
1059 \\};
1060 \\extern union OpenGLProcs glProcs;
1061 \\#define glClearUnion glProcs.gl.Clear
1062 \\#define glClearPFN PFNGLCLEARPROC
1063 ,
1064 \\pub const GLbitfield = c_uint;
1065 ,
1066 \\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield);
1067 ,
1068 \\pub const OpenGLProc = ?extern fn();
1069 ,
1070 \\pub const union_OpenGLProcs = extern union {
1071 \\ ptr: [1]OpenGLProc,
1072 \\ gl: extern struct {
1073 \\ Clear: PFNGLCLEARPROC,
1074 \\ },
1075 \\};
1076 ,
1077 \\pub extern var glProcs: union_OpenGLProcs;
1078 ,
1079 \\pub const glClearPFN = PFNGLCLEARPROC;
1080 ,
1081 \\pub inline fn glClearUnion(arg0: GLbitfield) {
1082 \\ (??glProcs.gl.Clear)(arg0)
1083 \\}
1084 ,
1085 \\pub const OpenGLProcs = union_OpenGLProcs;
1086 );
10491087
1050 cases.add("switch statement with no default",1088 cases.add("switch statement with no default",
1051 \\int foo(int x) {1089 \\int foo(int x) {