]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: add way to specify 'noescape' for extern funcs
authorRuss Cox <rsc@golang.org>
Tue, 5 Feb 2013 12:00:38 +0000 (07:00 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 5 Feb 2013 12:00:38 +0000 (07:00 -0500)
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
src/cmd/gc/esc.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/lex.c
src/cmd/gc/y.tab.c
test/escape2.go
test/fixedbugs/issue4099.go [new file with mode: 0644]

index 78bffc8ecb33e36ba91b20a2da0e03df2973ce85..c2eff88f6e11176d31173755a6872baaefeca259 100644 (file)
@@ -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
index 42e414ca27104aa5e8003c921dfc2ee2aa73533d..1b065d433e8719697aad720b82ea6dd7c3c1adb1 100644 (file)
@@ -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;
index e0f0dae8ee91ce51eff2281897cf40277e7ae316..886a6f78673fe1e02fc2a1ce4ac24a30851ed70b 100644 (file)
@@ -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;
index 5f410f308b9bbb6298d7aebe6c900bf4104b32ed..794961e8e7cfa077d3313e0e641df7e07c51ca83 100644 (file)
@@ -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:
index 9a017684931788ef5e1ec2de558491808ded2743..68ae6864d07b3264f7f94e4bd82484f2ec629319 100644 (file)
@@ -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;
 }
index a4e468845262865f30e16d8fb91c4f0cba0af8e8..75175455eaeaea5cb594fa224324a23e25939572 100644 (file)
@@ -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"
+#line 1804 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 279:
-#line 1804 "go.y"
+#line 1808 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 280:
-#line 1808 "go.y"
+#line 1812 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 281:
-#line 1812 "go.y"
+#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
index 8e3aa4de745ed3d6036446b8cf214b7a43fe4683..94816193385cceb9d7f10acf6d87de9573ff1d24 100644 (file)
@@ -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 (file)
index 0000000..89392bf
--- /dev/null
@@ -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"
+}