diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-28 03:47:02 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-28 03:47:02 -0500 |
| commit | a9acc8cb4574ce8f1792fbfa9bd93985a6b47f87 (patch) | |
| tree | d31ec81c7dec180d4f744950e8d504b18c3aa761 /src | |
| parent | dc26dec8e0c86c42485842eb3949edfe816f0e55 (diff) | |
| download | zig-a9acc8cb4574ce8f1792fbfa9bd93985a6b47f87.tar.gz zig-a9acc8cb4574ce8f1792fbfa9bd93985a6b47f87.zip | |
IR: error for returning from defer expression
also fix peer type resolution for pure error mixed with error union
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 13 | ||||
| -rw-r--r-- | src/analyze.cpp | 8 | ||||
| -rw-r--r-- | src/analyze.hpp | 1 | ||||
| -rw-r--r-- | src/codegen.cpp | 2 | ||||
| -rw-r--r-- | src/ir.cpp | 38 |
5 files changed, 57 insertions, 5 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index fc1abfc565..215d027c6e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -344,7 +344,7 @@ struct AstNodeDefer { // temporary data used in IR generation Scope *child_scope; - Scope *parent_scope; + Scope *expr_scope; }; struct AstNodeVariableDeclaration { @@ -1280,6 +1280,7 @@ enum ScopeId { ScopeIdDecls, ScopeIdBlock, ScopeIdDefer, + ScopeIdDeferExpr, ScopeIdVarDecl, ScopeIdCImport, ScopeIdLoop, @@ -1321,11 +1322,21 @@ struct ScopeBlock { }; // This scope is created from every defer expression. +// It's the code following the defer statement. // NodeTypeDefer struct ScopeDefer { Scope base; }; +// This scope is created from every defer expression. +// It's the parent of the defer expression itself. +// NodeTypeDefer +struct ScopeDeferExpr { + Scope base; + + bool reported_err; +}; + // This scope is created for every variable declaration inside an IrExecutable // NodeTypeVariableDeclaration, NodeTypeParamDecl struct ScopeVarDecl { diff --git a/src/analyze.cpp b/src/analyze.cpp index d19bc56143..2e3df10a81 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -163,6 +163,13 @@ ScopeDefer *create_defer_scope(AstNode *node, Scope *parent) { return scope; } +ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent) { + assert(node->type == NodeTypeDefer); + ScopeDeferExpr *scope = allocate<ScopeDeferExpr>(1); + init_scope(&scope->base, ScopeIdDeferExpr, node, parent); + return scope; +} + Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) { ScopeVarDecl *scope = allocate<ScopeVarDecl>(1); init_scope(&scope->base, ScopeIdVarDecl, node, parent); @@ -2183,6 +2190,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { return nullptr; case ScopeIdDecls: case ScopeIdDefer: + case ScopeIdDeferExpr: case ScopeIdVarDecl: case ScopeIdCImport: case ScopeIdLoop: diff --git a/src/analyze.hpp b/src/analyze.hpp index 4ee03abcd1..6204f50025 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -84,6 +84,7 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * ScopeBlock *create_block_scope(AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); +ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent); Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var); ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent); Scope *create_loop_scope(AstNode *node, Scope *parent); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4a0b901687..130fb4f351 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -325,6 +325,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); return scope->di_scope; } + case ScopeIdDeferExpr: + return get_di_scope(g, scope->parent); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index e7ca832f5d..2bb57abfca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1980,7 +1980,7 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o (gen_maybe_defers && defer_kind == ReturnKindMaybe)) { AstNode *defer_expr_node = defer_node->data.defer.expr; - ir_gen_node(irb, defer_expr_node, defer_node->data.defer.parent_scope); + ir_gen_node(irb, defer_expr_node, defer_node->data.defer.expr_scope); } } @@ -1994,6 +1994,18 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { irb->current_basic_block = basic_block; } +static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdDeferExpr) + return (ScopeDeferExpr *)scope; + if (scope->id == ScopeIdFnDef) + return nullptr; + + scope = scope->parent; + } + return nullptr; +} + static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeReturnExpr); @@ -2003,6 +2015,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_instruction; } + ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); + if (scope_defer_expr) { + if (!scope_defer_expr->reported_err) { + add_node_error(irb->codegen, node, buf_sprintf("cannot return from defer expression")); + scope_defer_expr->reported_err = true; + } + return irb->codegen->invalid_instruction; + } + Scope *outer_scope = fn_entry->child_scope; AstNode *expr_node = node->data.return_expr.expr; @@ -2593,6 +2614,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_instruction; } + // TODO put a variable of same name with invalid type in global scope + // so that future references to this same name will find a variable with an invalid type add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); return irb->codegen->invalid_instruction; } @@ -4012,9 +4035,11 @@ static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *n static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeDefer); - ScopeDefer *defer_scope = create_defer_scope(node, parent_scope); - node->data.defer.child_scope = &defer_scope->base; - node->data.defer.parent_scope = parent_scope; + ScopeDefer *defer_child_scope = create_defer_scope(node, parent_scope); + node->data.defer.child_scope = &defer_child_scope->base; + + ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(node, parent_scope); + node->data.defer.expr_scope = &defer_expr_scope->base; return ir_build_const_void(irb, parent_scope, node); } @@ -4665,6 +4690,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod ir_add_error_node(ira, source_node, buf_sprintf("unable to make error union out of null literal")); return ira->codegen->builtin_types.entry_invalid; + } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) { + return prev_inst->value.type; } else { return get_error_type(ira->codegen, prev_inst->value.type); } @@ -4675,6 +4702,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod ir_add_error_node(ira, source_node, buf_sprintf("unable to make maybe out of number literal")); return ira->codegen->builtin_types.entry_invalid; + } else if (prev_inst->value.type->id == TypeTableEntryIdMaybe) { + return prev_inst->value.type; } else { return get_maybe_type(ira->codegen, prev_inst->value.type); } @@ -9955,6 +9984,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, IrInstructionUnwrapErrPayload *instruction) { + assert(instruction->value->other); IrInstruction *value = instruction->value->other; if (value->value.type->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; |
