mirror of
https://github.com/golang/go
synced 2024-11-21 19:24:45 -07:00
gc: ... changes
R=ken2, ken3 CC=golang-dev https://golang.org/cl/2208047
This commit is contained in:
parent
6cf1a34402
commit
75dd8fdb34
@ -68,7 +68,7 @@ static void fixlbrace(int);
|
|||||||
|
|
||||||
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
|
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
|
||||||
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
|
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
|
||||||
%type <list> oexpr_list oexpr_or_type_list_ocomma caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
|
%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
|
||||||
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
|
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
|
||||||
%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
|
%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
|
||||||
|
|
||||||
@ -808,11 +808,21 @@ uexpr:
|
|||||||
* can be preceded by 'defer' and 'go'
|
* can be preceded by 'defer' and 'go'
|
||||||
*/
|
*/
|
||||||
pseudocall:
|
pseudocall:
|
||||||
pexpr '(' oexpr_or_type_list_ocomma ')'
|
pexpr '(' ')'
|
||||||
|
{
|
||||||
|
$$ = nod(OCALL, $1, N);
|
||||||
|
}
|
||||||
|
| pexpr '(' expr_or_type_list ocomma ')'
|
||||||
{
|
{
|
||||||
$$ = nod(OCALL, $1, N);
|
$$ = nod(OCALL, $1, N);
|
||||||
$$->list = $3;
|
$$->list = $3;
|
||||||
}
|
}
|
||||||
|
| pexpr '(' expr_or_type_list LDDD ocomma ')'
|
||||||
|
{
|
||||||
|
$$ = nod(OCALL, $1, N);
|
||||||
|
$$->list = $3;
|
||||||
|
$$->isddd = 1;
|
||||||
|
}
|
||||||
|
|
||||||
pexpr_no_paren:
|
pexpr_no_paren:
|
||||||
LLITERAL
|
LLITERAL
|
||||||
@ -1583,12 +1593,6 @@ oexpr_list:
|
|||||||
}
|
}
|
||||||
| expr_list
|
| expr_list
|
||||||
|
|
||||||
oexpr_or_type_list_ocomma:
|
|
||||||
{
|
|
||||||
$$ = nil;
|
|
||||||
}
|
|
||||||
| expr_or_type_list ocomma
|
|
||||||
|
|
||||||
osimple_stmt:
|
osimple_stmt:
|
||||||
{
|
{
|
||||||
$$ = N;
|
$$ = N;
|
||||||
|
@ -271,7 +271,6 @@ setlineno(Node *n)
|
|||||||
case OTYPE:
|
case OTYPE:
|
||||||
case OPACK:
|
case OPACK:
|
||||||
case OLITERAL:
|
case OLITERAL:
|
||||||
case ONONAME:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lineno = n->lineno;
|
lineno = n->lineno;
|
||||||
@ -3033,11 +3032,14 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
|
|||||||
Node *this, *fn, *call, *n, *t, *pad;
|
Node *this, *fn, *call, *n, *t, *pad;
|
||||||
NodeList *l, *args, *in, *out;
|
NodeList *l, *args, *in, *out;
|
||||||
Type *tpad;
|
Type *tpad;
|
||||||
|
int isddd;
|
||||||
|
|
||||||
if(debug['r'])
|
if(debug['r'])
|
||||||
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
|
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
|
||||||
rcvr, method, newnam);
|
rcvr, method, newnam);
|
||||||
|
|
||||||
|
lineno = 1; // less confusing than end of input
|
||||||
|
|
||||||
dclcontext = PEXTERN;
|
dclcontext = PEXTERN;
|
||||||
markdcl();
|
markdcl();
|
||||||
|
|
||||||
@ -3069,12 +3071,16 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
|
|||||||
|
|
||||||
// arg list
|
// arg list
|
||||||
args = nil;
|
args = nil;
|
||||||
for(l=in; l; l=l->next)
|
isddd = 0;
|
||||||
|
for(l=in; l; l=l->next) {
|
||||||
args = list(args, l->n->left);
|
args = list(args, l->n->left);
|
||||||
|
isddd = l->n->left->isddd;
|
||||||
|
}
|
||||||
|
|
||||||
// generate call
|
// generate call
|
||||||
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
|
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
|
||||||
call->list = args;
|
call->list = args;
|
||||||
|
call->isddd = isddd;
|
||||||
fn->nbody = list1(call);
|
fn->nbody = list1(call);
|
||||||
if(method->type->outtuple > 0) {
|
if(method->type->outtuple > 0) {
|
||||||
n = nod(ORETURN, N, N);
|
n = nod(ORETURN, N, N);
|
||||||
|
@ -17,7 +17,7 @@ static void implicitstar(Node**);
|
|||||||
static int onearg(Node*, char*, ...);
|
static int onearg(Node*, char*, ...);
|
||||||
static int twoarg(Node*);
|
static int twoarg(Node*);
|
||||||
static int lookdot(Node*, Type*, int);
|
static int lookdot(Node*, Type*, int);
|
||||||
static void typecheckaste(int, Type*, NodeList*, char*);
|
static void typecheckaste(int, int, Type*, NodeList*, char*);
|
||||||
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
|
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
|
||||||
static int nokeys(NodeList*);
|
static int nokeys(NodeList*);
|
||||||
static void typecheckcomplit(Node**);
|
static void typecheckcomplit(Node**);
|
||||||
@ -716,12 +716,16 @@ reswitch:
|
|||||||
case OCALL:
|
case OCALL:
|
||||||
l = n->left;
|
l = n->left;
|
||||||
if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
|
if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
|
||||||
|
if(n->isddd)
|
||||||
|
yyerror("invalid use of ... with builtin %#N", l);
|
||||||
n = r;
|
n = r;
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
}
|
}
|
||||||
typecheck(&n->left, Erv | Etype | Ecall);
|
typecheck(&n->left, Erv | Etype | Ecall);
|
||||||
l = n->left;
|
l = n->left;
|
||||||
if(l->op == ONAME && l->etype != 0) {
|
if(l->op == ONAME && l->etype != 0) {
|
||||||
|
if(n->isddd)
|
||||||
|
yyerror("invalid use of ... with builtin %#N", l);
|
||||||
// builtin: OLEN, OCAP, etc.
|
// builtin: OLEN, OCAP, etc.
|
||||||
n->op = l->etype;
|
n->op = l->etype;
|
||||||
n->left = n->right;
|
n->left = n->right;
|
||||||
@ -731,6 +735,8 @@ reswitch:
|
|||||||
defaultlit(&n->left, T);
|
defaultlit(&n->left, T);
|
||||||
l = n->left;
|
l = n->left;
|
||||||
if(l->op == OTYPE) {
|
if(l->op == OTYPE) {
|
||||||
|
if(n->isddd)
|
||||||
|
yyerror("invalid use of ... in type conversion", l);
|
||||||
// pick off before type-checking arguments
|
// pick off before type-checking arguments
|
||||||
ok |= Erv;
|
ok |= Erv;
|
||||||
// turn CALL(type, arg) into CONV(arg) w/ type
|
// turn CALL(type, arg) into CONV(arg) w/ type
|
||||||
@ -757,7 +763,7 @@ reswitch:
|
|||||||
|
|
||||||
case ODOTMETH:
|
case ODOTMETH:
|
||||||
n->op = OCALLMETH;
|
n->op = OCALLMETH;
|
||||||
typecheckaste(OCALL, getthisx(t), list1(l->left), "method receiver");
|
typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -768,7 +774,7 @@ reswitch:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
typecheckaste(OCALL, getinargx(t), n->list, "function argument");
|
typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument");
|
||||||
ok |= Etop;
|
ok |= Etop;
|
||||||
if(t->outtuple == 0)
|
if(t->outtuple == 0)
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -1160,7 +1166,7 @@ reswitch:
|
|||||||
}
|
}
|
||||||
if(curfn->type->outnamed && n->list == nil)
|
if(curfn->type->outnamed && n->list == nil)
|
||||||
goto ret;
|
goto ret;
|
||||||
typecheckaste(ORETURN, getoutargx(curfn->type), n->list, "return argument");
|
typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument");
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
case OSELECT:
|
case OSELECT:
|
||||||
@ -1451,7 +1457,7 @@ nokeys(NodeList *l)
|
|||||||
* typecheck assignment: type list = expression list
|
* typecheck assignment: type list = expression list
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
|
||||||
{
|
{
|
||||||
Type *t, *tl, *tn;
|
Type *t, *tl, *tn;
|
||||||
Node *n;
|
Node *n;
|
||||||
@ -1465,7 +1471,6 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
|||||||
|
|
||||||
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
|
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
|
||||||
if(n->type->etype == TSTRUCT && n->type->funarg) {
|
if(n->type->etype == TSTRUCT && n->type->funarg) {
|
||||||
setlineno(n);
|
|
||||||
tn = n->type->type;
|
tn = n->type->type;
|
||||||
for(tl=tstruct->type; tl; tl=tl->down) {
|
for(tl=tstruct->type; tl; tl=tl->down) {
|
||||||
if(tl->isddd) {
|
if(tl->isddd) {
|
||||||
@ -1474,29 +1479,34 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
|||||||
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
|
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(tn == T) {
|
if(tn == T)
|
||||||
yyerror("not enough arguments to %#O", op);
|
goto notenough;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if(assignop(tn->type, tl->type, &why) == 0)
|
if(assignop(tn->type, tl->type, &why) == 0)
|
||||||
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
|
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
|
||||||
tn = tn->down;
|
tn = tn->down;
|
||||||
}
|
}
|
||||||
if(tn != T)
|
if(tn != T)
|
||||||
yyerror("too many arguments to %#O", op);
|
goto toomany;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(tl=tstruct->type; tl; tl=tl->down) {
|
for(tl=tstruct->type; tl; tl=tl->down) {
|
||||||
t = tl->type;
|
t = tl->type;
|
||||||
if(tl->isddd) {
|
if(tl->isddd) {
|
||||||
if(nl != nil && nl->n->isddd && !eqtype(nl->n->type, t)) {
|
if(nl != nil && nl->n->isddd && !isddd) {
|
||||||
// TODO(rsc): This is not actually illegal but will
|
// TODO(rsc): This is not actually illegal, but it will help catch bugs.
|
||||||
// help catch bugs.
|
yyerror("to pass '%#N' as ...%T, use '%#N...'", nl->n, t->type, nl->n);
|
||||||
yyerror("cannot pass %+N as %T (... mismatch)", nl->n, tl);
|
isddd = 1;
|
||||||
}
|
}
|
||||||
if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
|
if(isddd) {
|
||||||
|
if(nl == nil)
|
||||||
|
goto notenough;
|
||||||
|
if(nl->next != nil)
|
||||||
|
goto toomany;
|
||||||
|
if(assignop(nl->n->type, t, &why) == 0)
|
||||||
|
yyerror("ddd cannot use %+N as type %T in %s%s", nl->n, t, desc, why);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
for(; nl; nl=nl->next) {
|
for(; nl; nl=nl->next) {
|
||||||
setlineno(nl->n);
|
setlineno(nl->n);
|
||||||
defaultlit(&nl->n, t->type);
|
defaultlit(&nl->n, t->type);
|
||||||
@ -1505,23 +1515,30 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
|||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(nl == nil) {
|
if(nl == nil)
|
||||||
yyerror("not enough arguments to %#O", op);
|
goto notenough;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
n = nl->n;
|
n = nl->n;
|
||||||
setlineno(nl->n);
|
setlineno(n);
|
||||||
if(n->type != T)
|
if(n->type != T)
|
||||||
nl->n = assignconv(n, t, desc);
|
nl->n = assignconv(n, t, desc);
|
||||||
nl = nl->next;
|
nl = nl->next;
|
||||||
}
|
}
|
||||||
if(nl != nil) {
|
if(nl != nil)
|
||||||
yyerror("too many arguments to %#O", op);
|
goto toomany;
|
||||||
goto out;
|
if(isddd)
|
||||||
}
|
yyerror("invalid use of ... in %#O", op);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lineno = lno;
|
lineno = lno;
|
||||||
|
return;
|
||||||
|
|
||||||
|
notenough:
|
||||||
|
yyerror("not enough arguments to %#O", op);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
toomany:
|
||||||
|
yyerror("too many arguments to %#O", op);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1695,11 +1712,13 @@ typecheckcomplit(Node **np)
|
|||||||
NodeList *ll;
|
NodeList *ll;
|
||||||
Type *t, *f;
|
Type *t, *f;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
int32 lno;
|
||||||
|
|
||||||
n = *np;
|
n = *np;
|
||||||
|
lno = lineno;
|
||||||
|
|
||||||
memset(hash, 0, sizeof hash);
|
memset(hash, 0, sizeof hash);
|
||||||
|
setlineno(n->right);
|
||||||
l = typecheck(&n->right /* sic */, Etype);
|
l = typecheck(&n->right /* sic */, Etype);
|
||||||
if((t = l->type) == T)
|
if((t = l->type) == T)
|
||||||
goto error;
|
goto error;
|
||||||
@ -1715,6 +1734,7 @@ typecheckcomplit(Node **np)
|
|||||||
i = 0;
|
i = 0;
|
||||||
for(ll=n->list; ll; ll=ll->next) {
|
for(ll=n->list; ll; ll=ll->next) {
|
||||||
l = ll->n;
|
l = ll->n;
|
||||||
|
setlineno(l);
|
||||||
if(l->op == OKEY) {
|
if(l->op == OKEY) {
|
||||||
typecheck(&l->left, Erv);
|
typecheck(&l->left, Erv);
|
||||||
evconst(l->left);
|
evconst(l->left);
|
||||||
@ -1756,6 +1776,7 @@ typecheckcomplit(Node **np)
|
|||||||
case TMAP:
|
case TMAP:
|
||||||
for(ll=n->list; ll; ll=ll->next) {
|
for(ll=n->list; ll; ll=ll->next) {
|
||||||
l = ll->n;
|
l = ll->n;
|
||||||
|
setlineno(l);
|
||||||
if(l->op != OKEY) {
|
if(l->op != OKEY) {
|
||||||
typecheck(&ll->n, Erv);
|
typecheck(&ll->n, Erv);
|
||||||
yyerror("missing key in map literal");
|
yyerror("missing key in map literal");
|
||||||
@ -1778,6 +1799,7 @@ typecheckcomplit(Node **np)
|
|||||||
// simple list of variables
|
// simple list of variables
|
||||||
f = t->type;
|
f = t->type;
|
||||||
for(ll=n->list; ll; ll=ll->next) {
|
for(ll=n->list; ll; ll=ll->next) {
|
||||||
|
setlineno(ll->n);
|
||||||
typecheck(&ll->n, Erv);
|
typecheck(&ll->n, Erv);
|
||||||
if(f == nil) {
|
if(f == nil) {
|
||||||
if(!bad++)
|
if(!bad++)
|
||||||
@ -1798,6 +1820,7 @@ typecheckcomplit(Node **np)
|
|||||||
// keyed list
|
// keyed list
|
||||||
for(ll=n->list; ll; ll=ll->next) {
|
for(ll=n->list; ll; ll=ll->next) {
|
||||||
l = ll->n;
|
l = ll->n;
|
||||||
|
setlineno(l);
|
||||||
if(l->op != OKEY) {
|
if(l->op != OKEY) {
|
||||||
if(!bad++)
|
if(!bad++)
|
||||||
yyerror("mixture of field:value and value initializers");
|
yyerror("mixture of field:value and value initializers");
|
||||||
@ -1836,11 +1859,13 @@ typecheckcomplit(Node **np)
|
|||||||
n->type = t;
|
n->type = t;
|
||||||
|
|
||||||
*np = n;
|
*np = n;
|
||||||
|
lineno = lno;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
n->type = T;
|
n->type = T;
|
||||||
*np = n;
|
*np = n;
|
||||||
|
lineno = lno;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
19
test/ddd1.go
19
test/ddd1.go
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
func sum(args ...int) int { return 0 }
|
func sum(args ...int) int { return 0 }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -26,3 +28,20 @@ var (
|
|||||||
_ = funny(nil, nil)
|
_ = funny(nil, nil)
|
||||||
_ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
|
_ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func bad(args ...int) {
|
||||||
|
print(1, 2, args...) // ERROR "[.][.][.]"
|
||||||
|
println(args...) // ERROR "[.][.][.]"
|
||||||
|
ch := make(chan int)
|
||||||
|
close(ch...) // ERROR "[.][.][.]"
|
||||||
|
_ = len(args...) // ERROR "[.][.][.]"
|
||||||
|
_ = closed(ch...) // ERROR "[.][.][.]"
|
||||||
|
_ = new(int...) // ERROR "[.][.][.]"
|
||||||
|
n := 10
|
||||||
|
_ = make([]byte, n...) // ERROR "[.][.][.]"
|
||||||
|
// TODO(rsc): enable after gofmt bug is fixed
|
||||||
|
// _ = make([]byte, 10 ...) // error "[.][.][.]"
|
||||||
|
var x int
|
||||||
|
_ = unsafe.Pointer(&x...) // ERROR "[.][.][.]"
|
||||||
|
_ = unsafe.Sizeof(x...) // ERROR "[.][.][.]"
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user