authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-07 00:22:14-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-07 00:22:14-05:00
logc0b2fe4d6cf3f8c6aa07899863861d506f588ef5
treed48eb21337f5da54b535bbc6be22290a3e3bd00a
parent7d9fa01ed54e99368f7351dbf1193e4f79ddf806

IR: add error for assigning runtime value to inline var


4 files changed, 74 insertions(+), 34 deletions(-)

doc/langref.md+2-2
...@@ -91,9 +91,9 @@ Defer = option("%" | "?") "defer" Expression...@@ -91,9 +91,9 @@ Defer = option("%" | "?") "defer" Expression
9191
92IfExpression = IfVarExpression | IfBoolExpression92IfExpression = IfVarExpression | IfBoolExpression
9393
94IfBoolExpression = "if" "(" Expression ")" Expression option(Else)94IfBoolExpression = option("inline") "if" "(" Expression ")" Expression option(Else)
9595
96IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)96IfVarExpression = option("inline") "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
9797
98Else = "else" Expression98Else = "else" Expression
9999
src/all_types.hpp+13-5
...@@ -78,15 +78,23 @@ struct ConstArrayValue {...@@ -78,15 +78,23 @@ struct ConstArrayValue {
78 size_t size;78 size_t size;
79};79};
8080
81enum ConstPtrSpecial {
82 ConstPtrSpecialNone,
83 // This helps us preserve the null byte when performing compile-time
84 // concatenation on C strings.
85 ConstPtrSpecialCStr,
86 // This means that the pointer points to inline memory, so attempting
87 // to write a non-compile-time known value is an error
88 ConstPtrSpecialInline,
89};
90
81struct ConstPtrValue {91struct ConstPtrValue {
82 ConstExprValue *base_ptr;92 ConstExprValue *base_ptr;
83 // If index is SIZE_MAX, then base_ptr points directly to child type.93 // If index is SIZE_MAX, then base_ptr points directly to child type.
84 // Otherwise base_ptr points to an array const val and index is offset94 // Otherwise base_ptr points to an array const val and index is offset
85 // in object units from base_ptr into the block of memory pointed to95 // in object units from base_ptr into the block of memory pointed to
86 size_t index;96 size_t index;
87 // This flag helps us preserve the null byte when performing compile-time97 ConstPtrSpecial special;
88 // concatenation on C strings.
89 bool is_c_str;
90};98};
9199
92struct ConstErrValue {100struct ConstErrValue {
...@@ -472,7 +480,7 @@ struct AstNodeIfBoolExpr {...@@ -472,7 +480,7 @@ struct AstNodeIfBoolExpr {
472 AstNode *condition;480 AstNode *condition;
473 AstNode *then_block;481 AstNode *then_block;
474 AstNode *else_node; // null, block node, or other if expr node482 AstNode *else_node; // null, block node, or other if expr node
475 bool is_inline; // TODO parse inline if483 bool is_inline;
476};484};
477485
478struct AstNodeIfVarExpr {486struct AstNodeIfVarExpr {
...@@ -480,7 +488,7 @@ struct AstNodeIfVarExpr {...@@ -480,7 +488,7 @@ struct AstNodeIfVarExpr {
480 AstNode *then_block;488 AstNode *then_block;
481 AstNode *else_node; // null, block node, or other if expr node489 AstNode *else_node; // null, block node, or other if expr node
482 bool var_is_ptr;490 bool var_is_ptr;
483 bool is_inline; // TODO parse inline ?if?491 bool is_inline;
484};492};
485493
486struct AstNodeWhileExpr {494struct AstNodeWhileExpr {
src/ir.cpp+35-19
...@@ -540,7 +540,7 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -540,7 +540,7 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
540 ptr_val->special = ConstValSpecialStatic;540 ptr_val->special = ConstValSpecialStatic;
541 ptr_val->data.x_ptr.base_ptr = array_val;541 ptr_val->data.x_ptr.base_ptr = array_val;
542 ptr_val->data.x_ptr.index = 0;542 ptr_val->data.x_ptr.index = 0;
543 ptr_val->data.x_ptr.is_c_str = true;543 ptr_val->data.x_ptr.special = ConstPtrSpecialCStr;
544544
545 return &const_instruction->base;545 return &const_instruction->base;
546}546}
...@@ -3352,13 +3352,15 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio...@@ -3352,13 +3352,15 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio
3352}3352}
33533353
3354static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,3354static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
3355 ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var)3355 ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var,
3356 ConstPtrSpecial special)
3356{3357{
3357 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, true);3358 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, true);
3358 ConstExprValue *const_val = ir_build_const_from(ira, instruction,3359 ConstExprValue *const_val = ir_build_const_from(ira, instruction,
3359 depends_on_compile_var || pointee->depends_on_compile_var);3360 depends_on_compile_var || pointee->depends_on_compile_var);
3360 const_val->data.x_ptr.base_ptr = pointee;3361 const_val->data.x_ptr.base_ptr = pointee;
3361 const_val->data.x_ptr.index = SIZE_MAX;3362 const_val->data.x_ptr.index = SIZE_MAX;
3363 const_val->data.x_ptr.special = special;
3362 return ptr_type;3364 return ptr_type;
3363}3365}
33643366
...@@ -3791,7 +3793,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst...@@ -3791,7 +3793,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
3791 ConstExprValue *val = ir_resolve_const(ira, value);3793 ConstExprValue *val = ir_resolve_const(ira, value);
3792 if (!val)3794 if (!val)
3793 return ira->codegen->builtin_types.entry_invalid;3795 return ira->codegen->builtin_types.entry_invalid;
3794 return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false);3796 return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false, ConstPtrSpecialNone);
3795 }3797 }
37963798
3797 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);3799 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
...@@ -4338,10 +4340,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -4338,10 +4340,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
4338 var->type = result_type;4340 var->type = result_type;
4339 assert(var->type);4341 assert(var->type);
43404342
4341 if (var->mem_slot_index != SIZE_MAX) {4343 if (casted_init_value->static_value.special == ConstValSpecialStatic) {
4342 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);4344 if (var->mem_slot_index != SIZE_MAX) {
4343 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];4345 assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
4344 *mem_slot = casted_init_value->static_value;4346 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
4347 *mem_slot = casted_init_value->static_value;
4348 }
4349 } else if (var->is_inline) {
4350 ir_add_error(ira, &decl_var_instruction->base,
4351 buf_sprintf("cannot store runtime value in compile time variable"));
4352 var->type = ira->codegen->builtin_types.entry_invalid;
4353 return ira->codegen->builtin_types.entry_invalid;
4345 }4354 }
43464355
4347 ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value);4356 ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value);
...@@ -5192,7 +5201,8 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc...@@ -5192,7 +5201,8 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
5192 }5201 }
51935202
5194 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {5203 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
5195 return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false);5204 ConstPtrSpecial ptr_special = var->is_inline ? ConstPtrSpecialInline : ConstPtrSpecialNone;
5205 return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special);
5196 } else {5206 } else {
5197 ir_build_var_ptr_from(&ira->new_irb, instruction, var);5207 ir_build_var_ptr_from(&ira->new_irb, instruction, var);
5198 return get_pointer_to_type(ira->codegen, var->type, false);5208 return get_pointer_to_type(ira->codegen, var->type, false);
...@@ -5407,7 +5417,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -5407,7 +5417,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
5407 const_val->special = ConstValSpecialStatic;5417 const_val->special = ConstValSpecialStatic;
5408 const_val->data.x_fn = fn_entry;5418 const_val->data.x_fn = fn_entry;
54095419
5410 return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var);5420 return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
5411 }5421 }
5412 case TldIdContainer:5422 case TldIdContainer:
5413 {5423 {
...@@ -5420,7 +5430,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -5420,7 +5430,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
5420 const_val->special = ConstValSpecialStatic;5430 const_val->special = ConstValSpecialStatic;
5421 const_val->data.x_type = tld_container->type_entry;5431 const_val->data.x_type = tld_container->type_entry;
54225432
5423 return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, depends_on_compile_var);5433 return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
5424 }5434 }
5425 case TldIdTypeDef:5435 case TldIdTypeDef:
5426 {5436 {
...@@ -5433,7 +5443,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -5433,7 +5443,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
5433 const_val->special = ConstValSpecialStatic;5443 const_val->special = ConstValSpecialStatic;
5434 const_val->data.x_type = tld_typedef->type_entry;5444 const_val->data.x_type = tld_typedef->type_entry;
54355445
5436 return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, depends_on_compile_var);5446 return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, depends_on_compile_var, ConstPtrSpecialNone);
5437 }5447 }
5438 }5448 }
5439 zig_unreachable();5449 zig_unreachable();
...@@ -5461,7 +5471,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -5461,7 +5471,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
5461 bignum_init_unsigned(&len_val->data.x_bignum, container_type->data.array.len);5471 bignum_init_unsigned(&len_val->data.x_bignum, container_type->data.array.len);
54625472
5463 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;5473 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
5464 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, usize, false);5474 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, usize, false, ConstPtrSpecialNone);
5465 } else {5475 } else {
5466 add_node_error(ira->codegen, source_node,5476 add_node_error(ira->codegen, source_node,
5467 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),5477 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
...@@ -5570,13 +5580,19 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru...@@ -5570,13 +5580,19 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
5570 if (casted_value == ira->codegen->invalid_instruction)5580 if (casted_value == ira->codegen->invalid_instruction)
5571 return ira->codegen->builtin_types.entry_invalid;5581 return ira->codegen->builtin_types.entry_invalid;
55725582
5573 if (ptr->static_value.special != ConstValSpecialRuntime &&5583 if (ptr->static_value.special != ConstValSpecialRuntime) {
5574 casted_value->static_value.special != ConstValSpecialRuntime)5584 bool is_inline = (ptr->static_value.data.x_ptr.special == ConstPtrSpecialInline);
5575 {5585 if (casted_value->static_value.special != ConstValSpecialRuntime) {
5576 ConstExprValue *dest_val = const_ptr_pointee(&ptr->static_value);5586 ConstExprValue *dest_val = const_ptr_pointee(&ptr->static_value);
5577 if (dest_val->special != ConstValSpecialRuntime) {5587 if (dest_val->special != ConstValSpecialRuntime) {
5578 *dest_val = casted_value->static_value;5588 *dest_val = casted_value->static_value;
5579 return ir_analyze_void(ira, &store_ptr_instruction->base);5589 return ir_analyze_void(ira, &store_ptr_instruction->base);
5590 }
5591 }
5592 if (is_inline) {
5593 ir_add_error(ira, &store_ptr_instruction->base,
5594 buf_sprintf("cannot store runtime value in compile time variable"));
5595 return ira->codegen->builtin_types.entry_invalid;
5580 }5596 }
5581 }5597 }
55825598
src/parser.cpp+24-8
...@@ -1306,25 +1306,40 @@ static AstNode *ast_parse_else(ParseContext *pc, size_t *token_index, bool manda...@@ -1306,25 +1306,40 @@ static AstNode *ast_parse_else(ParseContext *pc, size_t *token_index, bool manda
13061306
1307/*1307/*
1308IfExpression : IfVarExpression | IfBoolExpression1308IfExpression : IfVarExpression | IfBoolExpression
1309IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)1309IfBoolExpression = option("inline") "if" "(" Expression ")" Expression option(Else)
1310IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)1310IfVarExpression = option("inline") "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
1311*/1311*/
1312static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {1312static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
1313 Token *if_tok = &pc->tokens->at(*token_index);1313 Token *first_token = &pc->tokens->at(*token_index);
1314 if (if_tok->id != TokenIdKeywordIf) {1314 Token *if_tok;
1315 if (mandatory) {1315
1316 bool is_inline;
1317 if (first_token->id == TokenIdKeywordInline) {
1318 if_tok = &pc->tokens->at(*token_index + 1);
1319 if (if_tok->id == TokenIdKeywordIf) {
1320 is_inline = true;
1321 *token_index += 2;
1322 } else if (mandatory) {
1316 ast_expect_token(pc, if_tok, TokenIdKeywordIf);1323 ast_expect_token(pc, if_tok, TokenIdKeywordIf);
1317 } else {1324 } else {
1318 return nullptr;1325 return nullptr;
1319 }1326 }
1327 } else if (first_token->id == TokenIdKeywordIf) {
1328 if_tok = first_token;
1329 is_inline = false;
1330 *token_index += 1;
1331 } else if (mandatory) {
1332 ast_expect_token(pc, first_token, TokenIdKeywordIf);
1333 } else {
1334 return nullptr;
1320 }1335 }
1321 *token_index += 1;
13221336
1323 ast_eat_token(pc, token_index, TokenIdLParen);1337 ast_eat_token(pc, token_index, TokenIdLParen);
13241338
1325 Token *token = &pc->tokens->at(*token_index);1339 Token *token = &pc->tokens->at(*token_index);
1326 if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {1340 if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
1327 AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);1341 AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);
1342 node->data.if_var_expr.is_inline = is_inline;
1328 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);1343 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
1329 *token_index += 1;1344 *token_index += 1;
13301345
...@@ -1362,6 +1377,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma...@@ -1362,6 +1377,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
1362 return node;1377 return node;
1363 } else {1378 } else {
1364 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);1379 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);
1380 node->data.if_bool_expr.is_inline = is_inline;
1365 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);1381 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
1366 ast_eat_token(pc, token_index, TokenIdRParen);1382 ast_eat_token(pc, token_index, TokenIdRParen);
1367 node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);1383 node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);
...@@ -1561,12 +1577,12 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool...@@ -1561,12 +1577,12 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool
15611577
1562 bool is_inline;1578 bool is_inline;
1563 if (first_token->id == TokenIdKeywordInline) {1579 if (first_token->id == TokenIdKeywordInline) {
1564 is_inline = true;
1565 while_token = &pc->tokens->at(*token_index + 1);1580 while_token = &pc->tokens->at(*token_index + 1);
1566 if (while_token->id == TokenIdKeywordWhile) {1581 if (while_token->id == TokenIdKeywordWhile) {
1582 is_inline = true;
1567 *token_index += 2;1583 *token_index += 2;
1568 } else if (mandatory) {1584 } else if (mandatory) {
1569 ast_expect_token(pc, first_token, TokenIdKeywordWhile);1585 ast_expect_token(pc, while_token, TokenIdKeywordWhile);
1570 } else {1586 } else {
1571 return nullptr;1587 return nullptr;
1572 }1588 }