From fd178d6a7e62796c71258ba155b957616be86ff4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 5 Feb 2013 07:00:38 -0500 Subject: [PATCH] cmd/gc: add way to specify 'noescape' for extern funcs A new comment directive //go:noescape instructs the compiler that the following external (no body) func declaration should be treated as if none of its arguments escape to the heap. Fixes #4099. R=golang-dev, dave, minux.ma, daniel.morsing, remyoudompheng, adg, agl, iant CC=golang-dev https://golang.org/cl/7289048 --- src/cmd/gc/doc.go | 27 +++- src/cmd/gc/esc.c | 19 ++- src/cmd/gc/go.h | 2 + src/cmd/gc/go.y | 4 + src/cmd/gc/lex.c | 30 ++-- src/cmd/gc/y.tab.c | 280 ++++++++++++++++++------------------ test/escape2.go | 26 ++++ test/fixedbugs/issue4099.go | 26 ++++ 8 files changed, 263 insertions(+), 151 deletions(-) create mode 100644 test/fixedbugs/issue4099.go diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go index 78bffc8ecb3..c2eff88f6e1 100644 --- a/src/cmd/gc/doc.go +++ b/src/cmd/gc/doc.go @@ -25,6 +25,8 @@ other packages. It is therefore not necessary when compiling client C of package P to read the files of P's dependencies, only the compiled output of P. +Command Line + Usage: go tool 6g [flags] file... The specified files must be Go source files and all part of the same package. @@ -48,7 +50,7 @@ Flags: disable optimizations -S write assembly language text to standard output (code only) - -SS + -S -S write assembly language text to standard output (code and data) -u disallow importing packages not marked as safe @@ -60,5 +62,28 @@ Flags: There are also a number of debugging flags; run the command with no arguments to get a usage message. +Compiler Directives + +The compiler accepts two compiler directives in the form of // comments at the +beginning of a line. To distinguish them from non-directive comments, the directives +require no space between the slashes and the name of the directive. However, since +they are comments, tools unaware of the directive convention or of a particular +directive can skip over a directive like any other comment. + + //line path/to/file:linenumber + +The //line directive specifies that the source line that follows should be recorded +as having come from the given file path and line number. Successive lines are +recorded using increasing line numbers, until the next directive. This directive +typically appears in machine-generated code, so that compilers and debuggers +will show lines in the original input to the generator. + + //go:noescape + +The //go:noescape directive specifies that the next declaration in the file, which +must be a func without a body (meaning that it has an implementation not written +in Go) does not allow any of the pointers passed as arguments to escape into the +heap or into the values returned from the function. This information can be used as +during the compiler's escape analysis of Go code calling the function. */ package documentation diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index 42e414ca271..1b065d433e8 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -330,7 +330,10 @@ escfunc(EscState *e, Node *func) case PPARAM: if(ll->n->type && !haspointers(ll->n->type)) break; - ll->n->esc = EscNone; // prime for escflood later + if(curfn->nbody == nil && !curfn->noescape) + ll->n->esc = EscHeap; + else + ll->n->esc = EscNone; // prime for escflood later e->noesc = list(e->noesc, ll->n); ll->n->escloopdepth = 1; break; @@ -1109,13 +1112,21 @@ esctag(EscState *e, Node *func) { Node *savefn; NodeList *ll; - + Type *t; + USED(e); func->esc = EscFuncTagged; - // External functions must be assumed unsafe. - if(func->nbody == nil) + // External functions are assumed unsafe, + // unless //go:noescape is given before the declaration. + if(func->nbody == nil) { + if(func->noescape) { + for(t=getinargx(func->type)->type; t; t=t->down) + if(haspointers(t->type)) + t->note = mktag(EscNone); + } return; + } savefn = curfn; curfn = func; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index e0f0dae8ee9..886a6f78673 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -253,6 +253,7 @@ struct Node uchar colas; // OAS resulting from := uchar diag; // already printed error about this uchar esc; // EscXXX + uchar noescape; // func arguments do not escape uchar funcdepth; uchar builtin; // built-in name, like len or close uchar walkdef; @@ -943,6 +944,7 @@ EXTERN int compiling_wrappers; EXTERN int pure_go; EXTERN int flag_race; EXTERN int flag_largemodel; +EXTERN int noescape; EXTERN int nointerface; EXTERN int fieldtrack_enabled; diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 5f410f308b9..794961e8e7c 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1277,8 +1277,11 @@ xfndcl: $$ = $2; if($$ == N) break; + if(noescape && $3 != nil) + yyerror("can only use //go:noescape with external func implementations"); $$->nbody = $3; $$->endlineno = lineno; + $$->noescape = noescape; funcbody($$); } @@ -1462,6 +1465,7 @@ xdcl_list: if(nsyntaxerrors == 0) testdclstack(); nointerface = 0; + noescape = 0; } vardcl_list: diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 9a017684931..68ae6864d07 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -1436,7 +1436,7 @@ getlinepragma(void) Hist *h; c = getr(); - if(c == 'g' && fieldtrack_enabled) + if(c == 'g') goto go; if(c != 'l') goto out; @@ -1491,18 +1491,32 @@ getlinepragma(void) goto out; go: - for(i=1; i<11; i++) { - c = getr(); - if(c != "go:nointerface"[i]) - goto out; - } - nointerface = 1; + cp = lexbuf; + ep = lexbuf+sizeof(lexbuf)-5; + *cp++ = 'g'; // already read for(;;) { c = getr(); - if(c == EOF || c == '\n') + if(c == EOF || c >= Runeself) + goto out; + if(c == '\n') break; + if(cp < ep) + *cp++ = c; } + *cp = 0; + ep = strchr(lexbuf, ' '); + if(ep != nil) + *ep = 0; + if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) { + nointerface = 1; + goto out; + } + if(strcmp(lexbuf, "go:noescape") == 0) { + noescape = 1; + goto out; + } + out: return c; } diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c index a4e46884526..75175455eae 100644 --- a/src/cmd/gc/y.tab.c +++ b/src/cmd/gc/y.tab.c @@ -676,21 +676,21 @@ static const yytype_uint16 yyrline[] = 1158, 1159, 1160, 1161, 1167, 1168, 1169, 1170, 1171, 1177, 1178, 1181, 1184, 1185, 1186, 1187, 1188, 1191, 1192, 1205, 1209, 1214, 1219, 1224, 1228, 1229, 1232, 1238, 1245, 1251, - 1258, 1264, 1275, 1286, 1315, 1355, 1380, 1398, 1407, 1410, - 1418, 1422, 1426, 1433, 1439, 1444, 1456, 1459, 1468, 1469, - 1475, 1476, 1482, 1486, 1492, 1493, 1499, 1503, 1509, 1532, - 1537, 1543, 1549, 1556, 1565, 1574, 1589, 1595, 1600, 1604, - 1611, 1624, 1625, 1631, 1637, 1640, 1644, 1650, 1653, 1662, - 1665, 1666, 1670, 1671, 1677, 1678, 1679, 1680, 1681, 1683, - 1682, 1697, 1702, 1706, 1710, 1714, 1718, 1723, 1742, 1748, - 1756, 1760, 1766, 1770, 1776, 1780, 1786, 1790, 1799, 1803, - 1807, 1811, 1817, 1820, 1828, 1829, 1831, 1832, 1835, 1838, - 1841, 1844, 1847, 1850, 1853, 1856, 1859, 1862, 1865, 1868, - 1871, 1874, 1880, 1884, 1888, 1892, 1896, 1900, 1920, 1927, - 1938, 1939, 1940, 1943, 1944, 1947, 1951, 1961, 1965, 1969, - 1973, 1977, 1981, 1985, 1991, 1997, 2005, 2013, 2019, 2026, - 2042, 2060, 2064, 2070, 2073, 2076, 2080, 2090, 2094, 2109, - 2117, 2118, 2130, 2131, 2134, 2138, 2144, 2148, 2154, 2158 + 1258, 1264, 1275, 1289, 1318, 1358, 1383, 1401, 1410, 1413, + 1421, 1425, 1429, 1436, 1442, 1447, 1459, 1462, 1472, 1473, + 1479, 1480, 1486, 1490, 1496, 1497, 1503, 1507, 1513, 1536, + 1541, 1547, 1553, 1560, 1569, 1578, 1593, 1599, 1604, 1608, + 1615, 1628, 1629, 1635, 1641, 1644, 1648, 1654, 1657, 1666, + 1669, 1670, 1674, 1675, 1681, 1682, 1683, 1684, 1685, 1687, + 1686, 1701, 1706, 1710, 1714, 1718, 1722, 1727, 1746, 1752, + 1760, 1764, 1770, 1774, 1780, 1784, 1790, 1794, 1803, 1807, + 1811, 1815, 1821, 1824, 1832, 1833, 1835, 1836, 1839, 1842, + 1845, 1848, 1851, 1854, 1857, 1860, 1863, 1866, 1869, 1872, + 1875, 1878, 1884, 1888, 1892, 1896, 1900, 1904, 1924, 1931, + 1942, 1943, 1944, 1947, 1948, 1951, 1955, 1965, 1969, 1973, + 1977, 1981, 1985, 1989, 1995, 2001, 2009, 2017, 2023, 2030, + 2046, 2064, 2068, 2074, 2077, 2080, 2084, 2094, 2098, 2113, + 2121, 2122, 2134, 2135, 2138, 2142, 2148, 2152, 2158, 2162 }; #endif @@ -3767,14 +3767,17 @@ yyreduce: (yyval.node) = (yyvsp[(2) - (3)].node); if((yyval.node) == N) break; + if(noescape && (yyvsp[(3) - (3)].list) != nil) + yyerror("can only use //go:noescape with external func implementations"); (yyval.node)->nbody = (yyvsp[(3) - (3)].list); (yyval.node)->endlineno = lineno; + (yyval.node)->noescape = noescape; funcbody((yyval.node)); } break; case 203: -#line 1287 "go.y" +#line 1290 "go.y" { Node *t; @@ -3806,7 +3809,7 @@ yyreduce: break; case 204: -#line 1316 "go.y" +#line 1319 "go.y" { Node *rcvr, *t; @@ -3847,7 +3850,7 @@ yyreduce: break; case 205: -#line 1356 "go.y" +#line 1359 "go.y" { Sym *s; Type *t; @@ -3875,7 +3878,7 @@ yyreduce: break; case 206: -#line 1381 "go.y" +#line 1384 "go.y" { (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); @@ -3894,7 +3897,7 @@ yyreduce: break; case 207: -#line 1399 "go.y" +#line 1402 "go.y" { (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); (yyval.node) = nod(OTFUNC, N, N); @@ -3904,14 +3907,14 @@ yyreduce: break; case 208: -#line 1407 "go.y" +#line 1410 "go.y" { (yyval.list) = nil; } break; case 209: -#line 1411 "go.y" +#line 1414 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); if((yyval.list) == nil) @@ -3920,21 +3923,21 @@ yyreduce: break; case 210: -#line 1419 "go.y" +#line 1422 "go.y" { (yyval.list) = nil; } break; case 211: -#line 1423 "go.y" +#line 1426 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); } break; case 212: -#line 1427 "go.y" +#line 1430 "go.y" { (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); (yyval.list) = (yyvsp[(2) - (3)].list); @@ -3942,14 +3945,14 @@ yyreduce: break; case 213: -#line 1434 "go.y" +#line 1437 "go.y" { closurehdr((yyvsp[(1) - (1)].node)); } break; case 214: -#line 1440 "go.y" +#line 1443 "go.y" { (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); fixlbrace((yyvsp[(2) - (4)].i)); @@ -3957,80 +3960,81 @@ yyreduce: break; case 215: -#line 1445 "go.y" +#line 1448 "go.y" { (yyval.node) = closurebody(nil); } break; case 216: -#line 1456 "go.y" +#line 1459 "go.y" { (yyval.list) = nil; } break; case 217: -#line 1460 "go.y" +#line 1463 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); if(nsyntaxerrors == 0) testdclstack(); nointerface = 0; + noescape = 0; } break; case 219: -#line 1470 "go.y" +#line 1474 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 221: -#line 1477 "go.y" +#line 1481 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 222: -#line 1483 "go.y" +#line 1487 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 223: -#line 1487 "go.y" +#line 1491 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 225: -#line 1494 "go.y" +#line 1498 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 226: -#line 1500 "go.y" +#line 1504 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 227: -#line 1504 "go.y" +#line 1508 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 228: -#line 1510 "go.y" +#line 1514 "go.y" { NodeList *l; @@ -4056,7 +4060,7 @@ yyreduce: break; case 229: -#line 1533 "go.y" +#line 1537 "go.y" { (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); (yyval.list) = list1((yyvsp[(1) - (2)].node)); @@ -4064,7 +4068,7 @@ yyreduce: break; case 230: -#line 1538 "go.y" +#line 1542 "go.y" { (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); (yyval.list) = list1((yyvsp[(2) - (4)].node)); @@ -4073,7 +4077,7 @@ yyreduce: break; case 231: -#line 1544 "go.y" +#line 1548 "go.y" { (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); @@ -4082,7 +4086,7 @@ yyreduce: break; case 232: -#line 1550 "go.y" +#line 1554 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4092,7 +4096,7 @@ yyreduce: break; case 233: -#line 1557 "go.y" +#line 1561 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4102,7 +4106,7 @@ yyreduce: break; case 234: -#line 1566 "go.y" +#line 1570 "go.y" { Node *n; @@ -4114,7 +4118,7 @@ yyreduce: break; case 235: -#line 1575 "go.y" +#line 1579 "go.y" { Pkg *pkg; @@ -4130,14 +4134,14 @@ yyreduce: break; case 236: -#line 1590 "go.y" +#line 1594 "go.y" { (yyval.node) = embedded((yyvsp[(1) - (1)].sym)); } break; case 237: -#line 1596 "go.y" +#line 1600 "go.y" { (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ifacedcl((yyval.node)); @@ -4145,14 +4149,14 @@ yyreduce: break; case 238: -#line 1601 "go.y" +#line 1605 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); } break; case 239: -#line 1605 "go.y" +#line 1609 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); yyerror("cannot parenthesize embedded type"); @@ -4160,7 +4164,7 @@ yyreduce: break; case 240: -#line 1612 "go.y" +#line 1616 "go.y" { // without func keyword (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); @@ -4171,7 +4175,7 @@ yyreduce: break; case 242: -#line 1626 "go.y" +#line 1630 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4180,7 +4184,7 @@ yyreduce: break; case 243: -#line 1632 "go.y" +#line 1636 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4189,56 +4193,56 @@ yyreduce: break; case 245: -#line 1641 "go.y" +#line 1645 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 246: -#line 1645 "go.y" +#line 1649 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 247: -#line 1650 "go.y" +#line 1654 "go.y" { (yyval.list) = nil; } break; case 248: -#line 1654 "go.y" +#line 1658 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 249: -#line 1662 "go.y" +#line 1666 "go.y" { (yyval.node) = N; } break; case 251: -#line 1667 "go.y" +#line 1671 "go.y" { (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); } break; case 253: -#line 1672 "go.y" +#line 1676 "go.y" { (yyval.node) = N; } break; case 259: -#line 1683 "go.y" +#line 1687 "go.y" { (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions @@ -4246,7 +4250,7 @@ yyreduce: break; case 260: -#line 1688 "go.y" +#line 1692 "go.y" { NodeList *l; @@ -4259,7 +4263,7 @@ yyreduce: break; case 261: -#line 1698 "go.y" +#line 1702 "go.y" { // will be converted to OFALL (yyval.node) = nod(OXFALL, N, N); @@ -4267,35 +4271,35 @@ yyreduce: break; case 262: -#line 1703 "go.y" +#line 1707 "go.y" { (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); } break; case 263: -#line 1707 "go.y" +#line 1711 "go.y" { (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); } break; case 264: -#line 1711 "go.y" +#line 1715 "go.y" { (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); } break; case 265: -#line 1715 "go.y" +#line 1719 "go.y" { (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); } break; case 266: -#line 1719 "go.y" +#line 1723 "go.y" { (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); (yyval.node)->sym = dclstack; // context, for goto restrictions @@ -4303,7 +4307,7 @@ yyreduce: break; case 267: -#line 1724 "go.y" +#line 1728 "go.y" { (yyval.node) = nod(ORETURN, N, N); (yyval.node)->list = (yyvsp[(2) - (2)].list); @@ -4323,7 +4327,7 @@ yyreduce: break; case 268: -#line 1743 "go.y" +#line 1747 "go.y" { (yyval.list) = nil; if((yyvsp[(1) - (1)].node) != N) @@ -4332,7 +4336,7 @@ yyreduce: break; case 269: -#line 1749 "go.y" +#line 1753 "go.y" { (yyval.list) = (yyvsp[(1) - (3)].list); if((yyvsp[(3) - (3)].node) != N) @@ -4341,189 +4345,189 @@ yyreduce: break; case 270: -#line 1757 "go.y" +#line 1761 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 271: -#line 1761 "go.y" +#line 1765 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 272: -#line 1767 "go.y" +#line 1771 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 273: -#line 1771 "go.y" +#line 1775 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 274: -#line 1777 "go.y" +#line 1781 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 275: -#line 1781 "go.y" +#line 1785 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 276: -#line 1787 "go.y" +#line 1791 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 277: -#line 1791 "go.y" +#line 1795 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 278: -#line 1800 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 279: #line 1804 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 280: + case 279: #line 1808 "go.y" { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; - case 281: + case 280: #line 1812 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; + case 281: +#line 1816 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + case 282: -#line 1817 "go.y" +#line 1821 "go.y" { (yyval.list) = nil; } break; case 283: -#line 1821 "go.y" +#line 1825 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 288: -#line 1835 "go.y" +#line 1839 "go.y" { (yyval.node) = N; } break; case 290: -#line 1841 "go.y" +#line 1845 "go.y" { (yyval.list) = nil; } break; case 292: -#line 1847 "go.y" +#line 1851 "go.y" { (yyval.node) = N; } break; case 294: -#line 1853 "go.y" +#line 1857 "go.y" { (yyval.list) = nil; } break; case 296: -#line 1859 "go.y" +#line 1863 "go.y" { (yyval.list) = nil; } break; case 298: -#line 1865 "go.y" +#line 1869 "go.y" { (yyval.list) = nil; } break; case 300: -#line 1871 "go.y" +#line 1875 "go.y" { (yyval.val).ctype = CTxxx; } break; case 302: -#line 1881 "go.y" +#line 1885 "go.y" { importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); } break; case 303: -#line 1885 "go.y" +#line 1889 "go.y" { importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); } break; case 304: -#line 1889 "go.y" +#line 1893 "go.y" { importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); } break; case 305: -#line 1893 "go.y" +#line 1897 "go.y" { importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); } break; case 306: -#line 1897 "go.y" +#line 1901 "go.y" { importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); } break; case 307: -#line 1901 "go.y" +#line 1905 "go.y" { if((yyvsp[(2) - (4)].node) == N) { dclcontext = PEXTERN; // since we skip the funcbody below @@ -4544,7 +4548,7 @@ yyreduce: break; case 308: -#line 1921 "go.y" +#line 1925 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); structpkg = (yyval.sym)->pkg; @@ -4552,7 +4556,7 @@ yyreduce: break; case 309: -#line 1928 "go.y" +#line 1932 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); importsym((yyvsp[(1) - (1)].sym), OTYPE); @@ -4560,14 +4564,14 @@ yyreduce: break; case 315: -#line 1948 "go.y" +#line 1952 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); } break; case 316: -#line 1952 "go.y" +#line 1956 "go.y" { // predefined name like uint8 (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); @@ -4580,49 +4584,49 @@ yyreduce: break; case 317: -#line 1962 "go.y" +#line 1966 "go.y" { (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); } break; case 318: -#line 1966 "go.y" +#line 1970 "go.y" { (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); } break; case 319: -#line 1970 "go.y" +#line 1974 "go.y" { (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); } break; case 320: -#line 1974 "go.y" +#line 1978 "go.y" { (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); } break; case 321: -#line 1978 "go.y" +#line 1982 "go.y" { (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); } break; case 322: -#line 1982 "go.y" +#line 1986 "go.y" { (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); } break; case 323: -#line 1986 "go.y" +#line 1990 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(2) - (2)].type); @@ -4631,7 +4635,7 @@ yyreduce: break; case 324: -#line 1992 "go.y" +#line 1996 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (4)].type); @@ -4640,7 +4644,7 @@ yyreduce: break; case 325: -#line 1998 "go.y" +#line 2002 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4649,7 +4653,7 @@ yyreduce: break; case 326: -#line 2006 "go.y" +#line 2010 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4658,14 +4662,14 @@ yyreduce: break; case 327: -#line 2014 "go.y" +#line 2018 "go.y" { (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); } break; case 328: -#line 2020 "go.y" +#line 2024 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); if((yyvsp[(1) - (3)].sym)) @@ -4675,7 +4679,7 @@ yyreduce: break; case 329: -#line 2027 "go.y" +#line 2031 "go.y" { Type *t; @@ -4692,7 +4696,7 @@ yyreduce: break; case 330: -#line 2043 "go.y" +#line 2047 "go.y" { Sym *s; @@ -4711,49 +4715,49 @@ yyreduce: break; case 331: -#line 2061 "go.y" +#line 2065 "go.y" { (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); } break; case 332: -#line 2065 "go.y" +#line 2069 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); } break; case 333: -#line 2070 "go.y" +#line 2074 "go.y" { (yyval.list) = nil; } break; case 335: -#line 2077 "go.y" +#line 2081 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); } break; case 336: -#line 2081 "go.y" +#line 2085 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); } break; case 337: -#line 2091 "go.y" +#line 2095 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; case 338: -#line 2095 "go.y" +#line 2099 "go.y" { (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); switch((yyval.node)->val.ctype){ @@ -4771,7 +4775,7 @@ yyreduce: break; case 339: -#line 2110 "go.y" +#line 2114 "go.y" { (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); if((yyval.node)->op != OLITERAL) @@ -4780,7 +4784,7 @@ yyreduce: break; case 341: -#line 2119 "go.y" +#line 2123 "go.y" { if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { (yyval.node) = (yyvsp[(2) - (5)].node); @@ -4794,42 +4798,42 @@ yyreduce: break; case 344: -#line 2135 "go.y" +#line 2139 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 345: -#line 2139 "go.y" +#line 2143 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 346: -#line 2145 "go.y" +#line 2149 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 347: -#line 2149 "go.y" +#line 2153 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 348: -#line 2155 "go.y" +#line 2159 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 349: -#line 2159 "go.y" +#line 2163 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } @@ -4837,7 +4841,7 @@ yyreduce: /* Line 1267 of yacc.c. */ -#line 4842 "y.tab.c" +#line 4846 "y.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -5051,7 +5055,7 @@ yyreturn: } -#line 2163 "go.y" +#line 2167 "go.y" static void diff --git a/test/escape2.go b/test/escape2.go index 8e3aa4de745..94816193385 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1274,3 +1274,29 @@ func foo140() interface{} { T: t, } } + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) // ERROR "buf1 does not escape" + + var buf2 [10]byte // ERROR "moved to heap: buf2" + F2(buf2[:]) // ERROR "buf2 escapes to heap" + + var buf3 [10]byte + F3(buf3[:]) // ERROR "buf3 does not escape" + + var buf4 [10]byte // ERROR "moved to heap: buf4" + F4(buf4[:]) // ERROR "buf4 escapes to heap" +} diff --git a/test/fixedbugs/issue4099.go b/test/fixedbugs/issue4099.go new file mode 100644 index 00000000000..89392bfff1d --- /dev/null +++ b/test/fixedbugs/issue4099.go @@ -0,0 +1,26 @@ +// errorcheck -0 -m + +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check go:noescape annotations. + +package p + +// The noescape comment only applies to the next func, +// which must not have a body. + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) // ERROR "buf1 does not escape" + + var buf2 [10]byte // ERROR "moved to heap: buf2" + F2(buf2[:]) // ERROR "buf2 escapes to heap" +}