mirror of
https://github.com/odin-lang/Odin.git
synced 2026-05-25 05:09:53 +00:00
Merge pull request #6716 from wishfoundry/fix-parapoly-specialization-race
Fix race condition relating to type specialization
This commit is contained in:
@@ -1491,6 +1491,22 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t
|
||||
}
|
||||
|
||||
|
||||
// If `specialization` is a polymorphic-record specialization that has been published into
|
||||
// its originating record's `gen_types` cache, return that cache's `GenTypesData`. Its
|
||||
// `RecursiveMutex` guards concurrent `find_polymorphic_record_entity` reads, so the
|
||||
// in-place finalization below must hold it. Returns nullptr otherwise.
|
||||
gb_internal GenTypesData *gen_types_data_of_specialization(Type *specialization) {
|
||||
if (specialization != nullptr &&
|
||||
specialization->kind == Type_Named &&
|
||||
specialization->Named.type_name != nullptr) {
|
||||
Type *orig = specialization->Named.type_name->TypeName.original_type_for_parapoly;
|
||||
if (orig != nullptr && orig->kind == Type_Named) {
|
||||
return orig->Named.gen_types_data;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
|
||||
if (type == nullptr ||
|
||||
type == t_invalid) {
|
||||
@@ -1559,8 +1575,14 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special
|
||||
}
|
||||
|
||||
if (modify_type) {
|
||||
// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it
|
||||
// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it.
|
||||
// `specialization` may already be published in a polymorphic record's gen_types cache;
|
||||
// finalize it under that record's (recursive) gen_types mutex so a concurrent
|
||||
// find_polymorphic_record_entity on another thread cannot observe a torn Type.
|
||||
GenTypesData *gen_types = gen_types_data_of_specialization(specialization);
|
||||
if (gen_types != nullptr) mutex_lock(&gen_types->mutex);
|
||||
gb_memmove(specialization, type, gb_size_of(Type));
|
||||
if (gen_types != nullptr) mutex_unlock(&gen_types->mutex);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1606,8 +1628,12 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special
|
||||
}
|
||||
|
||||
if (modify_type) {
|
||||
// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it
|
||||
// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it.
|
||||
// See the struct branch above: finalize under the originating record's gen_types mutex.
|
||||
GenTypesData *gen_types = gen_types_data_of_specialization(specialization);
|
||||
if (gen_types != nullptr) mutex_lock(&gen_types->mutex);
|
||||
gb_memmove(specialization, type, gb_size_of(Type));
|
||||
if (gen_types != nullptr) mutex_unlock(&gen_types->mutex);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user