aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorColin Davidson <colrdavidson@gmail.com>2025-07-07 14:34:05 -0700
committerColin Davidson <colrdavidson@gmail.com>2025-07-07 14:34:05 -0700
commit389439ccb9e60014fa9d7dd26220da8b7b68f763 (patch)
tree5f2afed73a1baa177a3edd4de23aaedaa7efaff5 /src
parent04481e0fd289f854e35a84da909184140940bbf7 (diff)
parent86d576f7cc1ceeb7472c18e08e3c74214f26ddc6 (diff)
Merge branch 'master' into macharena
Diffstat (limited to 'src')
-rw-r--r--src/bug_report.cpp1
-rw-r--r--src/build_settings.cpp9
-rw-r--r--src/check_builtin.cpp5
-rw-r--r--src/check_decl.cpp8
-rw-r--r--src/check_expr.cpp307
-rw-r--r--src/check_stmt.cpp21
-rw-r--r--src/check_type.cpp2
-rw-r--r--src/checker.cpp6
-rw-r--r--src/checker.hpp1
-rw-r--r--src/entity.cpp1
-rw-r--r--src/error.cpp2
-rw-r--r--src/gb/gb.h6
-rw-r--r--src/linker.cpp7
-rw-r--r--src/llvm_abi.cpp70
-rw-r--r--src/llvm_backend_const.cpp20
-rw-r--r--src/llvm_backend_general.cpp16
-rw-r--r--src/llvm_backend_proc.cpp42
-rw-r--r--src/main.cpp36
-rw-r--r--src/types.cpp146
19 files changed, 499 insertions, 207 deletions
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index 32210c23e..98a376895 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -540,6 +540,7 @@ gb_internal void report_os_info() {
}
switch (major) {
+ case 26: gb_printf("macOS Tahoe"); break;
case 15: gb_printf("macOS Sequoia"); break;
case 14: gb_printf("macOS Sonoma"); break;
case 13: gb_printf("macOS Ventura"); break;
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 05709902a..ebe57bf1e 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -385,6 +385,13 @@ enum LinkerChoice : i32 {
Linker_COUNT,
};
+enum SourceCodeLocationInfo : u8 {
+ SourceCodeLocationInfo_Normal = 0,
+ SourceCodeLocationInfo_Obfuscated = 1,
+ SourceCodeLocationInfo_Filename = 2,
+ SourceCodeLocationInfo_None = 3,
+};
+
String linker_choices[Linker_COUNT] = {
str_lit("default"),
str_lit("lld"),
@@ -512,7 +519,7 @@ struct BuildContext {
bool dynamic_map_calls;
- bool obfuscate_source_code_locations;
+ SourceCodeLocationInfo source_code_location_info;
bool min_link_libs;
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index bd265affc..9f9787b61 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -148,6 +148,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) {
if (return_type == nullptr) {
return false;
}
+
+ if (build_context.metrics.os != TargetOs_darwin) {
+ return false;
+ }
+
if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) {
i64 struct_limit = type_size_of(t_uintptr) << 1;
return type_size_of(return_type) > struct_limit;
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index d53c3c6b7..3d0d95556 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -1334,12 +1334,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
has_instrumentation = false;
e->flags |= EntityFlag_Require;
} else if (ac.instrumentation_enter) {
+ init_core_source_code_location(ctx->checker);
if (!is_valid_instrumentation_call(e->type)) {
init_core_source_code_location(ctx->checker);
gbString s = type_to_string(e->type);
error(e->token, "@(instrumentation_enter) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
gb_string_free(s);
}
+ if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
+ error(e->token, "@(instrumentation_enter) procedures must be declared at the file scope");
+ }
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
if (ctx->info->instrumentation_enter_entity != nullptr) {
error(e->token, "@(instrumentation_enter) has already been set");
@@ -1356,6 +1360,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
error(e->token, "@(instrumentation_exit) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
gb_string_free(s);
}
+ if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
+ error(e->token, "@(instrumentation_exit) procedures must be declared at the file scope");
+ }
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
if (ctx->info->instrumentation_exit_entity != nullptr) {
error(e->token, "@(instrumentation_exit) has already been set");
@@ -1370,6 +1377,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.has_instrumentation = has_instrumentation;
e->Procedure.no_sanitize_address = ac.no_sanitize_address;
+ e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
e->deprecated_message = ac.deprecated_message;
e->warning_message = ac.warning_message;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 9308eab8e..aa9c8837d 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -2424,27 +2424,27 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o
Type *s = src->Array.elem;
Type *d = dst->Slice.elem;
if (are_types_identical(s, d)) {
- error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
+ error_line("\tSuggestion: The array expression may be sliced with %s[:]\n", a);
}
} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
Type *s = src->DynamicArray.elem;
Type *d = dst->Slice.elem;
if (are_types_identical(s, d)) {
- error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
+ error_line("\tSuggestion: The dynamic array expression may be sliced with %s[:]\n", a);
}
}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
- error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
+ error_line("\tSuggestion: The expression may be directly casted to type %s\n", b);
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
- error_line("\tSuggestion: a string may be transmuted to %s\n", b);
- error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n");
+ error_line("\tSuggestion: A string may be transmuted to %s\n", b);
+ error_line("\t This is an UNSAFE operation as string data is assumed to be immutable,\n");
error_line("\t whereas slices in general are assumed to be mutable.\n");
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) {
- error_line("\tSuggestion: the expression may be casted to %s\n", b);
+ error_line("\tSuggestion: The expression may be casted to %s\n", b);
} else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) {
return;
} else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) {
gbString s = expr_to_string(c->type_hint_expr);
- error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s);
+ error_line("\tSuggestion: Make sure that `%s` is attached to the compound literal directly\n", s);
gb_string_free(s);
} else if (is_type_pointer(type) &&
o->mode == Addressing_Variable &&
@@ -3086,126 +3086,106 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
GB_ASSERT(node->kind == Ast_BinaryExpr);
ast_node(be, BinaryExpr, node);
- ExactValue x_val = {};
- if (x->mode == Addressing_Constant) {
- x_val = exact_value_to_integer(x->value);
+ bool y_is_untyped = is_type_untyped(y->type);
+ if (y_is_untyped) {
+ convert_to_typed(c, y, t_untyped_integer);
+ if (y->mode == Addressing_Invalid) {
+ x->mode = Addressing_Invalid;
+ return;
+ }
+ } else if (!is_type_unsigned(y->type)) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' must be an unsigned integer", y_str);
+ gb_string_free(y_str);
+ x->mode = Addressing_Invalid;
+ return;
}
bool x_is_untyped = is_type_untyped(x->type);
- if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) {
- gbString err_str = expr_to_string(x->expr);
- error(node, "Shifted operand '%s' must be an integer", err_str);
- gb_string_free(err_str);
+ if (!(x_is_untyped || is_type_integer(x->type))) {
+ gbString x_str = expr_to_string(x->expr);
+ error(x->expr, "Shifted operand '%s' must be an integer", x_str);
+ gb_string_free(x_str);
x->mode = Addressing_Invalid;
return;
}
- if (is_type_unsigned(y->type)) {
-
- } else if (is_type_untyped(y->type)) {
- convert_to_typed(c, y, t_untyped_integer);
- if (y->mode == Addressing_Invalid) {
+ if (y->mode == Addressing_Constant) {
+ if (big_int_is_neg(&y->value.value_integer)) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' cannot be negative", y_str);
+ gb_string_free(y_str);
x->mode = Addressing_Invalid;
return;
}
- } else {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount '%s' must be an unsigned integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ BigInt max_shift = {};
+ big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
- if (x->mode == Addressing_Constant) {
- if (y->mode == Addressing_Constant) {
- ExactValue y_val = exact_value_to_integer(y->value);
- if (y_val.kind != ExactValue_Integer) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount '%s' must be an unsigned integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ if (big_int_cmp(&y->value.value_integer, &max_shift) > 0) {
+ gbString y_str = expr_to_string(y->expr);
+ error(y->expr, "Shift amount '%s' must be <= %u", y_str, MAX_BIG_INT_SHIFT);
+ gb_string_free(y_str);
+ x->mode = Addressing_Invalid;
+ return;
+ }
- BigInt max_shift = {};
- big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
+ if (x->mode == Addressing_Constant) {
+ if (x_is_untyped) {
+ convert_to_typed(c, x, t_untyped_integer);
+ if (x->mode == Addressing_Invalid) {
+ return;
+ }
- if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount too large: '%s'", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
+ x->expr = node;
+ x->value = exact_value_shift(be->op.kind, exact_value_to_integer(x->value), exact_value_to_integer(y->value));
- if (!is_type_integer(x->type)) {
- // NOTE(bill): It could be an untyped float but still representable
- // as an integer
- x->type = t_untyped_integer;
+ return;
}
x->expr = node;
- x->value = exact_value_shift(be->op.kind, x_val, y_val);
+ x->value = exact_value_shift(be->op.kind, x->value, y->value);
+ check_is_expressible(c, x, x->type);
- if (is_type_typed(x->type)) {
- check_is_expressible(c, x, x->type);
- }
return;
}
- TokenPos pos = ast_token(x->expr).pos;
+ if (y_is_untyped) {
+ convert_to_typed(c, y, t_uint);
+ }
+
+ return;
+ }
+
+ if (x->mode == Addressing_Constant) {
if (x_is_untyped) {
- if (x->expr != nullptr) {
- x->expr->tav.is_lhs = true;
- }
- x->mode = Addressing_Value;
if (type_hint) {
if (is_type_integer(type_hint)) {
convert_to_typed(c, x, type_hint);
+ } else if (is_type_any(type_hint)) {
+ convert_to_typed(c, x, default_type(t_untyped_integer));
} else {
gbString x_str = expr_to_string(x->expr);
- gbString to_type = type_to_string(type_hint);
- error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type);
+ gbString type_str = type_to_string(type_hint);
+ error(x->expr, "Shifted operand '%s' cannot convert to non-integer type '%s'", x_str, type_str);
gb_string_free(x_str);
- gb_string_free(to_type);
+ gb_string_free(type_str);
x->mode = Addressing_Invalid;
+ return;
}
- } else if (!is_type_integer(x->type)) {
- gbString x_str = expr_to_string(x->expr);
- error(node, "Non-integer shifted operand '%s' is not allowed", x_str);
- gb_string_free(x_str);
- x->mode = Addressing_Invalid;
+ } else {
+ check_is_expressible(c, x, default_type(t_untyped_integer));
+ }
+ if (x->mode == Addressing_Invalid) {
+ return;
}
- // x->value = x_val;
- return;
}
- }
- if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) {
- gbString err_str = expr_to_string(y->expr);
- error(node, "Shift amount cannot be negative: '%s'", err_str);
- gb_string_free(err_str);
- }
-
- if (!is_type_integer(x->type)) {
- gbString err_str = expr_to_string(x->expr);
- error(node, "Shift operand '%s' must be an integer", err_str);
- gb_string_free(err_str);
- x->mode = Addressing_Invalid;
- return;
- }
-
- if (is_type_untyped(y->type)) {
- convert_to_typed(c, y, t_uint);
+ x->mode = Addressing_Value;
}
-
- x->mode = Addressing_Value;
}
-
-
gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (check_is_assignable_to(c, operand, y)) {
return true;
@@ -5884,12 +5864,12 @@ typedef u32 UnpackFlags;
enum UnpackFlag : u32 {
UnpackFlag_None = 0,
UnpackFlag_AllowOk = 1<<0,
- UnpackFlag_IsVariadic = 1<<1,
- UnpackFlag_AllowUndef = 1<<2,
+ UnpackFlag_AllowUndef = 1<<1,
};
-gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) {
+gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags,
+ isize variadic_index = -1) {
auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize {
if (lhs == nullptr || c->decl == nullptr) {
return tuple_count;
@@ -5914,11 +5894,14 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
return tuple_count;
};
-
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
- bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
+ bool is_variadic = variadic_index > -1;
+ if (!is_variadic) {
+ variadic_index = lhs_count;
+ }
+
bool optional_ok = false;
isize tuple_index = 0;
for (Ast *rhs : rhs_arguments) {
@@ -5934,26 +5917,18 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
Type *type_hint = nullptr;
-
- if (lhs != nullptr && tuple_index < lhs_count) {
- // NOTE(bill): override DeclInfo for dependency
- Entity *e = lhs[tuple_index];
- if (e != nullptr) {
- type_hint = e->type;
- if (e->flags & EntityFlag_Ellipsis) {
- GB_ASSERT(is_type_slice(e->type));
- GB_ASSERT(e->type->kind == Type_Slice);
- type_hint = e->type->Slice.elem;
+ if (lhs != nullptr) {
+ if (tuple_index < variadic_index) {
+ // NOTE(bill): override DeclInfo for dependency
+ Entity *e = lhs[tuple_index];
+ if (e != nullptr) {
+ type_hint = e->type;
}
- }
- } else if (lhs != nullptr && tuple_index >= lhs_count && is_variadic) {
- // NOTE(bill): override DeclInfo for dependency
- Entity *e = lhs[lhs_count-1];
- if (e != nullptr) {
- type_hint = e->type;
- if (e->flags & EntityFlag_Ellipsis) {
+ } else if (is_variadic) {
+ Entity *e = lhs[variadic_index];
+ if (e != nullptr) {
+ GB_ASSERT(e->flags & EntityFlag_Ellipsis);
GB_ASSERT(is_type_slice(e->type));
- GB_ASSERT(e->type->kind == Type_Slice);
type_hint = e->type->Slice.elem;
}
}
@@ -6493,17 +6468,16 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) {
return ce->args[0]->kind == Ast_FieldValue;
}
-gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) {
+gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_) {
Entity **lhs = nullptr;
isize lhs_count = -1;
- if (proc_type == nullptr) {
+ if (proc_type == nullptr || proc_type == t_invalid) {
return nullptr;
}
GB_ASSERT(is_type_proc(proc_type));
TypeProc *pt = &base_type(proc_type)->Proc;
- *is_variadic = pt->variadic;
if (!pt->is_polymorphic || pt->is_poly_specialized) {
if (pt->params != nullptr) {
@@ -6697,6 +6671,9 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera
GB_ASSERT(proc_type != nullptr);
proc_type = base_type(proc_type);
+ if (proc_type == t_invalid) {
+ return false;
+ }
GB_ASSERT(proc_type->kind == Type_Proc);
CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data);
@@ -6830,7 +6807,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
Entity **lhs = nullptr;
isize lhs_count = -1;
- bool is_variadic = false;
+ i32 variadic_index = -1;
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
@@ -6839,9 +6816,14 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
if (procs.count == 1) {
Entity *e = procs[0];
-
- lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ Type *pt = base_type(e->type);
+ if (pt != nullptr && is_type_proc(pt)) {
+ lhs = populate_proc_parameter_list(c, pt, &lhs_count);
+ if (pt->Proc.variadic) {
+ variadic_index = pt->Proc.variadic_index;
+ }
+ }
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
if (check_named_arguments(c, e->type, named_args, &named_operands, true)) {
check_call_arguments_single(c, call, operand,
@@ -6901,11 +6883,30 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
}
lhs[param_index] = e;
}
+
+ for (Entity *p : procs) {
+ Type *pt = base_type(p->type);
+ if (!(pt != nullptr && is_type_proc(pt))) {
+ continue;
+ }
+
+ if (pt->Proc.is_polymorphic) {
+ if (variadic_index == -1) {
+ variadic_index = pt->Proc.variadic_index;
+ } else if (variadic_index != pt->Proc.variadic_index) {
+ variadic_index = -1;
+ break;
+ }
+ } else {
+ variadic_index = -1;
+ break;
+ }
+ }
}
}
}
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
for_array(i, named_args) {
Ast *arg = named_args[i];
@@ -7343,13 +7344,16 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
defer (array_free(&named_operands));
if (positional_args.count > 0) {
- isize lhs_count = -1;
- bool is_variadic = false;
Entity **lhs = nullptr;
+ isize lhs_count = -1;
+ i32 variadic_index = -1;
if (pt != nullptr) {
- lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
+ lhs = populate_proc_parameter_list(c, proc_type, &lhs_count);
+ if (pt->variadic) {
+ variadic_index = pt->variadic_index;
+ }
}
- check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
+ check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
}
if (named_args.count > 0) {
@@ -8756,23 +8760,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
String name = bd->name.string;
if (name == "file") {
String file = get_file_path_string(bd->token.pos.file_id);
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
file = obfuscate_string(file, "F");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(file);
} else if (name == "directory") {
String file = get_file_path_string(bd->token.pos.file_id);
String path = dir_from_path(file);
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
path = obfuscate_string(path, "D");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ path = last_path_element(path);
+ break;
+ case SourceCodeLocationInfo_None:
+ path = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(path);
} else if (name == "line") {
i32 line = bd->token.pos.line;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
line = obfuscate_i32(line);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ break;
+ case SourceCodeLocationInfo_None:
+ line = 0;
+ break;
}
o->type = t_untyped_integer;
o->value = exact_value_i64(line);
@@ -8783,8 +8816,17 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
o->value = exact_value_string(str_lit(""));
} else {
String p = c->proc_name;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
p = obfuscate_string(p, "P");
+ break;
+ case SourceCodeLocationInfo_Filename:
+ break;
+ case SourceCodeLocationInfo_None:
+ p = str_lit("");
+ break;
}
o->type = t_untyped_string;
o->value = exact_value_string(p);
@@ -11087,7 +11129,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
case_ast_node(u, Uninit, node);
o->mode = Addressing_Value;
o->type = t_untyped_uninit;
- error(node, "Use of --- outside of variable declaration");
+ error(node, "Global variables will always be zeroed if left unassigned, --- is disallowed");
case_end;
@@ -11322,6 +11364,13 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
o->mode = Addressing_Invalid;
o->expr = node;
return kind;
+ } else if (o->mode == Addressing_Type) {
+ gbString str = expr_to_string(o->expr);
+ error(o->expr, "Cannot dereference '%s' because it is a type", str);
+
+ o->mode = Addressing_Invalid;
+ o->expr = node;
+ return kind;
} else {
Type *t = base_type(o->type);
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index d92edf41d..07801b477 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -418,7 +418,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
-gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
+gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs, String context_name) {
if (rhs->mode == Addressing_Invalid) {
return nullptr;
}
@@ -430,7 +430,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
Ast *node = unparen_expr(lhs->expr);
- check_no_copy_assignment(*rhs, str_lit("assignment"));
+ check_no_copy_assignment(*rhs, context_name);
// NOTE(bill): Ignore assignments to '_'
if (is_blank_ident(node)) {
@@ -630,7 +630,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size;
}
- check_assignment(ctx, rhs, assignment_type, str_lit("assignment"));
+ check_assignment(ctx, rhs, assignment_type, context_name);
ctx->bit_field_bit_size = prev_bit_field_bit_size;
@@ -2418,7 +2418,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
isize lhs_count = as->lhs.count;
if (lhs_count == 0) {
- error(as->op, "Missing lhs in assignment statement");
+ error(as->op, "Missing LHS in assignment statement");
return;
}
@@ -2451,7 +2451,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
if (lhs_to_ignore[i]) {
continue;
}
- check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]);
+ check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i], str_lit("assignment"));
}
if (lhs_count != rhs_count) {
error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
@@ -2461,11 +2461,11 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
// a += 1; // Single-sided
Token op = as->op;
if (as->lhs.count != 1 || as->rhs.count != 1) {
- error(op, "Assignment operation '%.*s' requires single-valued expressions", LIT(op.string));
+ error(op, "Assignment operator '%.*s' requires single-valued operands", LIT(op.string));
return;
}
if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) {
- error(op, "Unknown Assignment operation '%.*s'", LIT(op.string));
+ error(op, "Unknown assignment operator '%.*s'", LIT(op.string));
return;
}
Operand lhs = {Addressing_Invalid};
@@ -2474,15 +2474,16 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
ast_node(be, BinaryExpr, binary_expr);
be->op = op;
be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add));
- // NOTE(bill): Only use the first one will be used
+ // NOTE(bill): Only use the first one will be used
be->left = as->lhs[0];
be->right = as->rhs[0];
check_expr(ctx, &lhs, as->lhs[0]);
check_binary_expr(ctx, &rhs, binary_expr, nullptr, true);
if (rhs.mode != Addressing_Invalid) {
- // NOTE(bill): Only use the first one will be used
- check_assignment_variable(ctx, &lhs, &rhs);
+ be->op.string = substring(be->op.string, 0, be->op.string.len - 1);
+ rhs.expr = binary_expr;
+ check_assignment_variable(ctx, &lhs, &rhs, str_lit("assignment operation"));
}
}
}
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 450b5e100..5f9540ee0 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -3284,7 +3284,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
}
if (count < 0) {
- error(at->count, "? can only be used in conjuction with compound literals");
+ error(at->count, "? can only be used in conjunction with compound literals");
count = 0;
}
diff --git a/src/checker.cpp b/src/checker.cpp
index 67dee9963..4ebabe004 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -3776,6 +3776,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
ac->no_sanitize_address = true;
return true;
+ } else if (name == "no_sanitize_memory") {
+ if (value != nullptr) {
+ error(value, "'%.*s' expects no parameter", LIT(name));
+ }
+ ac->no_sanitize_memory = true;
+ return true;
}
return false;
}
diff --git a/src/checker.hpp b/src/checker.hpp
index 0cdfd69ab..dabb7330a 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -140,6 +140,7 @@ struct AttributeContext {
bool instrumentation_enter : 1;
bool instrumentation_exit : 1;
bool no_sanitize_address : 1;
+ bool no_sanitize_memory : 1;
bool rodata : 1;
bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode
diff --git a/src/entity.cpp b/src/entity.cpp
index a16779419..6c0aa6ace 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -263,6 +263,7 @@ struct Entity {
bool uses_branch_location : 1;
bool is_anonymous : 1;
bool no_sanitize_address : 1;
+ bool no_sanitize_memory : 1;
} Procedure;
struct {
Array<Entity *> entities;
diff --git a/src/error.cpp b/src/error.cpp
index 1492b00c7..006d5ae8d 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -823,7 +823,7 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
gb_global String error_article_table[][2] = {
{str_lit("a "), str_lit("bit_set literal")},
{str_lit("a "), str_lit("constant declaration")},
- {str_lit("a "), str_lit("dynamiic array literal")},
+ {str_lit("a "), str_lit("dynamic array literal")},
{str_lit("a "), str_lit("map index")},
{str_lit("a "), str_lit("map literal")},
{str_lit("a "), str_lit("matrix literal")},
diff --git a/src/gb/gb.h b/src/gb/gb.h
index a1b659637..6ce8626c0 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -497,7 +497,11 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
#if !defined(gb_no_asan)
#if defined(_MSC_VER)
- #define gb_no_asan __declspec(no_sanitize_address)
+ #if _MSC_VER >= 1930
+ #define gb_no_asan __declspec(no_sanitize_address)
+ #else
+ #define gb_no_asan
+ #endif
#else
#define gb_no_asan __attribute__((disable_sanitizer_instrumentation))
#endif
diff --git a/src/linker.cpp b/src/linker.cpp
index 2210c1306..bf2ba6fe0 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -277,6 +277,9 @@ try_cross_linking:;
if (build_context.build_mode == BuildMode_DynamicLibrary) {
link_settings = gb_string_append_fmt(link_settings, " /DLL");
+ if (build_context.no_entry_point) {
+ link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
+ }
} else {
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
}
@@ -701,12 +704,12 @@ try_cross_linking:;
return result;
}
- object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(android_glue_static_lib));
+ object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(android_glue_static_lib));
}
for (String object_path : gen->output_object_paths) {
- object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
+ object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path));
}
gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index af08722c3..e1cbe7558 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -1313,7 +1313,7 @@ namespace lbAbiWasm {
registers/arguments if possible rather than by pointer.
*/
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type);
- gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
+ gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type);
enum {MAX_DIRECT_STRUCT_SIZE = 32};
@@ -1323,7 +1323,9 @@ namespace lbAbiWasm {
ft->ctx = c;
ft->calling_convention = calling_convention;
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type);
- ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
+
+ GB_ASSERT(original_type->kind == Type_Proc);
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple, original_type->Proc.results);
return ft;
}
@@ -1359,7 +1361,7 @@ namespace lbAbiWasm {
return false;
}
- gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal bool type_can_be_direct(LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
i64 sz = lb_sizeof(type);
if (sz == 0) {
@@ -1372,9 +1374,21 @@ namespace lbAbiWasm {
return false;
} else if (kind == LLVMStructTypeKind) {
unsigned count = LLVMCountStructElementTypes(type);
+
+ // NOTE(laytan): raw unions are always structs with 1 field in LLVM, need to check our own def.
+ Type *bt = base_type(original_type);
+ if (bt->kind == Type_Struct && bt->Struct.is_raw_union) {
+ count = cast(unsigned)bt->Struct.fields.count;
+ }
+
if (count == 1) {
- return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
+ return type_can_be_direct(
+ LLVMStructGetTypeAtIndex(type, 0),
+ type_internal_index(original_type, 0),
+ calling_convention
+ );
}
+
} else if (is_basic_register_type(type)) {
return true;
}
@@ -1398,7 +1412,7 @@ namespace lbAbiWasm {
return false;
}
- gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
@@ -1406,15 +1420,15 @@ namespace lbAbiWasm {
if (sz == 0) {
return lb_arg_type_ignore(type);
}
- if (type_can_be_direct(type, calling_convention)) {
+ if (type_can_be_direct(type, original_type, calling_convention)) {
return lb_arg_type_direct(type);
}
return lb_arg_type_indirect(type, nullptr);
}
- gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
+ gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
if (build_context.metrics.ptr_size < build_context.metrics.int_size &&
- type_can_be_direct(type, calling_convention)) {
+ type_can_be_direct(type, original_type, calling_convention)) {
LLVMTypeRef types[2] = {
LLVMStructGetTypeAtIndex(type, 0),
// ignore padding
@@ -1423,7 +1437,7 @@ namespace lbAbiWasm {
LLVMTypeRef new_type = LLVMStructTypeInContext(c, types, gb_count_of(types), false);
return lb_arg_type_direct(type, new_type, nullptr, nullptr);
} else {
- return is_struct(c, type, calling_convention);
+ return is_struct(c, type, original_type, calling_convention);
}
}
@@ -1444,9 +1458,9 @@ namespace lbAbiWasm {
LLVMTypeKind kind = LLVMGetTypeKind(t);
if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
if (is_type_slice(ptype) || is_type_string(ptype)) {
- args[i] = pseudo_slice(c, t, calling_convention);
+ args[i] = pseudo_slice(c, t, ptype, calling_convention);
} else {
- args[i] = is_struct(c, t, calling_convention);
+ args[i] = is_struct(c, t, ptype, calling_convention);
}
} else {
args[i] = non_struct(c, t, false);
@@ -1455,11 +1469,11 @@ namespace lbAbiWasm {
return args;
}
- gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
+ gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
- if (type_can_be_direct(return_type, ft->calling_convention)) {
+ if (type_can_be_direct(return_type, original_type, ft->calling_convention)) {
return lb_arg_type_direct(return_type);
} else if (ft->calling_convention != ProcCC_CDecl) {
i64 sz = lb_sizeof(return_type);
@@ -1471,7 +1485,35 @@ namespace lbAbiWasm {
}
}
- LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
+ // Multiple returns.
+ if (return_is_tuple) { \
+ lbArgType return_arg = {};
+ if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
+ unsigned field_count = LLVMCountStructElementTypes(return_type);
+ if (field_count > 1) {
+ ft->original_arg_count = ft->args.count;
+ ft->multiple_return_original_type = return_type;
+
+ for (unsigned i = 0; i < field_count-1; i++) {
+ LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
+ LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
+ lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
+ array_add(&ft->args, ret_partial);
+ }
+
+ return_arg = compute_return_type(
+ ft,
+ c,
+ LLVMStructGetTypeAtIndex(return_type, field_count-1),
+ true, false,
+ type_internal_index(original_type, field_count-1)
+ );
+ }
+ }
+ if (return_arg.type != nullptr) {
+ return return_arg;
+ }
+ }
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index e897ae282..c3112934e 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -292,12 +292,26 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons
i32 line = pos.line;
i32 column = pos.column;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
file = obfuscate_string(file, "F");
procedure = obfuscate_string(procedure, "P");
- line = obfuscate_i32(line);
- column = obfuscate_i32(column);
+ line = obfuscate_i32(line);
+ column = obfuscate_i32(column);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ procedure = str_lit("");
+
+ line = 0;
+ column = 0;
+ break;
}
LLVMValueRef fields[4] = {};
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 5aaa7f63a..aaa9ffd4d 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -568,10 +568,22 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array<lbValue> arr, TokenP
i32 line = pos.line;
i32 col = pos.column;
- if (build_context.obfuscate_source_code_locations) {
+ switch (build_context.source_code_location_info) {
+ case SourceCodeLocationInfo_Normal:
+ break;
+ case SourceCodeLocationInfo_Obfuscated:
file = obfuscate_string(file, "F");
line = obfuscate_i32(line);
col = obfuscate_i32(col);
+ break;
+ case SourceCodeLocationInfo_Filename:
+ file = last_path_element(file);
+ break;
+ case SourceCodeLocationInfo_None:
+ file = str_lit("");
+ line = 0;
+ col = 0;
+ break;
}
arr[0] = lb_find_or_add_entity_string(p->module, file, false);
@@ -2206,7 +2218,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_count = 3;
}
LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
- fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
+ fields[0] = LLVMPointerType(lb_type(m, type->SoaPointer.elem), 0);
if (bigger_int) {
fields[1] = lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size);
fields[2] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index f51ed2b4d..9f6a1d653 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -345,7 +345,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) {
lb_add_attribute_to_proc(m, p->value, "sanitize_address");
}
- if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
+ if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) {
lb_add_attribute_to_proc(m, p->value, "sanitize_memory");
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
@@ -546,6 +546,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
GB_ASSERT(p->type != nullptr);
lb_ensure_abi_function_type(p->module, p);
+ if (p->type->Proc.calling_convention == ProcCC_Odin) {
+ lb_push_context_onto_stack_from_implicit_parameter(p);
+ }
{
lbFunctionType *ft = p->abi_function_type;
@@ -743,9 +746,6 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
}
}
- if (p->type->Proc.calling_convention == ProcCC_Odin) {
- lb_push_context_onto_stack_from_implicit_parameter(p);
- }
lb_set_debug_position_to_procedure_begin(p);
if (p->debug_info != nullptr) {
@@ -2774,15 +2774,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
LLVMSetMetadata(instr, kind_id, LLVMMetadataAsValue(p->module->ctx, node));
}
break;
- case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break;
- case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+ case BuiltinProc_volatile_store:
+ LLVMSetVolatile(instr, true);
+ break;
+ case BuiltinProc_atomic_store:
+ LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
+ LLVMSetVolatile(instr, true);
+ break;
case BuiltinProc_atomic_store_explicit:
{
auto ordering = llvm_atomic_ordering_from_odin(ce->args[2]);
LLVMSetOrdering(instr, ordering);
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(instr, true);
- }
+ LLVMSetVolatile(instr, true);
}
break;
}
@@ -2808,15 +2811,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
}
break;
break;
- case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break;
- case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
+ case BuiltinProc_volatile_load:
+ LLVMSetVolatile(instr, true);
+ break;
+ case BuiltinProc_atomic_load:
+ LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
+ LLVMSetVolatile(instr, true);
+ break;
case BuiltinProc_atomic_load_explicit:
{
auto ordering = llvm_atomic_ordering_from_odin(ce->args[1]);
LLVMSetOrdering(instr, ordering);
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(instr, true);
- }
+ LLVMSetVolatile(instr, true);
}
break;
}
@@ -2901,9 +2907,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
lbValue res = {};
res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false);
res.type = tv.type;
- if (ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(res.value, true);
- }
+ LLVMSetVolatile(res.value, true);
return res;
}
@@ -2939,9 +2943,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
single_threaded
);
LLVMSetWeak(value, weak);
- if (success_ordering == LLVMAtomicOrderingUnordered || failure_ordering == LLVMAtomicOrderingUnordered) {
- LLVMSetVolatile(value, true);
- }
+ LLVMSetVolatile(value, true);
if (is_type_tuple(tv.type)) {
Type *fix_typed = alloc_type_tuple();
diff --git a/src/main.cpp b/src/main.cpp
index d7fb66f99..112d1208a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -370,6 +370,7 @@ enum BuildFlagKind {
BuildFlag_NoRTTI,
BuildFlag_DynamicMapCalls,
BuildFlag_ObfuscateSourceCodeLocations,
+ BuildFlag_SourceCodeLocations,
BuildFlag_Compact,
BuildFlag_GlobalDefinitions,
@@ -594,6 +595,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_SourceCodeLocations, str_lit("source-code-locations"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test | Command_build);
@@ -1422,7 +1424,23 @@ gb_internal bool parse_build_flags(Array<String> args) {
break;
case BuildFlag_ObfuscateSourceCodeLocations:
- build_context.obfuscate_source_code_locations = true;
+ gb_printf_err("'-obfuscate-source-code-locations' is now deprecated in favor of '-source-code-locations:obfuscated'\n");
+ build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
+ break;
+
+ case BuildFlag_SourceCodeLocations:
+ if (str_eq_ignore_case(value.value_string, str_lit("normal"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Normal;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("obfuscated"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("filename"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_Filename;
+ } else if (str_eq_ignore_case(value.value_string, str_lit("none"))) {
+ build_context.source_code_location_info = SourceCodeLocationInfo_None;
+ } else {
+ gb_printf_err("-source-code-locations:<string> options are 'normal', 'obfuscated', 'filename', and 'none'\n");
+ bad_flags = true;
+ }
break;
case BuildFlag_DefaultToNilAllocator:
@@ -2397,12 +2415,6 @@ gb_internal int print_show_help(String const arg0, String command, String option
}
}
- if (test_only) {
- if (print_flag("-build-only")) {
- print_usage_line(2, "Only builds the test executable; does not automatically run it afterwards.");
- }
- }
-
if (check) {
if (print_flag("-collection:<name>=<filepath>")) {
print_usage_line(2, "Defines a library collection used for imports.");
@@ -2669,8 +2681,14 @@ gb_internal int print_show_help(String const arg0, String command, String option
}
- if (print_flag("-obfuscate-source-code-locations")) {
- print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+ if (print_flag("-source-code-locations:<string>")) {
+ print_usage_line(2, "Processes the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-source-code-locations:normal");
+ print_usage_line(3, "-source-code-locations:obfuscated");
+ print_usage_line(3, "-source-code-locations:filename");
+ print_usage_line(3, "-source-code-locations:none");
+ print_usage_line(2, "The default is -source-code-locations:normal.");
}
diff --git a/src/types.cpp b/src/types.cpp
index ce921796d..74da7f6aa 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -1203,6 +1203,7 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
}
gb_internal bool is_type_named(Type *t) {
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return true;
}
@@ -1212,6 +1213,7 @@ gb_internal bool is_type_named(Type *t) {
gb_internal bool is_type_boolean(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Boolean) != 0;
}
@@ -1220,6 +1222,7 @@ gb_internal bool is_type_boolean(Type *t) {
gb_internal bool is_type_integer(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0;
}
@@ -1241,15 +1244,18 @@ gb_internal bool is_type_integer_like(Type *t) {
gb_internal bool is_type_unsigned(Type *t) {
t = base_type(t);
- // t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
}
+ if (t->kind == Type_Enum) {
+ return (t->Enum.base_type->Basic.flags & BasicFlag_Unsigned) != 0;
+ }
return false;
}
gb_internal bool is_type_integer_128bit(Type *t) {
- // t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16;
}
@@ -1258,6 +1264,7 @@ gb_internal bool is_type_integer_128bit(Type *t) {
gb_internal bool is_type_rune(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Rune) != 0;
}
@@ -1266,6 +1273,7 @@ gb_internal bool is_type_rune(Type *t) {
gb_internal bool is_type_numeric(Type *t) {
// t = core_type(t);
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Numeric) != 0;
} else if (t->kind == Type_Enum) {
@@ -1279,6 +1287,7 @@ gb_internal bool is_type_numeric(Type *t) {
}
gb_internal bool is_type_string(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_String) != 0;
}
@@ -1286,6 +1295,7 @@ gb_internal bool is_type_string(Type *t) {
}
gb_internal bool is_type_cstring(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_cstring;
}
@@ -1293,9 +1303,7 @@ gb_internal bool is_type_cstring(Type *t) {
}
gb_internal bool is_type_typed(Type *t) {
t = base_type(t);
- if (t == nullptr) {
- return false;
- }
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Untyped) == 0;
}
@@ -1303,9 +1311,7 @@ gb_internal bool is_type_typed(Type *t) {
}
gb_internal bool is_type_untyped(Type *t) {
t = base_type(t);
- if (t == nullptr) {
- return false;
- }
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Untyped) != 0;
}
@@ -1313,6 +1319,7 @@ gb_internal bool is_type_untyped(Type *t) {
}
gb_internal bool is_type_ordered(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_Ordered) != 0;
@@ -1325,6 +1332,7 @@ gb_internal bool is_type_ordered(Type *t) {
}
gb_internal bool is_type_ordered_numeric(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0;
@@ -1333,6 +1341,7 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
}
gb_internal bool is_type_constant_type(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
}
@@ -1346,6 +1355,7 @@ gb_internal bool is_type_constant_type(Type *t) {
}
gb_internal bool is_type_float(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Float) != 0;
}
@@ -1353,6 +1363,7 @@ gb_internal bool is_type_float(Type *t) {
}
gb_internal bool is_type_complex(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Complex) != 0;
}
@@ -1360,6 +1371,7 @@ gb_internal bool is_type_complex(Type *t) {
}
gb_internal bool is_type_quaternion(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
@@ -1367,6 +1379,7 @@ gb_internal bool is_type_quaternion(Type *t) {
}
gb_internal bool is_type_complex_or_quaternion(Type *t) {
t = core_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0;
}
@@ -1374,6 +1387,7 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) {
}
gb_internal bool is_type_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Pointer) != 0;
}
@@ -1381,10 +1395,12 @@ gb_internal bool is_type_pointer(Type *t) {
}
gb_internal bool is_type_soa_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_SoaPointer;
}
gb_internal bool is_type_multi_pointer(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_MultiPointer;
}
gb_internal bool is_type_internally_pointer_like(Type *t) {
@@ -1393,6 +1409,7 @@ gb_internal bool is_type_internally_pointer_like(Type *t) {
gb_internal bool is_type_tuple(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Tuple;
}
gb_internal bool is_type_uintptr(Type *t) {
@@ -1415,14 +1432,17 @@ gb_internal bool is_type_u8(Type *t) {
}
gb_internal bool is_type_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Array;
}
gb_internal bool is_type_enumerated_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_EnumeratedArray;
}
gb_internal bool is_type_matrix(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Matrix;
}
@@ -1566,22 +1586,27 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
gb_internal bool is_type_dynamic_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_DynamicArray;
}
gb_internal bool is_type_slice(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Slice;
}
gb_internal bool is_type_proc(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Proc;
}
gb_internal bool is_type_asm_proc(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm;
}
gb_internal bool is_type_simd_vector(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_SimdVector;
}
@@ -1621,11 +1646,13 @@ gb_internal Type *base_any_array_type(Type *t) {
gb_internal bool is_type_generic(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
return t->kind == Type_Generic;
}
gb_internal bool is_type_u8_slice(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Slice) {
return is_type_u8(t->Slice.elem);
}
@@ -1633,6 +1660,7 @@ gb_internal bool is_type_u8_slice(Type *t) {
}
gb_internal bool is_type_u8_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Array) {
return is_type_u8(t->Array.elem);
}
@@ -1640,6 +1668,7 @@ gb_internal bool is_type_u8_array(Type *t) {
}
gb_internal bool is_type_u8_ptr(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Pointer) {
return is_type_u8(t->Slice.elem);
}
@@ -1647,6 +1676,7 @@ gb_internal bool is_type_u8_ptr(Type *t) {
}
gb_internal bool is_type_u8_multi_ptr(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_MultiPointer) {
return is_type_u8(t->Slice.elem);
}
@@ -1654,6 +1684,7 @@ gb_internal bool is_type_u8_multi_ptr(Type *t) {
}
gb_internal bool is_type_rune_array(Type *t) {
t = base_type(t);
+ if (t == nullptr) { return false; }
if (t->kind == Type_Array) {
return is_type_rune(t->Array.elem);
}
@@ -1979,7 +2010,13 @@ gb_internal bool is_type_untyped_uninit(Type *t) {
}
gb_internal bool is_type_empty_union(Type *t) {
+ if (t == nullptr) {
+ return false;
+ }
t = base_type(t);
+ if (t == nullptr) {
+ return false;
+ }
return t->kind == Type_Union && t->Union.variants.count == 0;
}
@@ -2668,7 +2705,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) {
y = y->Named.base;
}
}
- if (x->kind != y->kind) {
+ if (x == nullptr || y == nullptr || x->kind != y->kind) {
return false;
}
@@ -3059,11 +3096,15 @@ gb_internal i64 union_tag_size(Type *u) {
compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count);
}
- for_array(i, u->Union.variants) {
- Type *variant_type = u->Union.variants[i];
- i64 align = type_align_of(variant_type);
- if (max_align < align) {
- max_align = align;
+ if (u->Union.custom_align > 0) {
+ max_align = gb_max(max_align, u->Union.custom_align);
+ } else {
+ for_array(i, u->Union.variants) {
+ Type *variant_type = u->Union.variants[i];
+ i64 align = type_align_of(variant_type);
+ if (max_align < align) {
+ max_align = align;
+ }
}
}
@@ -4580,6 +4621,83 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_
// return type;
// }
+// Index a type that is internally a struct or array.
+gb_internal Type *type_internal_index(Type *t, isize index) {
+ Type *bt = base_type(t);
+ if (bt == nullptr) {
+ return nullptr;
+ }
+
+ switch (bt->kind) {
+ case Type_Basic:
+ {
+ switch (bt->Basic.kind) {
+ case Basic_complex32: return t_f16;
+ case Basic_complex64: return t_f32;
+ case Basic_complex128: return t_f64;
+ case Basic_quaternion64: return t_f16;
+ case Basic_quaternion128: return t_f32;
+ case Basic_quaternion256: return t_f64;
+ case Basic_string:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_u8_ptr : t_int;
+ }
+ case Basic_any:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_typeid;
+ }
+ }
+ }
+ break;
+
+ case Type_Array: return bt->Array.elem;
+ case Type_EnumeratedArray: return bt->EnumeratedArray.elem;
+ case Type_SimdVector: return bt->SimdVector.elem;
+ case Type_Slice:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_typeid;
+ }
+ case Type_DynamicArray:
+ {
+ switch (index) {
+ case 0: return t_rawptr;
+ case 1: return t_int;
+ case 2: return t_int;
+ case 3: return t_allocator;
+ default: GB_PANIC("invalid raw dynamic array index");
+ };
+ }
+ case Type_Struct:
+ return get_struct_field_type(bt, index);
+ case Type_Union:
+ if (index < bt->Union.variants.count) {
+ return bt->Union.variants[index];
+ }
+ return union_tag_type(bt);
+ case Type_Tuple:
+ return bt->Tuple.variables[index]->type;
+ case Type_Matrix:
+ return bt->Matrix.elem;
+ case Type_SoaPointer:
+ {
+ GB_ASSERT(index == 0 || index == 1);
+ return index == 0 ? t_rawptr : t_int;
+ }
+ case Type_Map:
+ return type_internal_index(bt->Map.debug_metadata_type, index);
+ case Type_BitField:
+ return type_internal_index(bt->BitField.backing_type, index);
+ case Type_Generic:
+ return type_internal_index(bt->Generic.specialized, index);
+ };
+
+ GB_PANIC("Unhandled type %s", type_to_string(bt));
+ return nullptr;
+};
+
gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false, bool allow_polymorphic=false) {
if (type == nullptr) {
return gb_string_appendc(str, "<no type>");