Browse Source

Merge branch 'master' of github.com:odin-lang/Odin

Kevin Watters 6 years ago
parent
commit
14ff561f6c
6 changed files with 93 additions and 44 deletions
  1. 3 1
      core/runtime/core.odin
  2. 25 4
      core/runtime/internal.odin
  3. 26 9
      core/strconv/strconv.odin
  4. 0 14
      examples/demo/demo.odin
  5. 2 1
      src/checker.cpp
  6. 37 15
      src/ir.cpp

+ 3 - 1
core/runtime/core.odin

@@ -403,7 +403,9 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
 @builtin
 ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
 	bounds_check_error_loc(loc, index, len(array));
-	copy(array[index:], array[index+1:]);
+	if index+1 < len(array) {
+		copy(array[index:], array[index+1:]);
+	}
 	pop(array);
 }
 

+ 25 - 4
core/runtime/internal.odin

@@ -285,8 +285,25 @@ bounds_check_error :: proc "contextless" (file: string, line, column: int, index
 	handle_error(file, line, column, index, count);
 }
 
-slice_expr_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
-	if 0 <= lo && lo <= hi && hi <= len do return;
+slice_expr_error_hi :: proc "contextless" (file: string, line, column: int, hi: int, len: int) {
+	if 0 <= hi && hi <= len do return;
+	handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
+		fd := os.stderr;
+		print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
+		os.write_string(fd, " Invalid slice indices: ");
+		print_i64(fd, i64(lo));
+		os.write_string(fd, ":");
+		print_i64(fd, i64(hi));
+		os.write_string(fd, ":");
+		print_i64(fd, i64(len));
+		os.write_byte(fd, '\n');
+		debug_trap();
+	}
+	handle_error(file, line, column, 0, hi, len);
+}
+
+slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
+	if 0 <= lo && lo < len && lo <= hi && hi <= len do return;
 	handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
 		fd := os.stderr;
 		print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
@@ -343,8 +360,12 @@ bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_locati
 	bounds_check_error(file_path, int(line), int(column), index, count);
 }
 
-slice_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
-	slice_expr_error(file_path, int(line), int(column), lo, hi, len);
+slice_expr_error_hi_loc :: inline proc "contextless" (using loc := #caller_location, hi: int, len: int) {
+	slice_expr_error_hi(file_path, int(line), int(column), hi, len);
+}
+
+slice_expr_error_lo_hi_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
+	slice_expr_error_lo_hi(file_path, int(line), int(column), lo, hi, len);
 }
 
 dynamic_array_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, low, high, max: int) {

+ 26 - 9
core/strconv/strconv.odin

@@ -211,10 +211,15 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str
 
 quote :: proc(buf: []byte, s: string) -> string {
 	write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
+		if i^ >= len(buf) do return;
 		n := copy(buf[i^:], bytes[:]);
 		i^ += n;
 	}
 
+	if buf == nil {
+		return "";
+	}
+
 	c :: '"';
 	i := 0;
 
@@ -230,8 +235,10 @@ quote :: proc(buf: []byte, s: string) -> string {
 			write_byte(buf, &i, digits[s[0]>>4]);
 			write_byte(buf, &i, digits[s[0]&0xf]);
 		}
-		s2 := quote_rune(buf[i:], r);
-		i += len(s2);
+		if i < len(buf) {
+			s2 := quote_rune(buf[i:], r);
+			i += len(s2);
+		}
 	}
 	write_byte(buf, &i, c);
 	return string(buf[:i]);
