Merge lp:~mwhudson/juju-core/gccgo-reflection-fun into lp:~go-bot/juju-core/trunk

Proposed by John A Meinel
Status: Rejected
Rejected by: John A Meinel
Proposed branch: lp:~mwhudson/juju-core/gccgo-reflection-fun
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 128 lines (+33/-7)
4 files modified
rpc/reflect_test.go (+3/-0)
rpc/rpc_test.go (+15/-4)
rpc/rpcreflect/type.go (+12/-2)
state/apiserver/root.go (+3/-1)
To merge this branch: bzr merge lp:~mwhudson/juju-core/gccgo-reflection-fun
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+195717@code.launchpad.net

Commit message

Change RPC methods to not return empty structs.
Empty structs cause gccgo to panic, so instead we use struct { _ bool } to ensure they are not empty.

Description of the change

This fixes the linked bug and makes attempting to return a structure fail. I expect this will confusingly break other parts of Juju...

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

Resubmitting seems to have sorted Launchpad out. Now on to review.

Revision history for this message
John A Meinel (jameinel) wrote :

67 +type newlyAvailableMethods struct {
68 + _ bool
69 +}

I think for each of these we probably want to explain why we're doing it, referencing the related bug.

Something like:
67 +type newlyAvailableMethods struct {
68 + _ bool // gccgo Reflect breaks on empty structs: https://bugs.launchpad.net/juju-core/+bug/1251076
69 +}

Just poke me when you feel this is ready to land. I'm happy with just some doc tweaks.

review: Approve
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

John A Meinel <email address hidden> writes:

> Review: Approve
>
> 67 +type newlyAvailableMethods struct {
> 68 + _ bool
> 69 +}
>
> I think for each of these we probably want to explain why we're doing it, referencing the related bug.
>
> Something like:
> 67 +type newlyAvailableMethods struct {
> 68 + _ bool // gccgo Reflect breaks on empty structs: https://bugs.launchpad.net/juju-core/+bug/1251076
> 69 +}
>
> Just poke me when you feel this is ready to land. I'm happy with just some doc tweaks.

I think this is fine to land now.

That said, there are other gccgo fixes required to make gccgo and juju
play nice together and we're going to be providing a PPA with this and
those other fixes in it for at least saucy... so maybe this doesn't
actually need to land at all? If this happens, I'm sorry for wasting
your time!

Revision history for this message
Go Bot (go-bot) wrote :

Attempt to merge into lp:juju-core failed due to conflicts:

text conflict in state/apiserver/root.go

Revision history for this message
Go Bot (go-bot) wrote :

Attempt to merge into lp:juju-core failed due to conflicts:

text conflict in state/apiserver/root.go

Revision history for this message
John A Meinel (jameinel) wrote :

I'm pretty sure we decided we don't need this after all, so marking it rejected.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

John A Meinel <email address hidden> writes:

> I'm pretty sure we decided we don't need this after all, so marking it rejected.

Yes indeed. Sorry for not withdrawing this when that became clear.

Unmerged revisions

2076. By Michael Hudson-Doyle

another workaround field

2075. By Michael Hudson-Doyle

add workaround fields

2074. By Michael Hudson-Doyle

