@@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const
2464
2464
bool
2465
2465
Type::is_direct_iface_type_helper (Unordered_set(const Type*)* visited) const
2466
2466
{
2467
- if (this ->points_to () != NULL
2468
- || this ->channel_type () != NULL
2467
+ if (this ->points_to () != NULL )
2468
+ {
2469
+ // Pointers to notinheap types must be stored indirectly. See
2470
+ // https://golang.org/issue/42076.
2471
+ if (!this ->points_to ()->in_heap ())
2472
+ return false ;
2473
+ return true ;
2474
+ }
2475
+
2476
+ if (this ->channel_type () != NULL
2469
2477
|| this ->function_type () != NULL
2470
2478
|| this ->map_type () != NULL )
2471
2479
return true ;
@@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type,
3597
3605
vals->push_back (Expression::make_unary (OPERATOR_AND, s, bloc));
3598
3606
}
3599
3607
3600
- bool use_direct_iface_stub =
3601
- this ->points_to () != NULL
3602
- && this ->points_to ()->is_direct_iface_type ()
3603
- && m->is_value_method ();
3608
+ // The direct_iface_stub dereferences the value stored in the
3609
+ // interface when calling the method.
3610
+ //
3611
+ // We need this for a value method if this type is a pointer to a
3612
+ // direct-iface type. For example, if we have "type C chan int" and M
3613
+ // is a value method on C, then since a channel is a direct-iface type
3614
+ // M expects a value of type C. We are generating the method table
3615
+ // for *C, so the value stored in the interface is *C. We have to
3616
+ // call the direct-iface stub to dereference *C to get C to pass to M.
3617
+ //
3618
+ // We also need this for a pointer method if the pointer itself is not
3619
+ // a direct-iface type, as arises for notinheap types. In this case
3620
+ // we have "type NIH ..." where NIH is go:notinheap. Since NIH is
3621
+ // notinheap, *NIH is a pointer type that is not a direct-iface type,
3622
+ // so the value stored in the interface is actually **NIH. The method
3623
+ // expects *NIH, so we have to call the direct-iface stub to
3624
+ // dereference **NIH to get *NIH to pass to M. (This case doesn't
3625
+ // arise for value methods because pointer types can't have methods,
3626
+ // so there is no such thing as a value method for type *NIH.)
3627
+
3628
+ bool use_direct_iface_stub = false ;
3629
+ if (m->is_value_method ()
3630
+ && this ->points_to () != NULL
3631
+ && this ->points_to ()->is_direct_iface_type ())
3632
+ use_direct_iface_stub = true ;
3633
+ if (!m->is_value_method ()
3634
+ && this ->points_to () != NULL
3635
+ && !this ->is_direct_iface_type ())
3636
+ use_direct_iface_stub = true ;
3637
+
3604
3638
Named_object* no = (use_direct_iface_stub
3605
3639
? m->iface_stub_object ()
3606
3640
: (m->needs_stub_method ()
@@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update()
10902
10936
return ret;
10903
10937
}
10904
10938
10939
+ // Return whether this type is permitted in the heap.
10940
+ bool
10941
+ Named_type::do_in_heap () const
10942
+ {
10943
+ if (!this ->in_heap_ )
10944
+ return false ;
10945
+ if (this ->seen_ )
10946
+ return true ;
10947
+ this ->seen_ = true ;
10948
+ bool ret = this ->type_ ->in_heap ();
10949
+ this ->seen_ = false ;
10950
+ return ret;
10951
+ }
10952
+
10905
10953
// Return a hash code. This is used for method lookup. We simply
10906
10954
// hash on the name itself.
10907
10955
@@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location,
11434
11482
*all_methods = NULL ;
11435
11483
}
11436
11484
Type::build_stub_methods (gogo, type, *all_methods, location);
11437
- if (type->is_direct_iface_type ())
11485
+ if (type->is_direct_iface_type () || !type-> in_heap () )
11438
11486
Type::build_direct_iface_stub_methods (gogo, type, *all_methods, location);
11439
11487
}
11440
11488
@@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type,
11814
11862
if (methods == NULL )
11815
11863
return ;
11816
11864
11865
+ bool is_direct_iface = type->is_direct_iface_type ();
11866
+ bool in_heap = type->in_heap ();
11817
11867
for (Methods::const_iterator p = methods->begin ();
11818
11868
p != methods->end ();
11819
11869
++p)
11820
11870
{
11821
11871
Method* m = p->second ;
11822
- if (!m->is_value_method ())
11872
+
11873
+ // We need a direct-iface stub for a value method for a
11874
+ // direct-iface type, and for a pointer method for a not-in-heap
11875
+ // type.
11876
+ bool need_stub = false ;
11877
+ if (is_direct_iface && m->is_value_method ())
11878
+ need_stub = true ;
11879
+ if (!in_heap && !m->is_value_method ())
11880
+ need_stub = true ;
11881
+ if (!need_stub)
11823
11882
continue ;
11824
11883
11825
11884
Type* receiver_type = const_cast <Type*>(type);
0 commit comments