Browse Source

Add error block around `error_line` calls

gingerBill 1 year ago
parent
commit
517d7ae0b0
6 changed files with 28 additions and 4 deletions
  1. 3 0
      src/check_builtin.cpp
  2. 1 0
      src/check_decl.cpp
  3. 5 0
      src/check_expr.cpp
  4. 5 0
      src/check_stmt.cpp
  5. 11 1
      src/checker.cpp
  6. 3 3
      src/parser.cpp

+ 3 - 0
src/check_builtin.cpp

@@ -89,6 +89,7 @@ gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String
 
 
 
 
 gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
 gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
+	ERROR_BLOCK();
 	gbString t = type_to_string(x.type);
 	gbString t = type_to_string(x.type);
 	error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
 	error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
 	if (is_type_union(type_deref(x.type))) {
 	if (is_type_union(type_deref(x.type))) {
@@ -1565,6 +1566,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
 		}
 		}
 
 
 		if (!operand->value.value_bool) {
 		if (!operand->value.value_bool) {
+			ERROR_BLOCK();
 			gbString arg1 = expr_to_string(ce->args[0]);
 			gbString arg1 = expr_to_string(ce->args[0]);
 			gbString arg2 = {};
 			gbString arg2 = {};
 
 
@@ -1590,6 +1592,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
 		operand->type = t_untyped_bool;
 		operand->type = t_untyped_bool;
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 	} else if (name == "panic") {
 	} else if (name == "panic") {
+		ERROR_BLOCK();
 		if (ce->args.count != 1) {
 		if (ce->args.count != 1) {
 			error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
 			error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
 			return false;
 			return false;

+ 1 - 0
src/check_decl.cpp

@@ -1630,6 +1630,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
 		Entity *uvar = entry.uvar;
 		Entity *uvar = entry.uvar;
 		Entity *prev = scope_insert_no_mutex(ctx->scope, uvar);
 		Entity *prev = scope_insert_no_mutex(ctx->scope, uvar);
 		if (prev != nullptr) {
 		if (prev != nullptr) {
+			ERROR_BLOCK();
 			error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
 			error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
 			error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string));
 			error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string));
 			break;
 			break;

+ 5 - 0
src/check_expr.cpp

@@ -5905,6 +5905,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 				s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
 				s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
 			} else {
 			} else {
 				if (show_error) {
 				if (show_error) {
+					ERROR_BLOCK();
 					check_assignment(c, o, param_type, str_lit("procedure argument"));
 					check_assignment(c, o, param_type, str_lit("procedure argument"));
 
 
 					Type *src = base_type(o->type);
 					Type *src = base_type(o->type);
@@ -8459,6 +8460,7 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
 				// NOTE(bill): allow implicit conversion between boolean types
 				// NOTE(bill): allow implicit conversion between boolean types
 				// within 'or_return' to improve the experience using third-party code
 				// within 'or_return' to improve the experience using third-party code
 			} else if (!check_is_assignable_to(c, &rhs, end_type)) {
 			} else if (!check_is_assignable_to(c, &rhs, end_type)) {
+				ERROR_BLOCK();
 				// TODO(bill): better error message
 				// TODO(bill): better error message
 				gbString a = type_to_string(right_type);
 				gbString a = type_to_string(right_type);
 				gbString b = type_to_string(end_type);
 				gbString b = type_to_string(end_type);
@@ -10030,6 +10032,7 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
 	bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint);
 	bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint);
 	if (is_const) {
 	if (is_const) {
 		if (index < 0) {
 		if (index < 0) {
+			ERROR_BLOCK();
 			gbString str = expr_to_string(o->expr);
 			gbString str = expr_to_string(o->expr);
 			error(o->expr, "Cannot index a constant '%s'", str);
 			error(o->expr, "Cannot index a constant '%s'", str);
 			if (!build_context.terse_errors) {
 			if (!build_context.terse_errors) {
@@ -10046,6 +10049,7 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
 			bool finish = false;
 			bool finish = false;
 			o->value = get_constant_field_single(c, value, cast(i32)index, &success, &finish);
 			o->value = get_constant_field_single(c, value, cast(i32)index, &success, &finish);
 			if (!success) {
 			if (!success) {
+				ERROR_BLOCK();
 				gbString str = expr_to_string(o->expr);
 				gbString str = expr_to_string(o->expr);
 				error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
 				error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
 				if (!build_context.terse_errors) {
 				if (!build_context.terse_errors) {
@@ -10236,6 +10240,7 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
 			}
 			}
 		}
 		}
 		if (!all_constant) {
 		if (!all_constant) {
+			ERROR_BLOCK();
 			gbString str = expr_to_string(o->expr);
 			gbString str = expr_to_string(o->expr);
 			error(o->expr, "Cannot slice '%s' with non-constant indices", str);
 			error(o->expr, "Cannot slice '%s' with non-constant indices", str);
 			if (!build_context.terse_errors) {
 			if (!build_context.terse_errors) {

+ 5 - 0
src/check_stmt.cpp

@@ -883,6 +883,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod
 		}
 		}
 
 
 		if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
 		if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
+			ERROR_BLOCK();
 			if (prev_inline_for_depth > 0) {
 			if (prev_inline_for_depth > 0) {
 				error(node, "Nested '#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
 				error(node, "Nested '#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
 			} else {
 			} else {
@@ -1592,6 +1593,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
 				{
 				{
 					isize count = t->Tuple.variables.count;
 					isize count = t->Tuple.variables.count;
 					if (count < 1 || count > 3) {
 					if (count < 1 || count > 3) {
+						ERROR_BLOCK();
 						check_not_tuple(ctx, &operand);
 						check_not_tuple(ctx, &operand);
 						error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
 						error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
 						break;
 						break;
@@ -2085,6 +2087,9 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) {
 		}
 		}
 		return;
 		return;
 	}
 	}
+
+	ERROR_BLOCK();
+
 	gbString expr_str = expr_to_string(operand.expr);
 	gbString expr_str = expr_to_string(operand.expr);
 	error(node, "Expression is not used: '%s'", expr_str);
 	error(node, "Expression is not used: '%s'", expr_str);
 	gb_string_free(expr_str);
 	gb_string_free(expr_str);

+ 11 - 1
src/checker.cpp

@@ -3180,6 +3180,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 		    linkage == "link_once") {
 		    linkage == "link_once") {
 			ac->linkage = linkage;
 			ac->linkage = linkage;
 		} else {
 		} else {
+			ERROR_BLOCK();
 			error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage));
 			error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage));
 			error_line("\tinternal\n");
 			error_line("\tinternal\n");
 			error_line("\tstrong\n");
 			error_line("\tstrong\n");
@@ -3428,6 +3429,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 			} else if (mode == "speed") {
 			} else if (mode == "speed") {
 				ac->optimization_mode = ProcedureOptimizationMode_Speed;
 				ac->optimization_mode = ProcedureOptimizationMode_Speed;
 			} else {
 			} else {
+				ERROR_BLOCK();
 				error(elem, "Invalid optimization_mode for '%.*s'. Valid modes:", LIT(name));
 				error(elem, "Invalid optimization_mode for '%.*s'. Valid modes:", LIT(name));
 				error_line("\tnone\n");
 				error_line("\tnone\n");
 				error_line("\tminimal\n");
 				error_line("\tminimal\n");
@@ -3558,6 +3560,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
 			    model == "localexec") {
 			    model == "localexec") {
 				ac->thread_local_model = model;
 				ac->thread_local_model = model;
 			} else {
 			} else {
+				ERROR_BLOCK();
 				error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
 				error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
 				error_line("\tdefault\n");
 				error_line("\tdefault\n");
 				error_line("\tlocaldynamic\n");
 				error_line("\tlocaldynamic\n");
@@ -3608,6 +3611,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
 		    linkage == "link_once") {
 		    linkage == "link_once") {
 			ac->linkage = linkage;
 			ac->linkage = linkage;
 		} else {
 		} else {
+			ERROR_BLOCK();
 			error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage));
 			error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage));
 			error_line("\tinternal\n");
 			error_line("\tinternal\n");
 			error_line("\tstrong\n");
 			error_line("\tstrong\n");
@@ -3762,6 +3766,7 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
 
 
 			if (!proc(c, elem, name, value, ac)) {
 			if (!proc(c, elem, name, value, ac)) {
 				if (!build_context.ignore_unknown_attributes) {
 				if (!build_context.ignore_unknown_attributes) {
+					ERROR_BLOCK();
 					error(elem, "Unknown attribute element name '%.*s'", LIT(name));
 					error(elem, "Unknown attribute element name '%.*s'", LIT(name));
 					error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n");
 					error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n");
 				}
 				}
@@ -3831,6 +3836,8 @@ gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_
 			gb_string_free(str);
 			gb_string_free(str);
 			return false;
 			return false;
 		} else if (is_global) {
 		} else if (is_global) {
+			ERROR_BLOCK();
+
 			Ast *n = vd->values[rhs-1];
 			Ast *n = vd->values[rhs-1];
 			error(n, "Expected %td expressions on the right hand side, got %td", lhs, rhs);
 			error(n, "Expected %td expressions on the right hand side, got %td", lhs, rhs);
 			error_line("Note: Global declarations do not allow for multi-valued expressions");
 			error_line("Note: Global declarations do not allow for multi-valued expressions");
@@ -6052,11 +6059,14 @@ gb_internal void check_unique_package_names(Checker *c) {
 			continue;
 			continue;
 		}
 		}
 
 
+
+		begin_error_block();
 		error(curr, "Duplicate declaration of 'package %.*s'", LIT(name));
 		error(curr, "Duplicate declaration of 'package %.*s'", LIT(name));
 		error_line("\tA package name must be unique\n"
 		error_line("\tA package name must be unique\n"
 		           "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
 		           "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
 		           "\tA package name is required for link name prefixing to have a consistent ABI\n");
 		           "\tA package name is required for link name prefixing to have a consistent ABI\n");
-		error(prev, "found at previous location");
+		error_line("%s found at previous location\n", token_pos_to_string(ast_token(prev).pos));
+		end_error_block();
 	}
 	}
 }
 }
 
 

+ 3 - 3
src/parser.cpp

@@ -6295,7 +6295,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
 	if (!path_is_directory(init_fullpath)) {
 	if (!path_is_directory(init_fullpath)) {
 		String const ext = str_lit(".odin");
 		String const ext = str_lit(".odin");
 		if (!string_ends_with(init_fullpath, ext)) {
 		if (!string_ends_with(init_fullpath, ext)) {
-			error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
+			error({}, "Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
 			return ParseFile_WrongExtension;
 			return ParseFile_WrongExtension;
 		}
 		}
 	} else if (init_fullpath.len != 0) {
 	} else if (init_fullpath.len != 0) {
@@ -6308,7 +6308,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
 			String short_path = filename_from_path(path);
 			String short_path = filename_from_path(path);
 			char *cpath = alloc_cstring(temporary_allocator(), short_path);
 			char *cpath = alloc_cstring(temporary_allocator(), short_path);
 			if (gb_file_exists(cpath)) {
 			if (gb_file_exists(cpath)) {
-			    	error_line("Please specify the executable name with -out:<string> as a directory exists with the same name in the current working directory");
+			    	error({}, "Please specify the executable name with -out:<string> as a directory exists with the same name in the current working directory");
 			    	return ParseFile_DirectoryAlreadyExists;
 			    	return ParseFile_DirectoryAlreadyExists;
 			}
 			}
 		}
 		}
@@ -6344,7 +6344,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
 			if (!path_is_directory(fullpath)) {
 			if (!path_is_directory(fullpath)) {
 				String const ext = str_lit(".odin");
 				String const ext = str_lit(".odin");
 				if (!string_ends_with(fullpath, ext)) {
 				if (!string_ends_with(fullpath, ext)) {
-					error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(fullpath));
+					error({}, "Expected either a directory or a .odin file, got '%.*s'\n", LIT(fullpath));
 					return ParseFile_WrongExtension;
 					return ParseFile_WrongExtension;
 				}
 				}
 			}
 			}