discard methods taking or returning empty structures

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'rpc/reflect_test.go'
--- rpc/reflect_test.go 2013-09-23 10:06:47 +0000
+++ rpc/reflect_test.go 2013-11-19 07:42:22 +0000
@@ -28,6 +28,7 @@
28 "Discard1",28 "Discard1",
29 "Discard2",29 "Discard2",
30 "Discard3",30 "Discard3",
31 "Discard4",
31 })32 })
32 expect := map[string]reflect.Type{33 expect := map[string]reflect.Type{
33 "CallbackMethods": reflect.TypeOf(&CallbackMethods{}),34 "CallbackMethods": reflect.TypeOf(&CallbackMethods{}),
@@ -58,6 +59,8 @@
58 "Discard2",59 "Discard2",
59 "Discard3",60 "Discard3",
60 "Discard4",61 "Discard4",
62 "Discard5",
63 "Discard6",
61 })64 })
62 expect := map[string]*rpcreflect.ObjMethod{65 expect := map[string]*rpcreflect.ObjMethod{
63 "SliceArg": {66 "SliceArg": {
6467
=== modified file 'rpc/rpc_test.go'
--- rpc/rpc_test.go 2013-10-25 18:21:30 +0000
+++ rpc/rpc_test.go 2013-11-19 07:42:22 +0000
@@ -95,6 +95,8 @@
9595
96func (r *Root) Discard3(id string) int { return 0 }96func (r *Root) Discard3(id string) int { return 0 }
9797
98func (r *Root) Discard4(id string) (_ struct {}, _ error) { return }
99
98func (r *Root) CallbackMethods(string) (*CallbackMethods, error) {100func (r *Root) CallbackMethods(string) (*CallbackMethods, error) {
99 return &CallbackMethods{r}, nil101 return &CallbackMethods{r}, nil
100}102}
@@ -183,11 +185,16 @@
183185
184func (a *SimpleMethods) Discard1(int) {}186func (a *SimpleMethods) Discard1(int) {}
185187
186func (a *SimpleMethods) Discard2(struct{}, struct{}) {}188func (a *SimpleMethods) Discard2(struct{ _ bool }, struct{ _ bool }) {}
187189
188func (a *SimpleMethods) Discard3() int { return 0 }190func (a *SimpleMethods) Discard3() int { return 0 }
189191
190func (a *SimpleMethods) Discard4() (_, _ struct{}) { return }192func (a *SimpleMethods) Discard4() (_, _ struct{ _ bool }) { return }
193
194func (a *SimpleMethods) Discard5(struct {}) { return }
195
196func (a *SimpleMethods) Discard6() (_ struct {}) { return }
197
191198
192type DelayedMethods struct {199type DelayedMethods struct {
193 ready chan struct{}200 ready chan struct{}
@@ -243,13 +250,17 @@
243 a.r.conn.Serve(nil, nil)250 a.r.conn.Serve(nil, nil)
244}251}
245252
246type changedAPIRoot struct{}253type changedAPIRoot struct{
254 _ bool
255}
247256
248func (r *changedAPIRoot) NewlyAvailable(string) (newlyAvailableMethods, error) {257func (r *changedAPIRoot) NewlyAvailable(string) (newlyAvailableMethods, error) {
249 return newlyAvailableMethods{}, nil258 return newlyAvailableMethods{}, nil
250}259}
251260
252type newlyAvailableMethods struct{}261type newlyAvailableMethods struct {
262 _ bool
263}
253264
254func (newlyAvailableMethods) NewMethod() stringVal {265func (newlyAvailableMethods) NewMethod() stringVal {
255 return stringVal{"new method result"}266 return stringVal{"new method result"}
256267
=== modified file 'rpc/rpcreflect/type.go'
--- rpc/rpcreflect/type.go 2013-09-24 07:12:05 +0000
+++ rpc/rpcreflect/type.go 2013-11-19 07:42:22 +0000
@@ -130,6 +130,13 @@
130 return m.Name == "Kill" && m.Type.NumIn() == 1 && m.Type.NumOut() == 0130 return m.Name == "Kill" && m.Type.NumIn() == 1 && m.Type.NumOut() == 0
131}131}
132132
133func isEmptyStruct(t reflect.Type) bool {
134 // gccgo has a bug calling methods that take or return empty
135 // structs via reflection. See
136 // https://code.google.com/p/go/issues/detail?id=6761.
137 return t.Kind() == reflect.Struct && t.NumField() == 0
138}
139
133func newRootMethod(m reflect.Method) *RootMethod {140func newRootMethod(m reflect.Method) *RootMethod {
134 if m.PkgPath != "" {141 if m.PkgPath != "" {
135 return nil142 return nil
@@ -141,6 +148,9 @@
141 t.Out(1) != errorType {148 t.Out(1) != errorType {
142 return nil149 return nil
143 }150 }
151 if isEmptyStruct(t.Out(0)) {
152 return nil
153 }
144 f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {154 f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {
145 out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})155 out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})
146 if !out[1].IsNil() {156 if !out[1].IsNil() {
@@ -325,10 +335,10 @@
325 return nil335 return nil
326 }336 }
327 // The parameters and return value must be of struct type.337 // The parameters and return value must be of struct type.
328 if p.Params != nil && p.Params.Kind() != reflect.Struct {338 if p.Params != nil && (p.Params.Kind() != reflect.Struct || isEmptyStruct(p.Params)) {
329 return nil339 return nil
330 }340 }
331 if p.Result != nil && p.Result.Kind() != reflect.Struct {341 if p.Result != nil && (p.Result.Kind() != reflect.Struct || isEmptyStruct(p.Result)) {
332 return nil342 return nil
333 }343 }
334 return &p344 return &p
335345
=== modified file 'state/apiserver/root.go'
--- state/apiserver/root.go 2013-10-11 09:56:04 +0000
+++ state/apiserver/root.go 2013-11-19 07:42:22 +0000
@@ -233,7 +233,9 @@
233 return srvPinger{}, nil233 return srvPinger{}, nil
234}234}
235235
236type srvPinger struct{}236type srvPinger struct {
237 _ bool // see https://code.google.com/p/go/issues/detail?id=6761
238}
237239
238// Ping is a no-op used by client heartbeat monitor.240// Ping is a no-op used by client heartbeat monitor.
239func (r srvPinger) Ping() {}241func (r srvPinger) Ping() {}

Subscribers

People subscribed via source and target branches

to status/vote changes: