Browse Source

Diverging procedures `proc() -> !` (no return)

gingerBill 7 years ago
parent
commit
3825eab989
8 changed files with 37 additions and 6 deletions
  1. 1 1
      core/runtime/core.odin
  2. 10 0
      examples/demo/demo.odin
  3. 5 1
      src/check_stmt.cpp
  4. 1 0
      src/check_type.cpp
  5. 7 0
      src/ir_print.cpp
  6. 11 4
      src/parser.cpp
  7. 1 0
      src/parser.hpp
  8. 1 0
      src/types.cpp

+ 1 - 1
core/runtime/core.odin

@@ -299,7 +299,7 @@ foreign {
 	debug_trap :: proc() ---;
 
 	@(link_name="llvm.trap")
-	trap :: proc() ---;
+	trap :: proc() -> ! ---;
 
 	@(link_name="llvm.readcyclecounter")
 	read_cycle_counter :: proc() -> u64 ---;

+ 10 - 0
examples/demo/demo.odin

@@ -785,6 +785,15 @@ bit_set_type :: proc() {
 	}
 }
 
+diverging_procedures :: proc() {
+	// Diverging procedures may never return
+	foo :: proc() -> ! {
+		fmt.println("I'm a diverging procedure");
+	}
+
+	foo();
+}
+
 
 main :: proc() {
 	when true {
@@ -800,5 +809,6 @@ main :: proc() {
 		cstring_example();
 		deprecated_attribute();
 		bit_set_type();
+		diverging_procedures();
 	}
 }

+ 5 - 1
src/check_stmt.cpp

@@ -1213,13 +1213,17 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 		GB_ASSERT(proc_type->kind == Type_Proc);
 		// Type *proc_type = c->proc_stack[c->proc_stack.count-1];
 		TypeProc *pt = &proc_type->Proc;
+		if (pt->no_return) {
+			error(rs->token, "Diverging procedures may not return");
+			break;
+		}
+
 		isize result_count = 0;
 		bool has_named_results = pt->has_named_results;
 		if (pt->results) {
 			result_count = proc_type->Proc.results->Tuple.variables.count;
 		}
 
-
 		auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
 		defer (array_free(&operands));
 

+ 1 - 0
src/check_type.cpp

@@ -1951,6 +1951,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
 	type->Proc.calling_convention   = cc;
 	type->Proc.is_polymorphic       = pt->generic;
 	type->Proc.specialization_count = specialization_count;
+	type->Proc.no_return            = pt->no_return;
 
 	if (param_count > 0) {
 		Entity *end = params->Tuple.variables[param_count-1];

+ 7 - 0
src/ir_print.cpp

@@ -1475,6 +1475,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		}
 		ir_write_str_lit(f, ")");
 
+		if (proc_type->Proc.no_return) {
+			ir_write_str_lit(f, " noreturn");
+		}
 		ir_print_debug_location(f, m, value, instr->block->proc);
 
 		break;
@@ -1624,6 +1627,10 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 		break;
 	}
 
+	if (proc_type->no_return) {
+		ir_write_str_lit(f, "noreturn ");
+	}
+
 	if (m->generate_debug_info && proc->entity != nullptr && proc->body != nullptr) {
 		irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
 		if (di_ != nullptr) {

+ 11 - 4
src/parser.cpp

@@ -866,7 +866,7 @@ Ast *ast_poly_type(AstFile *f, Token token, Ast *type, Ast *specialization) {
 }
 
 
-Ast *ast_proc_type(AstFile *f, Token token, Ast *params, Ast *results, u64 tags, ProcCallingConvention calling_convention, bool generic) {
+Ast *ast_proc_type(AstFile *f, Token token, Ast *params, Ast *results, u64 tags, ProcCallingConvention calling_convention, bool generic, bool no_return) {
 	Ast *result = alloc_ast_node(f, Ast_ProcType);
 	result->ProcType.token = token;
 	result->ProcType.params = params;
@@ -874,6 +874,7 @@ Ast *ast_proc_type(AstFile *f, Token token, Ast *params, Ast *results, u64 tags,
 	result->ProcType.tags = tags;
 	result->ProcType.calling_convention = calling_convention;
 	result->ProcType.generic = generic;
+	result->ProcType.no_return = no_return;
 	return result;
 }
 
@@ -2620,11 +2621,16 @@ Ast *parse_block_stmt(AstFile *f, b32 is_when) {
 
 
 
-Ast *parse_results(AstFile *f) {
+Ast *parse_results(AstFile *f, bool *no_return) {
 	if (!allow_token(f, Token_ArrowRight)) {
 		return nullptr;
 	}
 
+	if (allow_token(f, Token_Not)) {
+		if (no_return) *no_return = true;
+		return nullptr;
+	}
+
 	isize prev_level = f->expr_level;
 	defer (f->expr_level = prev_level);
 	// f->expr_level = -1;
@@ -2661,6 +2667,7 @@ ProcCallingConvention string_to_calling_convention(String s) {
 Ast *parse_proc_type(AstFile *f, Token proc_token) {
 	Ast *params = nullptr;
 	Ast *results = nullptr;
+	bool no_return = false;
 
 	ProcCallingConvention cc = ProcCC_Invalid;
 	if (f->curr_token.kind == Token_String) {
@@ -2684,7 +2691,7 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
 	expect_token(f, Token_OpenParen);
 	params = parse_field_list(f, nullptr, FieldFlag_Signature, Token_CloseParen, true, true);
 	expect_token_after(f, Token_CloseParen, "parameter list");
-	results = parse_results(f);
+	results = parse_results(f, &no_return);
 
 	u64 tags = 0;
 	parse_proc_tags(f, &tags);
@@ -2710,7 +2717,7 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
 		}
 	}
 end:
-	return ast_proc_type(f, proc_token, params, results, tags, cc, is_generic);
+	return ast_proc_type(f, proc_token, params, results, tags, cc, is_generic, no_return);
 }
 
 Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) {

+ 1 - 0
src/parser.hpp

@@ -446,6 +446,7 @@ AST_KIND(_TypeBegin, "", bool) \
 		u64 tags;    \
 		ProcCallingConvention calling_convention; \
 		bool generic; \
+		bool no_return; \
 	}) \
 	AST_KIND(PointerType, "pointer type", struct { \
 		Token token; \

+ 1 - 0
src/types.cpp

@@ -174,6 +174,7 @@ struct TypeUnion {
 		bool     is_poly_specialized;                     \
 		bool     has_proc_default_values;                 \
 		bool     has_named_results;                       \
+		bool     no_return;                               \
 		isize    specialization_count;                    \
 		ProcCallingConvention calling_convention;         \
 	})                                                    \