diff options
Diffstat (limited to 'src/cmd/gc/racewalk.c')
-rw-r--r-- | src/cmd/gc/racewalk.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c index 5d4f62e76..790c7efd7 100644 --- a/src/cmd/gc/racewalk.c +++ b/src/cmd/gc/racewalk.c @@ -23,6 +23,7 @@ static void racewalklist(NodeList *l, NodeList **init); static void racewalknode(Node **np, NodeList **init, int wr, int skip); static int callinstr(Node **n, NodeList **init, int wr, int skip); static Node* uintptraddr(Node *n); +static void makeaddable(Node *n); static Node* basenod(Node *n); static void foreach(Node *n, void(*f)(Node*, void*), void *c); static void hascallspred(Node *n, void *c); @@ -489,6 +490,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip) *np = n; } n = treecopy(n); + makeaddable(n); f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n)); *init = list(*init, f); return 1; @@ -496,6 +498,37 @@ callinstr(Node **np, NodeList **init, int wr, int skip) return 0; } +// makeaddable returns a node whose memory location is the +// same as n, but which is addressable in the Go language +// sense. +// This is different from functions like cheapexpr that may make +// a copy of their argument. +static void +makeaddable(Node *n) +{ + // The arguments to uintptraddr technically have an address but + // may not be addressable in the Go sense: for example, in the case + // of T(v).Field where T is a struct type and v is + // an addressable value. + switch(n->op) { + case OINDEX: + if(isfixedarray(n->left->type)) + makeaddable(n->left); + break; + case ODOT: + case OXDOT: + // Turn T(v).Field into v.Field + if(n->left->op == OCONVNOP) + n->left = n->left->left; + makeaddable(n->left); + break; + case ODOTPTR: + default: + // nothing to do + break; + } +} + static Node* uintptraddr(Node *n) { |