Merge pull request #7445 from kalsprite/target_feature_empty_element

string_split_iterator fix
This commit is contained in:
Jeroen van Rijn
2026-08-24 18:03:35 -07:00
committed by GitHub
6 changed files with 49 additions and 53 deletions

View File

@@ -2146,9 +2146,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
gb_internal bool check_single_target_feature_is_valid(String const &feature_list, String const &feature) {
String_Iterator it = {feature_list, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (str == feature) {
return true;
}
@@ -2160,8 +2159,8 @@ gb_internal bool check_single_target_feature_is_valid(String const &feature_list
gb_internal bool check_target_feature_is_valid(String const &feature, TargetArchKind arch, String *invalid) {
String feature_list = target_features_list[arch];
String_Iterator it = {feature, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
String feature_str = str;
if (string_starts_with(feature_str, '+') || string_starts_with(feature_str, '-')) {
feature_str = substring(feature_str, 1, feature_str.len);
@@ -2169,7 +2168,6 @@ gb_internal bool check_target_feature_is_valid(String const &feature, TargetArch
return false;
}
}
if (feature_str == "") break;
if (!check_single_target_feature_is_valid(feature_list, feature_str)) {
if (invalid) *invalid = str;
return false;
@@ -2181,10 +2179,8 @@ gb_internal bool check_target_feature_is_valid(String const &feature, TargetArch
gb_internal bool check_target_feature_is_valid_globally(String const &feature, String *invalid) {
String_Iterator it = {feature, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
bool valid = false;
for (int arch = TargetArch_Invalid; arch < TargetArch_COUNT; arch += 1) {
if (check_target_feature_is_valid(str, cast(TargetArchKind)arch, invalid)) {
@@ -2208,15 +2204,19 @@ gb_internal bool check_target_feature_is_valid_for_target_arch(String const &fea
gb_internal bool check_target_feature_is_enabled(String const &feature, String *not_enabled) {
String_Iterator it = {feature, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
String feature_str = str;
bool want_enabled = true;
if (string_starts_with(feature_str, '+') || string_starts_with(feature_str, '-')) {
want_enabled = feature_str[0] == '+';
feature_str = substring(feature_str, 1, feature_str.len);
}
if (feature_str == "") break;
if (feature_str == "") {
// a bare sign names no feature, which cannot be enabled
if (not_enabled) *not_enabled = str;
return false;
}
String plus_str = concatenate_strings(temporary_allocator(), make_string_c("+"), feature_str);
String minus_str = concatenate_strings(temporary_allocator(), make_string_c("-"), feature_str);
@@ -2240,9 +2240,8 @@ gb_internal bool check_target_feature_is_enabled(String const &feature, String *
gb_internal bool check_target_feature_is_superset_of(String const &superset, String const &of, String *missing) {
String_Iterator it = {of, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (!check_single_target_feature_is_valid(superset, str)) {
if (missing) *missing = str;
return false;

View File

@@ -3164,10 +3164,9 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
gbString llvm_features = gb_string_make(temporary_allocator(), "");
String_Iterator it = {build_context.target_features_string, 0};
String str = {};
bool first = true;
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
while (string_split_iterator_next(&it, ',', &str)) {
if (!first) {
llvm_features = gb_string_appendc(llvm_features, ",");
}

View File

@@ -226,10 +226,9 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
gbString feature_str = gb_string_make(temporary_allocator(), "");
String_Iterator it = {pt->Proc.enable_target_feature, 0};
String str = {};
bool first = true;
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
while (string_split_iterator_next(&it, ',', &str)) {
bool add_prefix = !(string_starts_with(str, '+') || string_starts_with(str, '-'));
if (!first) {
feature_str = gb_string_appendc(feature_str, ",");

View File

@@ -1455,12 +1455,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_String);
String val = value.value_string;
String_Iterator it = {val, 0};
for (;;) {
String pkg = string_split_iterator(&it, ',');
if (pkg.len == 0) {
break;
}
String pkg = {};
while (string_split_iterator_next(&it, ',', &pkg)) {
pkg = string_trim_whitespace(pkg);
if (!string_is_valid_identifier(pkg)) {
gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(pkg));
@@ -1478,12 +1474,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_String);
String val = value.value_string;
String_Iterator it = {val, 0};
for (;;) {
String attr = string_split_iterator(&it, ',');
if (attr.len == 0) {
break;
}
String attr = {};
while (string_split_iterator_next(&it, ',', &attr)) {
attr = string_trim_whitespace(attr);
if (!string_is_valid_identifier(attr)) {
gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(attr));
@@ -4166,9 +4158,8 @@ int main(int arg_count, char const **arg_ptr) {
} else {
String march_list = target_microarch_list[build_context.metrics.arch];
String_Iterator it = {march_list, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (str == build_context.microarch) {
// Found matching microarch
print_microarch_list = false;
@@ -4193,9 +4184,8 @@ int main(int arg_count, char const **arg_ptr) {
String march_list = target_microarch_list[build_context.metrics.arch];
String_Iterator it = {march_list, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (str == default_march) {
gb_printf("\t%.*s (default)\n", LIT(str));
} else {
@@ -4209,9 +4199,8 @@ int main(int arg_count, char const **arg_ptr) {
String default_features = get_default_features();
{
String_Iterator it = {default_features, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
string_set_add(&build_context.target_features_set, str);
}
}
@@ -4231,10 +4220,8 @@ int main(int arg_count, char const **arg_ptr) {
if (build_context.target_features_string.len != 0) {
String_Iterator target_it = {build_context.target_features_string, 0};
for (;;) {
String item = string_split_iterator(&target_it, ',');
if (item == "") break;
String item = {};
while (string_split_iterator_next(&target_it, ',', &item)) {
String stripped_item = item;
if (*stripped_item.text == '+' || *stripped_item.text == '-') {
stripped_item.text++;
@@ -4251,9 +4238,8 @@ int main(int arg_count, char const **arg_ptr) {
String feature_list = target_features_list[build_context.metrics.arch];
String_Iterator it = {feature_list, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (check_single_target_feature_is_valid(default_features, str)) {
if (has_ansi_terminal_colours()) {
gb_printf("\t%.*s\x1b[38;5;244m (implied by target microarch %.*s)\x1b[0m\n", LIT(str), LIT(march));

View File

@@ -293,6 +293,20 @@ gb_internal String string_split_iterator(String_Iterator *it, const char sep) {
return substring(it->str, start, end);
}
// NOTE: `string_split_iterator` returns a zero-length `String` both for an empty element and at
// exhaustion, so a loop that stops on an empty result stops at the first empty element instead.
// This skips empty elements and stops only once the iterator is exhausted.
gb_internal bool string_split_iterator_next(String_Iterator *it, char const sep, String *str_) {
while (it->pos < it->str.len) {
String str = string_split_iterator(it, sep);
if (str.len != 0) {
*str_ = str;
return true;
}
}
return false;
}
gb_internal gb_inline bool is_separator(u8 const &ch) {
return (ch == '/' || ch == '\\');
}

View File

@@ -3640,9 +3640,8 @@ gb_internal int matched_target_features(TypeProc *t) {
int matches = 0;
String_Iterator it = {t->require_target_feature, 0};
for (;;) {
String str = string_split_iterator(&it, ',');
if (str == "") break;
String str = {};
while (string_split_iterator_next(&it, ',', &str)) {
if (check_target_feature_is_valid_for_target_arch(str, nullptr)) {
matches += 1;
}