authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 02:37:00-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 02:58:51-05:00
loge745544dacc5bda010fc65e5c8b81cb3b5249223
tree9e0a7501730d34fd8fe0dafdadb172733008e162
parentf537c51f2560564042da690e8fe3b6e85d9592c8

translate-c: detect macros referencing field lookup

as fn calls which assert the fn ptr is non-null

3 files changed, 91 insertions(+), 44 deletions(-)

src/c_tokenizer.cpp+1
...@@ -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}
src/translate_c.cpp+87-43
...@@ -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
...@@ -3808,6 +3801,83 @@ static void render_aliases(Context *c) {...@@ -3808,6 +3801,83 @@ static void render_aliases(Context *c) {
3808 }3801 }
3809}3802}
38103803
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
3811static void render_macros(Context *c) {3881static void render_macros(Context *c) {
3812 auto it = c->macro_table.entry_iterator();3882 auto it = c->macro_table.entry_iterator();
3813 for (;;) {3883 for (;;) {
...@@ -3815,9 +3885,16 @@ static void render_macros(Context *c) {...@@ -3815,9 +3885,16 @@ static void render_macros(Context *c) {
3815 if (!entry)3885 if (!entry)
3816 break;3886 break;
38173887
3888 AstNode *proto_node;
3818 AstNode *value_node = entry->value;3889 AstNode *value_node = entry->value;
3819 if (value_node->type == NodeTypeFnDef) {3890 if (value_node->type == NodeTypeFnDef) {
3820 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);
3821 } else {3898 } else {
3822 add_global_var(c, entry->key, value_node);3899 add_global_var(c, entry->key, value_node);
3823 }3900 }
...@@ -3944,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch...@@ -3944,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
3944 if (buf_eql_buf(name, symbol_name)) {4021 if (buf_eql_buf(name, symbol_name)) {
3945 return;4022 return;
3946 }4023 }
3947 c->macro_symbols.append({name, symbol_name});
3948 } else {
3949 c->macro_table.put(name, result_node);
3950 }
3951}
3952
3953static void process_symbol_macros(Context *c) {
3954 for (size_t i = 0; i < c->macro_symbols.length; i += 1) {
3955 MacroSymbol ms = c->macro_symbols.at(i);
3956
3957 // Check if this macro aliases another top level declaration
3958 AstNode *existing_node = get_global(c, ms.value);
3959 if (!existing_node || name_exists_global(c, ms.name))
3960 continue;
3961
3962 // If a macro aliases a global variable which is a function pointer, we conclude that
3963 // the macro is intended to represent a function that assumes the function pointer
3964 // variable is non-null and calls it.
3965 if (existing_node->type == NodeTypeVariableDeclaration) {
3966 AstNode *var_type = existing_node->data.variable_declaration.type;
3967 if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr &&
3968 var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe)
3969 {
3970 AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr;
3971 if (fn_proto_node->type == NodeTypeFnProto) {
3972 AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node);
3973 c->macro_table.put(ms.name, inline_fn_node);
3974 continue;
3975 }
3976 }
3977 }
3978
3979 add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value));
3980 }4024 }
4025 c->macro_table.put(name, result_node);
3981}4026}
39824027
3983static void process_preprocessor_entities(Context *c, ASTUnit &unit) {4028static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
...@@ -4194,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch...@@ -4194,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
41944239
4195 process_preprocessor_entities(c, *ast_unit);4240 process_preprocessor_entities(c, *ast_unit);
41964241
4197 process_symbol_macros(c);
4198 render_macros(c);4242 render_macros(c);
4199 render_aliases(c);4243 render_aliases(c);
42004244
test/translate_c.zig+3-1
...@@ -1078,7 +1078,9 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1078,7 +1078,9 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1078 ,1078 ,
1079 \\pub const glClearPFN = PFNGLCLEARPROC;1079 \\pub const glClearPFN = PFNGLCLEARPROC;
1080 ,1080 ,
1081 \\pub const glClearUnion = glProcs.gl.Clear;1081 \\pub inline fn glClearUnion(arg0: GLbitfield) {
1082 \\ (??glProcs.gl.Clear)(arg0)
1083 \\}
1082 ,1084 ,
1083 \\pub const OpenGLProcs = union_OpenGLProcs;1085 \\pub const OpenGLProcs = union_OpenGLProcs;
1084 );1086 );