| author | |
| committer | |
| log | 201a3c121a5c28273138b1160c5aac4e24d619bd |
| tree | 68480040ae3c4cedce7d8bf953cd69359b6749f1 |
| parent | 47cf8520adb245dbd34ad60fc9206b7eaab5e0be |
closes #2218 files changed, 118 insertions(+), 136 deletions(-)
doc/langref.md+5-3| ... | ... | @@ -123,7 +123,7 @@ MultiplyOperator = "*" | "/" | "%" | "**" | "*%" |
| 123 | 123 | |
| 124 | 124 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression |
| 125 | 125 | |
| 126 | SuffixOpExpression = option("inline") PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 126 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 127 | 127 | |
| 128 | 128 | FieldAccessExpression = "." Symbol |
| 129 | 129 | |
| ... | ... | @@ -141,11 +141,13 @@ StructLiteralField = "." Symbol "=" Expression |
| 141 | 141 | |
| 142 | 142 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%" |
| 143 | 143 | |
| 144 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 144 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 145 | 145 | |
| 146 | 146 | ArrayType = "[" option(Expression) "]" option("const") TypeExpr |
| 147 | 147 | |
| 148 | GotoExpression = option("inline") "goto" Symbol | |
| 148 | GotoExpression = "goto" Symbol | |
| 149 | ||
| 150 | CompTimeExpression = option("comptime") Expression | |
| 149 | 151 | |
| 150 | 152 | GroupedExpression = "(" Expression ")" |
| 151 | 153 |
src/all_types.hpp+14-1| ... | ... | @@ -280,6 +280,7 @@ enum NodeType { |
| 280 | 280 | NodeTypeSwitchRange, |
| 281 | 281 | NodeTypeLabel, |
| 282 | 282 | NodeTypeGoto, |
| 283 | NodeTypeCompTime, | |
| 283 | 284 | NodeTypeBreak, |
| 284 | 285 | NodeTypeContinue, |
| 285 | 286 | NodeTypeAsmExpr, |
| ... | ... | @@ -449,7 +450,6 @@ struct AstNodeFnCallExpr { |
| 449 | 450 | AstNode *fn_ref_expr; |
| 450 | 451 | ZigList<AstNode *> params; |
| 451 | 452 | bool is_builtin; |
| 452 | bool is_comptime; | |
| 453 | 453 | }; |
| 454 | 454 | |
| 455 | 455 | struct AstNodeArrayAccessExpr { |
| ... | ... | @@ -556,6 +556,10 @@ struct AstNodeGoto { |
| 556 | 556 | bool is_inline; |
| 557 | 557 | }; |
| 558 | 558 | |
| 559 | struct AstNodeCompTime { | |
| 560 | AstNode *expr; | |
| 561 | }; | |
| 562 | ||
| 559 | 563 | struct AsmOutput { |
| 560 | 564 | Buf *asm_symbolic_name; |
| 561 | 565 | Buf *constraint; |
| ... | ... | @@ -721,6 +725,7 @@ struct AstNode { |
| 721 | 725 | AstNodeSwitchRange switch_range; |
| 722 | 726 | AstNodeLabel label; |
| 723 | 727 | AstNodeGoto goto_expr; |
| 728 | AstNodeCompTime comptime_expr; | |
| 724 | 729 | AstNodeAsmExpr asm_expr; |
| 725 | 730 | AstNodeFieldAccessExpr field_access_expr; |
| 726 | 731 | AstNodeContainerDecl container_decl; |
| ... | ... | @@ -1289,6 +1294,7 @@ enum ScopeId { |
| 1289 | 1294 | ScopeIdCImport, |
| 1290 | 1295 | ScopeIdLoop, |
| 1291 | 1296 | ScopeIdFnDef, |
| 1297 | ScopeIdCompTime, | |
| 1292 | 1298 | }; |
| 1293 | 1299 | |
| 1294 | 1300 | struct Scope { |
| ... | ... | @@ -1366,6 +1372,13 @@ struct ScopeLoop { |
| 1366 | 1372 | Scope base; |
| 1367 | 1373 | }; |
| 1368 | 1374 | |
| 1375 | // This scope is created for a comptime expression. | |
| 1376 | // NodeTypeCompTime | |
| 1377 | struct ScopeCompTime { | |
| 1378 | Scope base; | |
| 1379 | }; | |
| 1380 | ||
| 1381 | ||
| 1369 | 1382 | // This scope is created for a function definition. |
| 1370 | 1383 | // NodeTypeFnDef |
| 1371 | 1384 | struct ScopeFnDef { |
src/analyze.cpp+9-61| ... | ... | @@ -24,67 +24,6 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type); |
| 24 | 24 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); |
| 25 | 25 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); |
| 26 | 26 | |
| 27 | AstNode *first_executing_node(AstNode *node) { | |
| 28 | switch (node->type) { | |
| 29 | case NodeTypeFnCallExpr: | |
| 30 | return first_executing_node(node->data.fn_call_expr.fn_ref_expr); | |
| 31 | case NodeTypeBinOpExpr: | |
| 32 | return first_executing_node(node->data.bin_op_expr.op1); | |
| 33 | case NodeTypeUnwrapErrorExpr: | |
| 34 | return first_executing_node(node->data.unwrap_err_expr.op1); | |
| 35 | case NodeTypeArrayAccessExpr: | |
| 36 | return first_executing_node(node->data.array_access_expr.array_ref_expr); | |
| 37 | case NodeTypeSliceExpr: | |
| 38 | return first_executing_node(node->data.slice_expr.array_ref_expr); | |
| 39 | case NodeTypeFieldAccessExpr: | |
| 40 | return first_executing_node(node->data.field_access_expr.struct_expr); | |
| 41 | case NodeTypeSwitchRange: | |
| 42 | return first_executing_node(node->data.switch_range.start); | |
| 43 | case NodeTypeRoot: | |
| 44 | case NodeTypeFnProto: | |
| 45 | case NodeTypeFnDef: | |
| 46 | case NodeTypeFnDecl: | |
| 47 | case NodeTypeParamDecl: | |
| 48 | case NodeTypeBlock: | |
| 49 | case NodeTypeReturnExpr: | |
| 50 | case NodeTypeDefer: | |
| 51 | case NodeTypeVariableDeclaration: | |
| 52 | case NodeTypeTypeDecl: | |
| 53 | case NodeTypeErrorValueDecl: | |
| 54 | case NodeTypeNumberLiteral: | |
| 55 | case NodeTypeStringLiteral: | |
| 56 | case NodeTypeCharLiteral: | |
| 57 | case NodeTypeSymbol: | |
| 58 | case NodeTypePrefixOpExpr: | |
| 59 | case NodeTypeUse: | |
| 60 | case NodeTypeBoolLiteral: | |
| 61 | case NodeTypeNullLiteral: | |
| 62 | case NodeTypeUndefinedLiteral: | |
| 63 | case NodeTypeThisLiteral: | |
| 64 | case NodeTypeIfBoolExpr: | |
| 65 | case NodeTypeIfVarExpr: | |
| 66 | case NodeTypeLabel: | |
| 67 | case NodeTypeGoto: | |
| 68 | case NodeTypeBreak: | |
| 69 | case NodeTypeContinue: | |
| 70 | case NodeTypeAsmExpr: | |
| 71 | case NodeTypeContainerDecl: | |
| 72 | case NodeTypeStructField: | |
| 73 | case NodeTypeStructValueField: | |
| 74 | case NodeTypeWhileExpr: | |
| 75 | case NodeTypeForExpr: | |
| 76 | case NodeTypeSwitchExpr: | |
| 77 | case NodeTypeSwitchProng: | |
| 78 | case NodeTypeArrayType: | |
| 79 | case NodeTypeErrorType: | |
| 80 | case NodeTypeTypeLiteral: | |
| 81 | case NodeTypeContainerInitExpr: | |
| 82 | case NodeTypeVarLiteral: | |
| 83 | return node; | |
| 84 | } | |
| 85 | zig_unreachable(); | |
| 86 | } | |
| 87 | ||
| 88 | 27 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 89 | 28 | // if this assert fails, then parseh generated code that |
| 90 | 29 | // failed semantic analysis, which isn't supposed to happen |
| ... | ... | @@ -199,6 +138,13 @@ ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_en |
| 199 | 138 | return scope; |
| 200 | 139 | } |
| 201 | 140 | |
| 141 | Scope *create_comptime_scope(AstNode *node, Scope *parent) { | |
| 142 | assert(node->type == NodeTypeCompTime); | |
| 143 | ScopeCompTime *scope = allocate<ScopeCompTime>(1); | |
| 144 | init_scope(&scope->base, ScopeIdCompTime, node, parent); | |
| 145 | return &scope->base; | |
| 146 | } | |
| 147 | ||
| 202 | 148 | ImportTableEntry *get_scope_import(Scope *scope) { |
| 203 | 149 | while (scope) { |
| 204 | 150 | if (scope->id == ScopeIdDecls) { |
| ... | ... | @@ -1804,6 +1750,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 1804 | 1750 | case NodeTypeSwitchRange: |
| 1805 | 1751 | case NodeTypeLabel: |
| 1806 | 1752 | case NodeTypeGoto: |
| 1753 | case NodeTypeCompTime: | |
| 1807 | 1754 | case NodeTypeBreak: |
| 1808 | 1755 | case NodeTypeContinue: |
| 1809 | 1756 | case NodeTypeAsmExpr: |
| ... | ... | @@ -2199,6 +2146,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { |
| 2199 | 2146 | case ScopeIdVarDecl: |
| 2200 | 2147 | case ScopeIdCImport: |
| 2201 | 2148 | case ScopeIdLoop: |
| 2149 | case ScopeIdCompTime: | |
| 2202 | 2150 | scope = scope->parent; |
| 2203 | 2151 | continue; |
| 2204 | 2152 | case ScopeIdFnDef: |
src/analyze.hpp+1-2| ... | ... | @@ -42,8 +42,6 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry); |
| 42 | 42 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, |
| 43 | 43 | Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code); |
| 44 | 44 | |
| 45 | AstNode *first_executing_node(AstNode *node); | |
| 46 | ||
| 47 | 45 | |
| 48 | 46 | // TODO move these over, these used to be static |
| 49 | 47 | bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type); |
| ... | ... | @@ -95,6 +93,7 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent); |
| 95 | 93 | Scope *create_loop_scope(AstNode *node, Scope *parent); |
| 96 | 94 | ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); |
| 97 | 95 | ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); |
| 96 | Scope *create_comptime_scope(AstNode *node, Scope *parent); | |
| 98 | 97 | |
| 99 | 98 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 100 | 99 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/ast_render.cpp+9-2| ... | ... | @@ -197,6 +197,8 @@ static const char *node_type_str(NodeType node_type) { |
| 197 | 197 | return "Label"; |
| 198 | 198 | case NodeTypeGoto: |
| 199 | 199 | return "Goto"; |
| 200 | case NodeTypeCompTime: | |
| 201 | return "CompTime"; | |
| 200 | 202 | case NodeTypeBreak: |
| 201 | 203 | return "Break"; |
| 202 | 204 | case NodeTypeContinue: |
| ... | ... | @@ -810,8 +812,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 810 | 812 | } |
| 811 | 813 | case NodeTypeGoto: |
| 812 | 814 | { |
| 813 | const char *inline_str = node->data.goto_expr.is_inline ? "inline " : ""; | |
| 814 | fprintf(ar->f, "%sgoto %s", inline_str, buf_ptr(node->data.goto_expr.name)); | |
| 815 | fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name)); | |
| 816 | break; | |
| 817 | } | |
| 818 | case NodeTypeCompTime: | |
| 819 | { | |
| 820 | fprintf(ar->f, "comptime "); | |
| 821 | render_node_grouped(ar, node->data.comptime_expr.expr); | |
| 815 | 822 | break; |
| 816 | 823 | } |
| 817 | 824 | case NodeTypeForExpr: |
src/codegen.cpp+2-1| ... | ... | @@ -316,7 +316,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 316 | 316 | case ScopeIdBlock: |
| 317 | 317 | case ScopeIdDefer: |
| 318 | 318 | case ScopeIdVarDecl: |
| 319 | case ScopeIdLoop: | |
| 320 | 319 | { |
| 321 | 320 | assert(scope->parent); |
| 322 | 321 | ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, |
| ... | ... | @@ -328,6 +327,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 328 | 327 | return scope->di_scope; |
| 329 | 328 | } |
| 330 | 329 | case ScopeIdDeferExpr: |
| 330 | case ScopeIdLoop: | |
| 331 | case ScopeIdCompTime: | |
| 331 | 332 | return get_di_scope(g, scope->parent); |
| 332 | 333 | } |
| 333 | 334 | zig_unreachable(); |
src/ir.cpp+44-27| ... | ... | @@ -64,8 +64,16 @@ ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { |
| 64 | 64 | } |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | static bool ir_should_inline(IrBuilder *irb) { | |
| 68 | return irb->exec->is_inline; | |
| 67 | static bool ir_should_inline(IrExecutable *exec, Scope *scope) { | |
| 68 | if (exec->is_inline) | |
| 69 | return true; | |
| 70 | ||
| 71 | while (scope != nullptr) { | |
| 72 | if (scope->id == ScopeIdCompTime) | |
| 73 | return true; | |
| 74 | scope = scope->parent; | |
| 75 | } | |
| 76 | return false; | |
| 69 | 77 | } |
| 70 | 78 | |
| 71 | 79 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| ... | ... | @@ -2904,7 +2912,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2904 | 2912 | IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); |
| 2905 | 2913 | |
| 2906 | 2914 | IrInstruction *is_comptime; |
| 2907 | if (ir_should_inline(irb)) { | |
| 2915 | if (ir_should_inline(irb->exec, scope)) { | |
| 2908 | 2916 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2909 | 2917 | } else { |
| 2910 | 2918 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); |
| ... | ... | @@ -2926,7 +2934,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2926 | 2934 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, return_value); |
| 2927 | 2935 | |
| 2928 | 2936 | IrInstruction *is_comptime; |
| 2929 | if (ir_should_inline(irb)) { | |
| 2937 | if (ir_should_inline(irb->exec, scope)) { | |
| 2930 | 2938 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 2931 | 2939 | } else { |
| 2932 | 2940 | is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); |
| ... | ... | @@ -2958,7 +2966,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2958 | 2966 | |
| 2959 | 2967 | IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn"); |
| 2960 | 2968 | IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue"); |
| 2961 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb)); | |
| 2969 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope)); | |
| 2962 | 2970 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime)); |
| 2963 | 2971 | |
| 2964 | 2972 | ir_set_cursor_at_end(irb, return_block); |
| ... | ... | @@ -2984,7 +2992,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2984 | 2992 | |
| 2985 | 2993 | IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); |
| 2986 | 2994 | IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); |
| 2987 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb)); | |
| 2995 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope)); | |
| 2988 | 2996 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_non_null, continue_block, return_block, is_comptime)); |
| 2989 | 2997 | |
| 2990 | 2998 | ir_set_cursor_at_end(irb, return_block); |
| ... | ... | @@ -3128,7 +3136,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3128 | 3136 | |
| 3129 | 3137 | if (!return_value || !instr_is_unreachable(return_value)) { |
| 3130 | 3138 | IrInstruction *is_comptime = ir_mark_gen(ir_build_const_bool(irb, child_scope, statement_node, |
| 3131 | ir_should_inline(irb))); | |
| 3139 | ir_should_inline(irb->exec, child_scope))); | |
| 3132 | 3140 | ir_mark_gen(ir_build_br(irb, child_scope, statement_node, label_block, is_comptime)); |
| 3133 | 3141 | } |
| 3134 | 3142 | ir_set_cursor_at_end(irb, label_block); |
| ... | ... | @@ -3207,7 +3215,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node |
| 3207 | 3215 | IrBasicBlock *post_val1_block = irb->current_basic_block; |
| 3208 | 3216 | |
| 3209 | 3217 | IrInstruction *is_comptime; |
| 3210 | if (ir_should_inline(irb)) { | |
| 3218 | if (ir_should_inline(irb->exec, scope)) { | |
| 3211 | 3219 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 3212 | 3220 | } else { |
| 3213 | 3221 | is_comptime = ir_build_test_comptime(irb, scope, node, val1); |
| ... | ... | @@ -3249,7 +3257,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod |
| 3249 | 3257 | IrBasicBlock *post_val1_block = irb->current_basic_block; |
| 3250 | 3258 | |
| 3251 | 3259 | IrInstruction *is_comptime; |
| 3252 | if (ir_should_inline(irb)) { | |
| 3260 | if (ir_should_inline(irb->exec, scope)) { | |
| 3253 | 3261 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 3254 | 3262 | } else { |
| 3255 | 3263 | is_comptime = ir_build_test_comptime(irb, scope, node, val1); |
| ... | ... | @@ -3296,7 +3304,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As |
| 3296 | 3304 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val); |
| 3297 | 3305 | |
| 3298 | 3306 | IrInstruction *is_comptime; |
| 3299 | if (ir_should_inline(irb)) { | |
| 3307 | if (ir_should_inline(irb->exec, parent_scope)) { | |
| 3300 | 3308 | is_comptime = ir_build_const_bool(irb, parent_scope, node, true); |
| 3301 | 3309 | } else { |
| 3302 | 3310 | is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null); |
| ... | ... | @@ -4042,8 +4050,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 4042 | 4050 | return args[i]; |
| 4043 | 4051 | } |
| 4044 | 4052 | |
| 4045 | bool is_comptime = node->data.fn_call_expr.is_comptime; | |
| 4046 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, is_comptime); | |
| 4053 | return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false); | |
| 4047 | 4054 | } |
| 4048 | 4055 | |
| 4049 | 4056 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | ... | @@ -4054,7 +4061,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode |
| 4054 | 4061 | return condition; |
| 4055 | 4062 | |
| 4056 | 4063 | IrInstruction *is_comptime; |
| 4057 | if (ir_should_inline(irb) || node->data.if_bool_expr.is_inline) { | |
| 4064 | if (ir_should_inline(irb->exec, scope) || node->data.if_bool_expr.is_inline) { | |
| 4058 | 4065 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 4059 | 4066 | } else { |
| 4060 | 4067 | is_comptime = ir_build_test_comptime(irb, scope, node, condition); |
| ... | ... | @@ -4281,7 +4288,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 4281 | 4288 | bool is_const = variable_declaration->is_const; |
| 4282 | 4289 | bool is_extern = variable_declaration->is_extern; |
| 4283 | 4290 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, |
| 4284 | ir_should_inline(irb) || variable_declaration->is_inline); | |
| 4291 | ir_should_inline(irb->exec, scope) || variable_declaration->is_inline); | |
| 4285 | 4292 | VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, |
| 4286 | 4293 | is_const, is_const, is_shadowable, is_comptime); |
| 4287 | 4294 | // we detect IrInstructionIdDeclVar in gen_block to make sure the next node |
| ... | ... | @@ -4312,7 +4319,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4312 | 4319 | IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd"); |
| 4313 | 4320 | |
| 4314 | 4321 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, |
| 4315 | ir_should_inline(irb) || node->data.while_expr.is_inline); | |
| 4322 | ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); | |
| 4316 | 4323 | ir_build_br(irb, scope, node, cond_block, is_comptime); |
| 4317 | 4324 | |
| 4318 | 4325 | if (continue_expr_node) { |
| ... | ... | @@ -4381,7 +4388,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4381 | 4388 | } |
| 4382 | 4389 | |
| 4383 | 4390 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, |
| 4384 | ir_should_inline(irb) || node->data.for_expr.is_inline); | |
| 4391 | ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); | |
| 4385 | 4392 | |
| 4386 | 4393 | Scope *child_scope = create_loop_scope(node, parent_scope); |
| 4387 | 4394 | |
| ... | ... | @@ -4602,7 +4609,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 4602 | 4609 | IrBasicBlock *endif_block = ir_build_basic_block(irb, scope, "MaybeEndIf"); |
| 4603 | 4610 | |
| 4604 | 4611 | IrInstruction *is_comptime; |
| 4605 | if (ir_should_inline(irb) || node->data.if_var_expr.is_inline) { | |
| 4612 | if (ir_should_inline(irb->exec, scope) || node->data.if_var_expr.is_inline) { | |
| 4606 | 4613 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 4607 | 4614 | } else { |
| 4608 | 4615 | is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); |
| ... | ... | @@ -4714,7 +4721,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 4714 | 4721 | ZigList<IrInstructionSwitchBrCase> cases = {0}; |
| 4715 | 4722 | |
| 4716 | 4723 | IrInstruction *is_comptime; |
| 4717 | if (ir_should_inline(irb) || node->data.switch_expr.is_inline) { | |
| 4724 | if (ir_should_inline(irb->exec, scope) || node->data.switch_expr.is_inline) { | |
| 4718 | 4725 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 4719 | 4726 | } else { |
| 4720 | 4727 | is_comptime = ir_build_test_comptime(irb, scope, node, target_value); |
| ... | ... | @@ -4892,6 +4899,13 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 4892 | 4899 | return ir_build_unreachable(irb, scope, node); |
| 4893 | 4900 | } |
| 4894 | 4901 | |
| 4902 | static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LValPurpose lval) { | |
| 4903 | assert(node->type == NodeTypeCompTime); | |
| 4904 | ||
| 4905 | Scope *child_scope = create_comptime_scope(node, parent_scope); | |
| 4906 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); | |
| 4907 | } | |
| 4908 | ||
| 4895 | 4909 | static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 4896 | 4910 | assert(node->type == NodeTypeBreak); |
| 4897 | 4911 | |
| ... | ... | @@ -4904,7 +4918,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) |
| 4904 | 4918 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 4905 | 4919 | |
| 4906 | 4920 | IrInstruction *is_comptime; |
| 4907 | if (ir_should_inline(irb) || node->data.break_expr.is_inline) { | |
| 4921 | if (ir_should_inline(irb->exec, scope) || node->data.break_expr.is_inline) { | |
| 4908 | 4922 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 4909 | 4923 | } else { |
| 4910 | 4924 | is_comptime = loop_stack_item->is_comptime; |
| ... | ... | @@ -4927,7 +4941,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod |
| 4927 | 4941 | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 4928 | 4942 | |
| 4929 | 4943 | IrInstruction *is_comptime; |
| 4930 | if (ir_should_inline(irb) || node->data.continue_expr.is_inline) { | |
| 4944 | if (ir_should_inline(irb->exec, scope) || node->data.continue_expr.is_inline) { | |
| 4931 | 4945 | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 4932 | 4946 | } else { |
| 4933 | 4947 | is_comptime = loop_stack_item->is_comptime; |
| ... | ... | @@ -5003,7 +5017,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 5003 | 5017 | IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val); |
| 5004 | 5018 | |
| 5005 | 5019 | IrInstruction *is_comptime; |
| 5006 | if (ir_should_inline(irb)) { | |
| 5020 | if (ir_should_inline(irb->exec, parent_scope)) { | |
| 5007 | 5021 | is_comptime = ir_build_const_bool(irb, parent_scope, node, true); |
| 5008 | 5022 | } else { |
| 5009 | 5023 | is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err); |
| ... | ... | @@ -5197,6 +5211,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5197 | 5211 | return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); |
| 5198 | 5212 | case NodeTypeGoto: |
| 5199 | 5213 | return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); |
| 5214 | case NodeTypeCompTime: | |
| 5215 | return ir_gen_comptime(irb, scope, node, lval); | |
| 5200 | 5216 | case NodeTypeTypeLiteral: |
| 5201 | 5217 | return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval); |
| 5202 | 5218 | case NodeTypeErrorType: |
| ... | ... | @@ -5259,7 +5275,7 @@ static bool ir_goto_pass2(IrBuilder *irb) { |
| 5259 | 5275 | label->used = true; |
| 5260 | 5276 | |
| 5261 | 5277 | IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node, |
| 5262 | ir_should_inline(irb) || source_node->data.goto_expr.is_inline); | |
| 5278 | ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline); | |
| 5263 | 5279 | if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false, false)) { |
| 5264 | 5280 | add_node_error(irb->codegen, source_node, |
| 5265 | 5281 | buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); |
| ... | ... | @@ -5379,7 +5395,7 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) |
| 5379 | 5395 | } |
| 5380 | 5396 | |
| 5381 | 5397 | static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { |
| 5382 | if (ir_should_inline(&ira->new_irb)) { | |
| 5398 | if (ir_should_inline(ira->new_irb.exec, source_instruction->scope)) { | |
| 5383 | 5399 | ir_add_error(ira, source_instruction, buf_sprintf("unable to evaluate constant expression")); |
| 5384 | 5400 | return false; |
| 5385 | 5401 | } |
| ... | ... | @@ -7841,7 +7857,8 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 7841 | 7857 | if (fn_ref->value.type->id == TypeTableEntryIdInvalid) |
| 7842 | 7858 | return ira->codegen->builtin_types.entry_invalid; |
| 7843 | 7859 | |
| 7844 | bool is_inline = call_instruction->is_comptime || ir_should_inline(&ira->new_irb); | |
| 7860 | bool is_inline = call_instruction->is_comptime || | |
| 7861 | ir_should_inline(ira->new_irb.exec, call_instruction->base.scope); | |
| 7845 | 7862 | |
| 7846 | 7863 | if (is_inline || instr_is_comptime(fn_ref)) { |
| 7847 | 7864 | if (fn_ref->value.type->id == TypeTableEntryIdMetaType) { |
| ... | ... | @@ -8146,7 +8163,7 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct |
| 8146 | 8163 | return ir_unreach_error(ira); |
| 8147 | 8164 | |
| 8148 | 8165 | if (!cond_br_instruction->base.is_gen && !condition->value.depends_on_compile_var && |
| 8149 | !ir_should_inline(&ira->new_irb)) | |
| 8166 | !ir_should_inline(ira->new_irb.exec, cond_br_instruction->base.scope)) | |
| 8150 | 8167 | { |
| 8151 | 8168 | const char *true_or_false = cond_is_true ? "true" : "false"; |
| 8152 | 8169 | ir_add_error(ira, &cond_br_instruction->base, |
| ... | ... | @@ -9814,7 +9831,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 9814 | 9831 | |
| 9815 | 9832 | IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); |
| 9816 | 9833 | |
| 9817 | bool is_comptime = ir_should_inline(&ira->new_irb); | |
| 9834 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | |
| 9818 | 9835 | |
| 9819 | 9836 | ConstExprValue const_val = {}; |
| 9820 | 9837 | const_val.special = ConstValSpecialStatic; |
| ... | ... | @@ -9931,7 +9948,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira |
| 9931 | 9948 | const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count); |
| 9932 | 9949 | const_val.data.x_array.size = elem_count; |
| 9933 | 9950 | |
| 9934 | bool is_comptime = ir_should_inline(&ira->new_irb); | |
| 9951 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); | |
| 9935 | 9952 | |
| 9936 | 9953 | IrInstruction **new_items = allocate<IrInstruction *>(elem_count); |
| 9937 | 9954 |
src/parser.cpp+34-39| ... | ... | @@ -585,29 +585,14 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m |
| 585 | 585 | } |
| 586 | 586 | |
| 587 | 587 | /* |
| 588 | GotoExpression = option("inline") "goto" Symbol | |
| 588 | GotoExpression = "goto" Symbol | |
| 589 | 589 | */ |
| 590 | 590 | static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 591 | Token *first_token = &pc->tokens->at(*token_index); | |
| 592 | Token *goto_token; | |
| 593 | bool is_inline; | |
| 594 | if (first_token->id == TokenIdKeywordInline) { | |
| 595 | is_inline = true; | |
| 596 | goto_token = &pc->tokens->at(*token_index + 1); | |
| 597 | if (goto_token->id == TokenIdKeywordGoto) { | |
| 598 | *token_index += 2; | |
| 599 | } else if (mandatory) { | |
| 600 | ast_expect_token(pc, first_token, TokenIdKeywordGoto); | |
| 601 | zig_unreachable(); | |
| 602 | } else { | |
| 603 | return nullptr; | |
| 604 | } | |
| 605 | } else if (first_token->id == TokenIdKeywordGoto) { | |
| 606 | goto_token = first_token; | |
| 607 | is_inline = false; | |
| 591 | Token *goto_token = &pc->tokens->at(*token_index); | |
| 592 | if (goto_token->id == TokenIdKeywordGoto) { | |
| 608 | 593 | *token_index += 1; |
| 609 | 594 | } else if (mandatory) { |
| 610 | ast_expect_token(pc, first_token, TokenIdKeywordGoto); | |
| 595 | ast_expect_token(pc, goto_token, TokenIdKeywordGoto); | |
| 611 | 596 | zig_unreachable(); |
| 612 | 597 | } else { |
| 613 | 598 | return nullptr; |
| ... | ... | @@ -617,11 +602,30 @@ static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool |
| 617 | 602 | |
| 618 | 603 | Token *dest_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 619 | 604 | node->data.goto_expr.name = token_buf(dest_symbol); |
| 620 | node->data.goto_expr.is_inline = is_inline; | |
| 621 | 605 | return node; |
| 622 | 606 | } |
| 607 | ||
| 623 | 608 | /* |
| 624 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 609 | CompTimeExpression = "comptime" Expression | |
| 610 | */ | |
| 611 | static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, bool mandatory) { | |
| 612 | Token *comptime_token = &pc->tokens->at(*token_index); | |
| 613 | if (comptime_token->id == TokenIdKeywordCompTime) { | |
| 614 | *token_index += 1; | |
| 615 | } else if (mandatory) { | |
| 616 | ast_expect_token(pc, comptime_token, TokenIdKeywordCompTime); | |
| 617 | zig_unreachable(); | |
| 618 | } else { | |
| 619 | return nullptr; | |
| 620 | } | |
| 621 | ||
| 622 | AstNode *node = ast_create_node(pc, NodeTypeCompTime, comptime_token); | |
| 623 | node->data.comptime_expr.expr = ast_parse_expression(pc, token_index, true); | |
| 624 | return node; | |
| 625 | } | |
| 626 | ||
| 627 | /* | |
| 628 | PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | CompTimeExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl | |
| 625 | 629 | KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" |
| 626 | 630 | */ |
| 627 | 631 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| ... | ... | @@ -706,6 +710,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 706 | 710 | if (goto_node) |
| 707 | 711 | return goto_node; |
| 708 | 712 | |
| 713 | AstNode *comptime_node = ast_parse_comptime_expr(pc, token_index, false); | |
| 714 | if (comptime_node) | |
| 715 | return comptime_node; | |
| 716 | ||
| 709 | 717 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); |
| 710 | 718 | if (grouped_expr_node) { |
| 711 | 719 | return grouped_expr_node; |
| ... | ... | @@ -835,7 +843,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde |
| 835 | 843 | } |
| 836 | 844 | |
| 837 | 845 | /* |
| 838 | SuffixOpExpression = option("inline") PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 846 | SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) | |
| 839 | 847 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 840 | 848 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 841 | 849 | SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const)) |
| ... | ... | @@ -843,24 +851,9 @@ FieldAccessExpression : token(Dot) token(Symbol) |
| 843 | 851 | StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression |
| 844 | 852 | */ |
| 845 | 853 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 846 | Token *inline_token = &pc->tokens->at(*token_index); | |
| 847 | bool is_comptime; | |
| 848 | if (inline_token->id == TokenIdKeywordInline) { | |
| 849 | // TODO make it an error if something other than function call has the comptime keyword | |
| 850 | is_comptime = true; | |
| 851 | *token_index += 1; | |
| 852 | } else { | |
| 853 | is_comptime = false; | |
| 854 | } | |
| 855 | ||
| 856 | ||
| 857 | 854 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); |
| 858 | if (!primary_expr) { | |
| 859 | if (is_comptime) { | |
| 860 | *token_index -= 1; | |
| 861 | } | |
| 855 | if (!primary_expr) | |
| 862 | 856 | return nullptr; |
| 863 | } | |
| 864 | 857 | |
| 865 | 858 | while (true) { |
| 866 | 859 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -869,7 +862,6 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, |
| 869 | 862 | |
| 870 | 863 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token); |
| 871 | 864 | node->data.fn_call_expr.fn_ref_expr = primary_expr; |
| 872 | node->data.fn_call_expr.is_comptime = is_comptime; | |
| 873 | 865 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); |
| 874 | 866 | |
| 875 | 867 | primary_expr = node; |
| ... | ... | @@ -2624,6 +2616,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2624 | 2616 | case NodeTypeGoto: |
| 2625 | 2617 | // none |
| 2626 | 2618 | break; |
| 2619 | case NodeTypeCompTime: | |
| 2620 | visit_field(&node->data.comptime_expr.expr, visit, context); | |
| 2621 | break; | |
| 2627 | 2622 | case NodeTypeBreak: |
| 2628 | 2623 | // none |
| 2629 | 2624 | break; |