Skip to content

Commit 493bea1

Browse files
authored
Fearlessly hold references into ValueStore again (#5589)
Undo changes that were meant to prevent use of a reference into `ValueStore` after being invalidated. After #5576, the `ValueStore` makes such references stable, so there's no need to worry about invalidation.
1 parent a85d292 commit 493bea1

14 files changed

+100
-202
lines changed

toolchain/check/convert.cpp

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -567,21 +567,13 @@ static auto ConvertStructToClass(
567567
SemIR::InstId value_id, ConversionTarget target,
568568
SemIR::InstId dest_vtable_id = SemIR::InstId::None) -> SemIR::InstId {
569569
PendingBlock target_block(&context);
570-
auto object_repr_id = SemIR::TypeId::None;
571-
572-
{
573-
auto& dest_class_info = context.classes().Get(dest_type.class_id);
574-
CARBON_CHECK(dest_class_info.inheritance_kind != SemIR::Class::Abstract);
575-
if (!dest_vtable_id.has_value()) {
576-
dest_vtable_id = dest_class_info.vtable_id;
577-
}
578-
object_repr_id =
579-
dest_class_info.GetObjectRepr(context.sem_ir(), dest_type.specific_id);
580-
if (object_repr_id == SemIR::ErrorInst::TypeId) {
581-
return SemIR::ErrorInst::InstId;
582-
}
570+
auto& dest_class_info = context.classes().Get(dest_type.class_id);
571+
CARBON_CHECK(dest_class_info.inheritance_kind != SemIR::Class::Abstract);
572+
auto object_repr_id =
573+
dest_class_info.GetObjectRepr(context.sem_ir(), dest_type.specific_id);
574+
if (object_repr_id == SemIR::ErrorInst::TypeId) {
575+
return SemIR::ErrorInst::InstId;
583576
}
584-
585577
auto dest_struct_type =
586578
context.types().GetAs<SemIR::StructType>(object_repr_id);
587579

@@ -596,7 +588,8 @@ static auto ConvertStructToClass(
596588
}
597589

598590
auto result_id = ConvertStructToStructOrClass<SemIR::ClassElementAccess>(
599-
context, src_type, dest_struct_type, value_id, target, dest_vtable_id);
591+
context, src_type, dest_struct_type, value_id, target,
592+
dest_vtable_id.has_value() ? dest_vtable_id : dest_class_info.vtable_id);
600593

601594
if (need_temporary) {
602595
target_block.InsertHere();
@@ -1461,9 +1454,6 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
14611454
const SemIR::Function& callee,
14621455
SemIR::SpecificId callee_specific_id)
14631456
-> SemIR::InstBlockId {
1464-
// The callee reference can be invalidated by conversions, so ensure all reads
1465-
// from it are done before conversion calls.
1466-
auto callee_decl_id = callee.latest_decl_id();
14671457
auto param_patterns =
14681458
context.inst_blocks().GetOrEmpty(callee.param_patterns_id);
14691459
auto return_slot_pattern_id = callee.return_slot_pattern_id;
@@ -1477,7 +1467,7 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
14771467
CARBON_DIAGNOSTIC(InCallToFunction, Note, "calling function declared here");
14781468
context.emitter()
14791469
.Build(call_loc_id, MissingObjectInMethodCall)
1480-
.Note(callee_decl_id, InCallToFunction)
1470+
.Note(callee.latest_decl_id(), InCallToFunction)
14811471
.Emit();
14821472
self_id = SemIR::ErrorInst::InstId;
14831473
}

toolchain/check/deduce.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,8 @@ auto DeduceGenericCallArguments(
602602
return deduction.MakeSpecific();
603603
}
604604

605-
auto DeduceImplArguments(Context& context, SemIR::LocId loc_id, DeduceImpl impl,
606-
SemIR::ConstantId self_id,
605+
auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
606+
const SemIR::Impl& impl, SemIR::ConstantId self_id,
607607
SemIR::SpecificId constraint_specific_id)
608608
-> SemIR::SpecificId {
609609
DeductionContext deduction(&context, loc_id, impl.generic_id,
@@ -613,7 +613,7 @@ auto DeduceImplArguments(Context& context, SemIR::LocId loc_id, DeduceImpl impl,
613613

614614
// Prepare to perform deduction of the type and interface.
615615
deduction.Add(impl.self_id, context.constant_values().GetInstId(self_id));
616-
deduction.Add(impl.specific_id, constraint_specific_id);
616+
deduction.Add(impl.interface.specific_id, constraint_specific_id);
617617

618618
if (!deduction.Deduce() || !deduction.CheckDeductionIsComplete()) {
619619
return SemIR::SpecificId::None;

toolchain/check/deduce.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,10 @@ auto DeduceGenericCallArguments(
1818
SemIR::InstBlockId param_patterns_id, SemIR::InstId self_id,
1919
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::SpecificId;
2020

21-
// Data from the `Impl` that is used by deduce.
22-
//
23-
// We don't use a reference to an `Impl` as deduction can invalidate the
24-
// reference by causing impl declarations to be imported from `Core` during
25-
// conversion.
26-
struct DeduceImpl {
27-
SemIR::InstId self_id;
28-
SemIR::GenericId generic_id;
29-
SemIR::SpecificId specific_id;
30-
};
31-
3221
// Deduces the impl arguments to use in a use of a parameterized impl. Returns
3322
// `None` if deduction fails.
34-
auto DeduceImplArguments(Context& context, SemIR::LocId loc_id, DeduceImpl impl,
35-
SemIR::ConstantId self_id,
23+
auto DeduceImplArguments(Context& context, SemIR::LocId loc_id,
24+
const SemIR::Impl& impl, SemIR::ConstantId self_id,
3625
SemIR::SpecificId constraint_specific_id)
3726
-> SemIR::SpecificId;
3827

toolchain/check/handle_choice.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,21 +283,17 @@ auto HandleParseNode(Context& context, Parse::ChoiceDefinitionId node_id)
283283
.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId),
284284
.object_repr_type_inst_id =
285285
context.types().GetInstId(GetStructType(context, fields_id))});
286-
// Note: avoid storing a reference to the returned Class, since it may be
287-
// invalidated by other type constructions.
288-
context.classes().Get(class_id).complete_type_witness_id = choice_witness_id;
289-
290-
auto self_type_id = context.classes().Get(class_id).self_type_id;
291-
auto name_scope_id = context.classes().Get(class_id).scope_id;
286+
auto& class_info = context.classes().Get(class_id);
287+
class_info.complete_type_witness_id = choice_witness_id;
292288

293289
auto self_struct_type_id = GetStructType(
294290
context, context.struct_type_fields().AddCanonical(struct_type_fields));
295291

296292
for (auto [i, deferred_binding] :
297293
llvm::enumerate(context.choice_deferred_bindings())) {
298294
MakeLetBinding(context,
299-
ChoiceInfo{.self_type_id = self_type_id,
300-
.name_scope_id = name_scope_id,
295+
ChoiceInfo{.self_type_id = class_info.self_type_id,
296+
.name_scope_id = class_info.scope_id,
301297
.self_struct_type_id = self_struct_type_id,
302298
.discriminant_type_id = discriminant_type_id,
303299
.num_alternative_bits = num_alternative_bits},
@@ -310,7 +306,7 @@ auto HandleParseNode(Context& context, Parse::ChoiceDefinitionId node_id)
310306
context.scope_stack().Pop();
311307
context.decl_name_stack().PopScope();
312308

313-
FinishGenericDefinition(context, context.classes().Get(class_id).generic_id);
309+
FinishGenericDefinition(context, class_info.generic_id);
314310

315311
context.choice_deferred_bindings().clear();
316312
return true;

toolchain/check/handle_class.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,10 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
366366
return true;
367367
}
368368

369-
auto adapt_id = context.classes().Get(parent_class_decl->class_id).adapt_id;
370-
if (adapt_id.has_value()) {
371-
DiagnoseClassSpecificDeclRepeated(context, node_id, SemIR::LocId(adapt_id),
369+
auto& class_info = context.classes().Get(parent_class_decl->class_id);
370+
if (class_info.adapt_id.has_value()) {
371+
DiagnoseClassSpecificDeclRepeated(context, node_id,
372+
SemIR::LocId(class_info.adapt_id),
372373
Lex::TokenKind::Adapt);
373374
return true;
374375
}
@@ -395,10 +396,8 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
395396
}
396397

397398
// Build a SemIR representation for the declaration.
398-
adapt_id = AddInst<SemIR::AdaptDecl>(
399+
class_info.adapt_id = AddInst<SemIR::AdaptDecl>(
399400
context, node_id, {.adapted_type_inst_id = adapted_type_inst_id});
400-
auto& class_info = context.classes().Get(parent_class_decl->class_id);
401-
class_info.adapt_id = adapt_id;
402401

403402
// Extend the class scope with the adapted type's scope if requested.
404403
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
@@ -502,9 +501,10 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
502501
return true;
503502
}
504503

505-
auto base_id = context.classes().Get(parent_class_decl->class_id).base_id;
506-
if (base_id.has_value()) {
507-
DiagnoseClassSpecificDeclRepeated(context, node_id, SemIR::LocId(base_id),
504+
auto& class_info = context.classes().Get(parent_class_decl->class_id);
505+
if (class_info.base_id.has_value()) {
506+
DiagnoseClassSpecificDeclRepeated(context, node_id,
507+
SemIR::LocId(class_info.base_id),
508508
Lex::TokenKind::Base);
509509
return true;
510510
}
@@ -525,16 +525,13 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
525525
// The `base` value in the class scope has an unbound element type. Instance
526526
// binding will be performed when it's found by name lookup into an instance.
527527
auto field_type_id = GetUnboundElementType(
528-
context,
529-
context.types().GetInstId(
530-
context.classes().Get(parent_class_decl->class_id).self_type_id),
528+
context, context.types().GetInstId(class_info.self_type_id),
531529
base_info.inst_id);
532-
base_id = AddInst<SemIR::BaseDecl>(context, node_id,
533-
{.type_id = field_type_id,
534-
.base_type_inst_id = base_info.inst_id,
535-
.index = SemIR::ElementIndex::None});
536-
auto& class_info = context.classes().Get(parent_class_decl->class_id);
537-
class_info.base_id = base_id;
530+
class_info.base_id =
531+
AddInst<SemIR::BaseDecl>(context, node_id,
532+
{.type_id = field_type_id,
533+
.base_type_inst_id = base_info.inst_id,
534+
.index = SemIR::ElementIndex::None});
538535

539536
if (base_info.type_id != SemIR::ErrorInst::TypeId) {
540537
auto base_class_info = context.classes().Get(

toolchain/check/handle_impl.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -352,30 +352,22 @@ static auto DiagnoseUnusedGenericBinding(Context& context,
352352
SemIR::ImplId impl_id) -> void {
353353
auto deduced_specific_id = SemIR::SpecificId::None;
354354

355-
{
356-
auto& stored_impl_info = context.impls().Get(impl_id);
357-
if (!stored_impl_info.generic_id.has_value() ||
358-
stored_impl_info.witness_id == SemIR::ErrorInst::InstId) {
359-
return;
360-
}
361-
362-
// TODO: Deduce has side effects in the semir by generating `Converted`
363-
// instructions which we will not use here. We should stop generating
364-
// those when deducing for impl lookup, but for now we discard them by
365-
// pushing an InstBlock on the stack and dropping it right after.
366-
context.inst_block_stack().Push();
367-
// Deduction can invalidate references to ValueStores; we can't use
368-
// `stored_impl_info` after.
369-
deduced_specific_id = DeduceImplArguments(
370-
context, node_id,
371-
DeduceImpl{.self_id = stored_impl_info.self_id,
372-
.generic_id = stored_impl_info.generic_id,
373-
.specific_id = stored_impl_info.interface.specific_id},
374-
context.constant_values().Get(stored_impl_info.self_id),
375-
stored_impl_info.interface.specific_id);
376-
context.inst_block_stack().PopAndDiscard();
355+
auto& impl = context.impls().Get(impl_id);
356+
if (!impl.generic_id.has_value() ||
357+
impl.witness_id == SemIR::ErrorInst::InstId) {
358+
return;
377359
}
378360

361+
// TODO: Deduce has side effects in the semir by generating `Converted`
362+
// instructions which we will not use here. We should stop generating
363+
// those when deducing for impl lookup, but for now we discard them by
364+
// pushing an InstBlock on the stack and dropping it right after.
365+
context.inst_block_stack().Push();
366+
deduced_specific_id = DeduceImplArguments(
367+
context, node_id, impl, context.constant_values().Get(impl.self_id),
368+
impl.interface.specific_id);
369+
context.inst_block_stack().PopAndDiscard();
370+
379371
if (deduced_specific_id.has_value()) {
380372
// Deduction succeeded, all bindings were used.
381373
return;

toolchain/check/impl.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,7 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
164164
// Adds functions to the witness that the specified impl implements the given
165165
// interface.
166166
auto FinishImplWitness(Context& context, SemIR::ImplId impl_id) -> void {
167-
// Make a copy of the impl. We're going to reference it a lot, and `impl`s
168-
// could get invalidated by some of the things we do.
169-
const auto impl = context.impls().Get(impl_id);
167+
const auto& impl = context.impls().Get(impl_id);
170168

171169
CARBON_CHECK(impl.is_being_defined());
172170
CARBON_CHECK(impl.witness_id.has_value());

toolchain/check/impl_lookup.cpp

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -206,31 +206,20 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id,
206206
SemIR::ConstantId query_self_const_id,
207207
const SemIR::SpecificInterface& interface,
208208
SemIR::ImplId impl_id) -> EvalImplLookupResult {
209+
const SemIR::Impl& impl = context.impls().Get(impl_id);
210+
209211
// The impl may have generic arguments, in which case we need to deduce them
210212
// to find what they are given the specific type and interface query. We use
211213
// that specific to map values in the impl to the deduced values.
212214
auto specific_id = SemIR::SpecificId::None;
213-
{
214-
// DeduceImplArguments can import new impls which can invalidate any
215-
// pointers into `context.impls()`.
216-
const SemIR::Impl& impl = context.impls().Get(impl_id);
217-
218-
if (impl.generic_id.has_value()) {
219-
specific_id =
220-
DeduceImplArguments(context, loc_id,
221-
{.self_id = impl.self_id,
222-
.generic_id = impl.generic_id,
223-
.specific_id = impl.interface.specific_id},
224-
query_self_const_id, interface.specific_id);
225-
if (!specific_id.has_value()) {
226-
return EvalImplLookupResult::MakeNone();
227-
}
215+
if (impl.generic_id.has_value()) {
216+
specific_id = DeduceImplArguments(
217+
context, loc_id, impl, query_self_const_id, interface.specific_id);
218+
if (!specific_id.has_value()) {
219+
return EvalImplLookupResult::MakeNone();
228220
}
229221
}
230222

231-
// Get a pointer again after DeduceImplArguments() is complete.
232-
const SemIR::Impl& impl = context.impls().Get(impl_id);
233-
234223
// The self type of the impl must match the type in the query, or this is an
235224
// `impl T as ...` for some other type `T` and should not be considered.
236225
auto deduced_self_const_id = SemIR::GetConstantValueInSpecific(
@@ -279,28 +268,22 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id,
279268
return EvalImplLookupResult::MakeNone();
280269
}
281270

282-
bool is_effectively_final = query_is_concrete || impl.is_final;
283-
auto witness_id = impl.witness_id;
284-
285-
// Note that this invalidates our `impl` reference. Don't use it again after
286-
// this point.
287-
LoadImportRef(context, witness_id);
288-
271+
LoadImportRef(context, impl.witness_id);
289272
if (specific_id.has_value()) {
290273
// We need a definition of the specific `impl` so we can access its
291274
// witness.
292275
ResolveSpecificDefinition(context, loc_id, specific_id);
293276
}
294277

295-
if (is_effectively_final) {
278+
if (query_is_concrete || impl.is_final) {
296279
// TODO: These final results should be cached somehow. Positive (non-None)
297280
// results could be cached globally, as they can not change. But
298281
// negative results can change after a final impl is written, so
299282
// they can only be cached in a limited way, or the cache needs to
300283
// be invalidated by writing a final impl that would match.
301284
return EvalImplLookupResult::MakeFinal(
302285
context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
303-
context.sem_ir(), specific_id, witness_id)));
286+
context.sem_ir(), specific_id, impl.witness_id)));
304287
} else {
305288
return EvalImplLookupResult::MakeNonFinal();
306289
}
@@ -583,11 +566,6 @@ auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id,
583566
SemIR::InstId non_canonical_query_self_inst_id,
584567
bool poison_concrete_results)
585568
-> EvalImplLookupResult {
586-
// NOTE: Do not retain this reference to the SpecificInterface obtained from a
587-
// value store by SpecificInterfaceId. Doing impl lookup does deduce which can
588-
// do more impl lookups, and impl lookup can add a new SpecificInterface to
589-
// the store which can reallocate and invalidate any references held here into
590-
// the store.
591569
auto query_specific_interface =
592570
context.specific_interfaces().Get(eval_query.query_specific_interface_id);
593571

@@ -656,8 +634,6 @@ auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id,
656634
context.impl_lookup_stack().back().impl_loc = candidate.loc_inst_id;
657635
}
658636

659-
// NOTE: GetWitnessIdForImpl() does deduction, which can cause new impls
660-
// to be imported, invalidating any pointer into `context.impls()`.
661637
auto result = GetWitnessIdForImpl(
662638
context, loc_id, query_is_concrete, query_self_const_id,
663639
query_specific_interface, candidate.impl_id);

0 commit comments

Comments
 (0)