@@ -239,17 +246,27 @@ quote :: proc(buf: []byte, s: string) -> string {
 
 quote_rune :: proc(buf: []byte, r: rune) -> string {
 	write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
-		n := copy(buf[i^:], bytes[:]);
-		i^ += n;
+		if i^ < len(buf) {
+			n := copy(buf[i^:], bytes[:]);
+			i^ += n;
+		}
 	}
 	write_string :: inline proc(buf: []byte, i: ^int, s: string) {
-		n := copy(buf[i^:], cast([]byte)s);
-		i^ += n;
+		if i^ < len(buf) {
+			n := copy(buf[i^:], cast([]byte)s);
+			i^ += n;
+		}
 	}
 	write_rune :: inline proc(buf: []byte, i: ^int, r: rune) {
-		b, w := utf8.encode_rune(r);
-		n := copy(buf[i^:], b[:w]);
-		i^ += n;
+		if i^ < len(buf) {
+			b, w := utf8.encode_rune(r);
+			n := copy(buf[i^:], b[:w]);
+			i^ += n;
+		}
+	}
+
+	if buf == nil {
+		return "";
 	}
 
 	i := 0;

+ 0 - 14
examples/demo/demo.odin

@@ -561,20 +561,6 @@ threading_example :: proc() {
 	when os.OS == "windows" {
 		fmt.println("# threading_example");
 
-		unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
-			runtime.bounds_check_error_loc(loc, index, len(array));
-			n := len(array)-1;
-			if index != n {
-				array[index] = array[n];
-			}
-			pop(array);
-		}
-		ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_location) {
-			runtime.bounds_check_error_loc(loc, index, len(array));
-			copy(array[index:], array[index+1:]);
-			pop(array);
-		}
-
 		worker_proc :: proc(t: ^thread.Thread) -> int {
 			for iteration in 1..5 {
 				fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);

+ 2 - 1
src/checker.cpp

@@ -1606,7 +1606,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 	if (!build_context.no_bounds_check) {
 		String bounds_check_entities[] = {
 			str_lit("bounds_check_error"),
-			str_lit("slice_expr_error"),
+			str_lit("slice_expr_error_hi"),
+			str_lit("slice_expr_error_lo_hi"),
 			str_lit("dynamic_array_expr_error"),
 		};
 		for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) {

+ 37 - 15
src/ir.cpp

@@ -5352,7 +5352,7 @@ void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValu
 	ir_emit_runtime_call(proc, "bounds_check_error", args);
 }
 
-void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *len, bool is_substring) {
+void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *len, bool lower_value_used) {
 	if (build_context.no_bounds_check) {
 		return;
 	}
@@ -5364,18 +5364,31 @@ void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, ir
 	irValue *file = ir_find_or_add_entity_string(proc->module, token.pos.file);
 	irValue *line = ir_const_int(token.pos.line);
 	irValue *column = ir_const_int(token.pos.column);
-	low  = ir_emit_conv(proc, low,  t_int);
 	high = ir_emit_conv(proc, high, t_int);
 
-	auto args = array_make<irValue *>(ir_allocator(), 6);
-	args[0] = file;
-	args[1] = line;
-	args[2] = column;
-	args[3] = low;
-	args[4] = high;
-	args[5] = len;
+	if (!lower_value_used) {
+		auto args = array_make<irValue *>(ir_allocator(), 5);
+		args[0] = file;
+		args[1] = line;
+		args[2] = column;
+		args[3] = high;
+		args[4] = len;
+
+		ir_emit_runtime_call(proc, "slice_expr_error_hi", args);
+	} else {
+		// No need to convert unless used
+		low  = ir_emit_conv(proc, low, t_int);
 
-	ir_emit_runtime_call(proc, "slice_expr_error", args);
+		auto args = array_make<irValue *>(ir_allocator(), 6);
+		args[0] = file;
+		args[1] = line;
+		args[2] = column;
+		args[3] = low;
+		args[4] = high;
+		args[5] = len;
+
+		ir_emit_runtime_call(proc, "slice_expr_error_lo_hi", args);
+	}
 }
 
 void ir_emit_dynamic_array_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *max) {
@@ -7169,6 +7182,8 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 		if (se->low  != nullptr) low  = ir_build_expr(proc, se->low);
 		if (se->high != nullptr) high = ir_build_expr(proc, se->high);
 
+		bool no_indices = se->low == nullptr && se->high == nullptr;
+
 		irValue *addr = ir_build_addr_ptr(proc, se->expr);
 		irValue *base = ir_emit_load(proc, addr);
 		Type *type = base_type(ir_type(base));
@@ -7186,7 +7201,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			irValue *len = ir_slice_len(proc, base);
 			if (high == nullptr) high = len;
 
-			ir_emit_slice_bounds_check(proc, se->open, low, high, len, false);
+			if (!no_indices) {
+				ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
+			}
 
 			irValue *elem   = ir_emit_ptr_offset(proc, ir_slice_elem(proc, base), low);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -7203,7 +7220,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			irValue *len = ir_dynamic_array_len(proc, base);
 			if (high == nullptr) high = len;
 
-			ir_emit_slice_bounds_check(proc, se->open, low, high, len, false);
+			if (!no_indices) {
+				ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
+			}
 
 			irValue *elem    = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -7224,7 +7243,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant;
 
 			if (!low_const || !high_const) {
-				ir_emit_slice_bounds_check(proc, se->open, low, high, len, false);
+				if (!no_indices) {
+					ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
+				}
 			}
 			irValue *elem    = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
@@ -7238,9 +7259,10 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			GB_ASSERT(type == t_string);
 			irValue *len = ir_string_len(proc, base);
 			if (high == nullptr) high = len;
-			// if (max == nullptr)  max = ir_string_len(proc, base);
 
-			ir_emit_slice_bounds_check(proc, se->open, low, high, len, true);
+			if (!no_indices) {
+				ir_emit_slice_bounds_check(proc, se->open, low, high, len, se->low != nullptr);
+			}
 
 			irValue *elem    = ir_emit_ptr_offset(proc, ir_string_elem(proc, base), low);
 			irValue *new_len = ir_emit_arith(proc, Token_Sub, high, low, t_int);