1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- E X P _ C H 1 1 --
-- --
-- B o d y --
-- --
-- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- ware Foundation; either version 3, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING3. If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Atree; use Atree;
with Debug; use Debug;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
with Exp_Ch7; use Exp_Ch7;
with Exp_Intr; use Exp_Intr;
with Exp_Util; use Exp_Util;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Ch8; use Sem_Ch8;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Sinput; use Sinput;
with Snames; use Snames;
with Stand; use Stand;
with Stringt; use Stringt;
with Targparm; use Targparm;
with Tbuild; use Tbuild;
with Uintp; use Uintp;
package body Exp_Ch11 is
-----------------------
-- Local Subprograms --
-----------------------
procedure Warn_No_Exception_Propagation_Active (N : Node_Id);
-- Generates warning that pragma Restrictions (No_Exception_Propagation)
-- is in effect. Caller then generates appropriate continuation message.
-- N is the node on which the warning is placed.
procedure Warn_If_No_Propagation (N : Node_Id);
-- Called for an exception raise that is not a local raise (and thus can
-- not be optimized to a goto. Issues warning if No_Exception_Propagation
-- restriction is set. N is the node for the raise or equivalent call.
---------------------------
-- Expand_At_End_Handler --
---------------------------
-- For a handled statement sequence that has a cleanup (At_End_Proc
-- field set), an exception handler of the following form is required:
-- exception
-- when all others =>
-- cleanup call
-- raise;
-- Note: this exception handler is treated rather specially by
-- subsequent expansion in two respects:
-- The normal call to Undefer_Abort is omitted
-- The raise call does not do Defer_Abort
-- This is because the current tasking code seems to assume that
-- the call to the cleanup routine that is made from an exception
-- handler for the abort signal is called with aborts deferred.
-- This expansion is only done if we have front end exception handling.
-- If we have back end exception handling, then the AT END handler is
-- left alone, and cleanups (including the exceptional case) are handled
-- by the back end.
-- In the front end case, the exception handler described above handles
-- the exceptional case. The AT END handler is left in the generated tree
-- and the code generator (e.g. gigi) must still handle proper generation
-- of cleanup calls for the non-exceptional case.
procedure Expand_At_End_Handler (HSS : Node_Id; Blk_Id : Entity_Id) is
Clean : constant Entity_Id := Entity (At_End_Proc (HSS));
Ohandle : Node_Id;
Stmnts : List_Id;
Loc : constant Source_Ptr := No_Location;
-- Location used for expansion. We quite deliberately do not set a
-- specific source location for the expanded handler. This makes
-- sense since really the handler is not associated with specific
-- source. We used to set this to Sloc (Clean), but that caused
-- useless and annoying bouncing around of line numbers in the
-- debugger in some circumstances.
begin
pragma Assert (Present (Clean));
pragma Assert (No (Exception_Handlers (HSS)));
-- Back end exception schemes don't need explicit handlers to
-- trigger AT-END actions on exceptional paths.
if Back_End_Exceptions then
return;
end if;
-- Don't expand an At End handler if we have already had configurable
-- run-time violations, since likely this will just be a matter of
-- generating useless cascaded messages
if Configurable_Run_Time_Violations > 0 then
return;
end if;
-- Don't expand an At End handler if we are not allowing exceptions
-- or if exceptions are transformed into local gotos, and never
-- propagated (No_Exception_Propagation).
if No_Exception_Handlers_Set then
return;
end if;
if Present (Blk_Id) then
Push_Scope (Blk_Id);
end if;
Ohandle :=
Make_Others_Choice (Loc);
Set_All_Others (Ohandle);
Stmnts := New_List (
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (Clean, Loc)));
-- Generate reraise statement as last statement of AT-END handler,
-- unless we are under control of No_Exception_Propagation, in which
-- case no exception propagation is possible anyway, so we do not need
-- a reraise (the AT END handler in this case is only for normal exits
-- not for exceptional exits). Also, we flag the Reraise statement as
-- being part of an AT END handler to prevent signalling this reraise
-- as a violation of the restriction when it is not set.
if not Restriction_Active (No_Exception_Propagation) then
declare
Rstm : constant Node_Id := Make_Raise_Statement (Loc);
begin
Set_From_At_End (Rstm);
Append_To (Stmnts, Rstm);
end;
end if;
Set_Exception_Handlers (HSS, New_List (
Make_Implicit_Exception_Handler (Loc,
Exception_Choices => New_List (Ohandle),
Statements => Stmnts)));
Analyze_List (Stmnts, Suppress => All_Checks);
Expand_Exception_Handlers (HSS);
if Present (Blk_Id) then
Pop_Scope;
end if;
end Expand_At_End_Handler;
-------------------------------
-- Expand_Exception_Handlers --
-------------------------------
procedure Expand_Exception_Handlers (HSS : Node_Id) is
Handlrs : constant List_Id := Exception_Handlers (HSS);
Loc : constant Source_Ptr := Sloc (HSS);
Handler : Node_Id;
Others_Choice : Boolean;
Obj_Decl : Node_Id;
Next_Handler : Node_Id;
procedure Expand_Local_Exception_Handlers;
-- This procedure handles the expansion of exception handlers for the
-- optimization of local raise statements into goto statements.
procedure Prepend_Call_To_Handler
(Proc : RE_Id;
Args : List_Id := No_List);
-- Routine to prepend a call to the procedure referenced by Proc at
-- the start of the handler code for the current Handler.
procedure Replace_Raise_By_Goto (Raise_S : Node_Id; Goto_L1 : Node_Id);
-- Raise_S is a raise statement (possibly expanded, and possibly of the
-- form of a Raise_xxx_Error node with a condition. This procedure is
-- called to replace the raise action with the (already analyzed) goto
-- statement passed as Goto_L1. This procedure also takes care of the
-- requirement of inserting a Local_Raise call where possible.
-------------------------------------
-- Expand_Local_Exception_Handlers --
-------------------------------------
-- There are two cases for this transformation. First the case of
-- explicit raise statements. For this case, the transformation we do
-- looks like this. Right now we have for example (where L1, L2 are
-- exception labels)
-- begin
-- ...
-- raise_exception (excep1'identity); -- was raise excep1
-- ...
-- raise_exception (excep2'identity); -- was raise excep2
-- ...
-- exception
-- when excep1 =>
-- estmts1
-- when excep2 =>
-- estmts2
-- end;
-- This gets transformed into:
-- begin
-- L1 : label; -- marked Exception_Junk
-- L2 : label; -- marked Exception_Junk
-- L3 : label; -- marked Exception_Junk
-- begin -- marked Exception_Junk
-- ...
-- local_raise (excep1'address); -- was raise excep1
-- goto L1;
-- ...
-- local_raise (excep2'address); -- was raise excep2
-- goto L2;
-- ...
-- exception
-- when excep1 =>
-- goto L1;
-- when excep2 =>
-- goto L2;
-- end;
-- goto L3; -- skip handler if no raise, marked Exception_Junk
-- <<L1>> -- local excep target label, marked Exception_Junk
-- begin -- marked Exception_Junk
-- estmts1
-- end;
-- goto L3; -- marked Exception_Junk
-- <<L2>> -- marked Exception_Junk
-- begin -- marked Exception_Junk
-- estmts2
-- end;
-- goto L3; -- marked Exception_Junk
-- <<L3>> -- marked Exception_Junk
-- end;
-- Note: the reason we wrap the original statement sequence in an
-- inner block is that there may be raise statements within the
-- sequence of statements in the handlers, and we must ensure that
-- these are properly handled, and in particular, such raise statements
-- must not reenter the same exception handlers.
-- If the restriction No_Exception_Propagation is in effect, then we
-- can omit the exception handlers.
-- begin
-- L1 : label; -- marked Exception_Junk
-- L2 : label; -- marked Exception_Junk
-- L3 : label; -- marked Exception_Junk
-- begin -- marked Exception_Junk
-- ...
-- local_raise (excep1'address); -- was raise excep1
-- goto L1;
-- ...
-- local_raise (excep2'address); -- was raise excep2
-- goto L2;
-- ...
-- end;
-- goto L3; -- skip handler if no raise, marked Exception_Junk
-- <<L1>> -- local excep target label, marked Exception_Junk
-- begin -- marked Exception_Junk
-- estmts1
-- end;
-- goto L3; -- marked Exception_Junk
-- <<L2>> -- marked Exception_Junk
-- begin -- marked Exception_Junk
-- estmts2
-- end;
-- <<L3>> -- marked Exception_Junk
-- end;
-- The second case is for exceptions generated by the back end in one
-- of three situations:
-- 1. Front end generates N_Raise_xxx_Error node
-- 2. Front end sets Do_xxx_Check flag in subexpression node
-- 3. Back end detects a situation where an exception is appropriate
-- In all these cases, the current processing in gigi is to generate a
-- call to the appropriate Rcheck_xx routine (where xx encodes both the
-- exception message and the exception to be raised, Constraint_Error,
-- Program_Error, or Storage_Error.
-- We could handle some subcases of 1 using the same front end expansion
-- into gotos, but even for case 1, we can't handle all cases, since
-- generating gotos in the middle of expressions is not possible (it's
-- possible at the gigi/gcc level, but not at the level of the GNAT
-- tree).
-- In any case, it seems easier to have a scheme which handles all three
-- cases in a uniform manner. So here is how we proceed in this case.
-- This procedure detects all handlers for these three exceptions,
-- Constraint_Error, Program_Error and Storage_Error (including WHEN
-- OTHERS handlers that cover one or more of these cases).
-- If the handler meets the requirements for being the target of a local
-- raise, then the front end does the expansion described previously,
-- creating a label to be used as a goto target to raise the exception.
-- However, no attempt is made in the front end to convert any related
-- raise statements into gotos, e.g. all N_Raise_xxx_Error nodes are
-- left unchanged and passed to the back end.
-- Instead, the front end generates three nodes
-- N_Push_Constraint_Error_Label
-- N_Push_Program_Error_Label
-- N_Push_Storage_Error_Label
-- The Push node is generated at the start of the statements
-- covered by the handler, and has as a parameter the label to be
-- used as the raise target.
-- N_Pop_Constraint_Error_Label
-- N_Pop_Program_Error_Label
-- N_Pop_Storage_Error_Label
-- The Pop node is generated at the end of the covered statements
-- and undoes the effect of the preceding corresponding Push node.
-- In the case where the handler does NOT meet the requirements, the
-- front end will still generate the Push and Pop nodes, but the label
-- field in the Push node will be empty signifying that for this region
-- of code, no optimization is possible.
-- These Push/Pop nodes are inhibited if No_Exception_Handlers is set
-- since they are useless in this case, and in CodePeer mode, where
-- they serve no purpose and can intefere with the analysis.
-- The back end must maintain three stacks, one for each exception case,
-- the Push node pushes an entry onto the corresponding stack, and Pop
-- node pops off the entry. Then instead of calling Rcheck_nn, if the
-- corresponding top stack entry has an non-empty label, a goto is
-- generated. This goto should be preceded by a call to Local_Raise as
-- described above.
-- An example of this transformation is as follows, given:
-- declare
-- A : Integer range 1 .. 10;
-- begin
-- A := B + C;
-- exception
-- when Constraint_Error =>
-- estmts
-- end;
-- gets transformed to:
-- declare
-- A : Integer range 1 .. 10;
-- begin
-- L1 : label;
-- L2 : label;
-- begin
-- %push_constraint_error_label (L1)
-- R1b : constant long_long_integer := long_long_integer?(b) +
-- long_long_integer?(c);
-- [constraint_error when
-- not (R1b in -16#8000_0000# .. 16#7FFF_FFFF#)
-- "overflow check failed"]
-- a := integer?(R1b);
-- %pop_constraint_error_Label
-- exception
-- ...
-- when constraint_error =>
-- goto L1;
-- end;
-- goto L2; -- skip handler when exception not raised
-- <<L1>> -- target label for local exception
-- estmts
-- <<L2>>
-- end;
-- Note: the generated labels and goto statements all have the flag
-- Exception_Junk set True, so that Sem_Ch6.Check_Returns will ignore
-- this generated exception stuff when checking for missing return
-- statements (see circuitry in Check_Statement_Sequence).
-- Note: All of the processing described above occurs only if
-- restriction No_Exception_Propagation applies or debug flag .g is
-- enabled.
CE_Locally_Handled : Boolean := False;
SE_Locally_Handled : Boolean := False;
PE_Locally_Handled : Boolean := False;
-- These three flags indicate whether a handler for the corresponding
-- exception (CE=Constraint_Error, SE=Storage_Error, PE=Program_Error)
-- is present. If so the switch is set to True, the Exception_Label
-- field of the corresponding handler is set, and appropriate Push
-- and Pop nodes are inserted into the code.
Local_Expansion_Required : Boolean := False;
-- Set True if we have at least one handler requiring local raise
-- expansion as described above.
procedure Expand_Local_Exception_Handlers is
procedure Add_Exception_Label (H : Node_Id);
-- H is an exception handler. First check for an Exception_Label
-- already allocated for H. If none, allocate one, set the field in
-- the handler node, add the label declaration, and set the flag
-- Local_Expansion_Required. Note: if Local_Raise_Not_OK is set
-- the call has no effect and Exception_Label is left empty.
procedure Add_Label_Declaration (L : Entity_Id);
-- Add an implicit declaration of the given label to the declaration
-- list in the parent of the current sequence of handled statements.
generic
Exc_Locally_Handled : in out Boolean;
-- Flag indicating whether a local handler for this exception
-- has already been generated.
with function Make_Push_Label (Loc : Source_Ptr) return Node_Id;
-- Function to create a Push_xxx_Label node
with function Make_Pop_Label (Loc : Source_Ptr) return Node_Id;
-- Function to create a Pop_xxx_Label node
procedure Generate_Push_Pop (H : Node_Id);
-- Common code for Generate_Push_Pop_xxx below, used to generate an
-- exception label and Push/Pop nodes for Constraint_Error,
-- Program_Error, or Storage_Error.
-------------------------
-- Add_Exception_Label --
-------------------------
procedure Add_Exception_Label (H : Node_Id) is
begin
if No (Exception_Label (H))
and then not Local_Raise_Not_OK (H)
and then not Special_Exception_Package_Used
then
Local_Expansion_Required := True;
declare
L : constant Entity_Id := Make_Temporary (Sloc (H), 'L');
begin
Set_Exception_Label (H, L);
Add_Label_Declaration (L);
end;
end if;
end Add_Exception_Label;
---------------------------
-- Add_Label_Declaration --
---------------------------
procedure Add_Label_Declaration (L : Entity_Id) is
P : constant Node_Id := Parent (HSS);
Decl_L : constant Node_Id :=
Make_Implicit_Label_Declaration (Loc,
Defining_Identifier => L);
begin
if Declarations (P) = No_List then
Set_Declarations (P, Empty_List);
end if;
Append (Decl_L, Declarations (P));
Analyze (Decl_L);
end Add_Label_Declaration;
-----------------------
-- Generate_Push_Pop --
-----------------------
procedure Generate_Push_Pop (H : Node_Id) is
begin
if Restriction_Active (No_Exception_Handlers)
or else CodePeer_Mode
then
return;
end if;
if Exc_Locally_Handled then
return;
else
Exc_Locally_Handled := True;
end if;
Add_Exception_Label (H);
declare
F : constant Node_Id := First (Statements (HSS));
L : constant Node_Id := Last (Statements (HSS));
Push : constant Node_Id := Make_Push_Label (Sloc (F));
Pop : constant Node_Id := Make_Pop_Label (Sloc (L));
begin
-- We make sure that a call to Get_Local_Raise_Call_Entity is
-- made during front end processing, so that when we need it
-- in the back end, it will already be available and loaded.
Discard_Node (Get_Local_Raise_Call_Entity);
-- Prepare and insert Push and Pop nodes
Set_Exception_Label (Push, Exception_Label (H));
Insert_Before (F, Push);
Set_Analyzed (Push);
Insert_After (L, Pop);
Set_Analyzed (Pop);
end;
end Generate_Push_Pop;
-- Local declarations
Loc : constant Source_Ptr := Sloc (HSS);
Stmts : List_Id := No_List;
Choice : Node_Id;
Excep : Entity_Id;
procedure Generate_Push_Pop_For_Constraint_Error is
new Generate_Push_Pop
(Exc_Locally_Handled => CE_Locally_Handled,
Make_Push_Label => Make_Push_Constraint_Error_Label,
Make_Pop_Label => Make_Pop_Constraint_Error_Label);
-- If no Push/Pop has been generated for CE yet, then set the flag
-- CE_Locally_Handled, allocate an Exception_Label for handler H (if
-- not already done), and generate Push/Pop nodes for the exception
-- label at the start and end of the statements of HSS.
procedure Generate_Push_Pop_For_Program_Error is
new Generate_Push_Pop
(Exc_Locally_Handled => PE_Locally_Handled,
Make_Push_Label => Make_Push_Program_Error_Label,
Make_Pop_Label => Make_Pop_Program_Error_Label);
-- If no Push/Pop has been generated for PE yet, then set the flag
-- PE_Locally_Handled, allocate an Exception_Label for handler H (if
-- not already done), and generate Push/Pop nodes for the exception
-- label at the start and end of the statements of HSS.
procedure Generate_Push_Pop_For_Storage_Error is
new Generate_Push_Pop
(Exc_Locally_Handled => SE_Locally_Handled,
Make_Push_Label => Make_Push_Storage_Error_Label,
Make_Pop_Label => Make_Pop_Storage_Error_Label);
-- If no Push/Pop has been generated for SE yet, then set the flag
-- SE_Locally_Handled, allocate an Exception_Label for handler H (if
-- not already done), and generate Push/Pop nodes for the exception
-- label at the start and end of the statements of HSS.
-- Start of processing for Expand_Local_Exception_Handlers
begin
-- No processing if all exception handlers will get removed
if Debug_Flag_Dot_X then
return;
end if;
-- See for each handler if we have any local raises to expand
Handler := First_Non_Pragma (Handlrs);
while Present (Handler) loop
-- Note, we do not test Local_Raise_Not_OK here, because in the
-- case of Push/Pop generation we want to generate push with a
-- null label. The Add_Exception_Label routine has no effect if
-- Local_Raise_Not_OK is set, so this works as required.
if Present (Local_Raise_Statements (Handler)) then
Add_Exception_Label (Handler);
end if;
-- If we are doing local raise to goto optimization (restriction
-- No_Exception_Propagation set or debug flag .g set), then check
-- to see if handler handles CE, PE, SE and if so generate the
-- appropriate push/pop sequence for the back end.
if (Debug_Flag_Dot_G
or else Restriction_Active (No_Exception_Propagation))
and then Has_Local_Raise (Handler)
then
Choice := First (Exception_Choices (Handler));
while Present (Choice) loop
if Nkind (Choice) = N_Others_Choice
and then not All_Others (Choice)
then
Generate_Push_Pop_For_Constraint_Error (Handler);
Generate_Push_Pop_For_Program_Error (Handler);
Generate_Push_Pop_For_Storage_Error (Handler);
elsif Is_Entity_Name (Choice) then
Excep := Get_Renamed_Entity (Entity (Choice));
if Excep = Standard_Constraint_Error then
Generate_Push_Pop_For_Constraint_Error (Handler);
elsif Excep = Standard_Program_Error then
Generate_Push_Pop_For_Program_Error (Handler);
elsif Excep = Standard_Storage_Error then
Generate_Push_Pop_For_Storage_Error (Handler);
end if;
end if;
Next (Choice);
end loop;
end if;
Next_Non_Pragma (Handler);
end loop;
-- Nothing to do if no handlers requiring the goto transformation
if not (Local_Expansion_Required) then
return;
end if;
-- Prepare to do the transformation
declare
-- L3 is the label to exit the HSS
L3_Dent : constant Entity_Id := Make_Temporary (Loc, 'L');
Labl_L3 : constant Node_Id :=
Make_Label (Loc,
Identifier => New_Occurrence_Of (L3_Dent, Loc));
Blk_Stm : Node_Id;
Relmt : Elmt_Id;
begin
Set_Exception_Junk (Labl_L3);
Add_Label_Declaration (L3_Dent);
-- Wrap existing statements and handlers in an inner block
Blk_Stm :=
Make_Block_Statement (Loc,
Handled_Statement_Sequence => Relocate_Node (HSS));
Set_Exception_Junk (Blk_Stm);
Rewrite (HSS,
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (Blk_Stm),
End_Label => Relocate_Node (End_Label (HSS))));
-- Set block statement as analyzed, we don't want to actually call
-- Analyze on this block, it would cause a recursion in exception
-- handler processing which would mess things up.
Set_Analyzed (Blk_Stm);
-- Now loop through the exception handlers to deal with those that
-- are targets of local raise statements.
Handler := First_Non_Pragma (Handlrs);
while Present (Handler) loop
if Present (Exception_Label (Handler)) then
-- This handler needs the goto expansion
declare
Loc : constant Source_Ptr := Sloc (Handler);
-- L1 is the start label for this handler
L1_Dent : constant Entity_Id := Exception_Label (Handler);
Labl_L1 : constant Node_Id :=
Make_Label (Loc,
Identifier =>
New_Occurrence_Of (L1_Dent, Loc));
-- Jump to L1 to be used as replacement for the original
-- handler (used in the case where exception propagation
-- may still occur).
Name_L1 : constant Node_Id :=
New_Occurrence_Of (L1_Dent, Loc);
Goto_L1 : constant Node_Id :=
Make_Goto_Statement (Loc,
Name => Name_L1);
-- Jump to L3 to be used at the end of handler
Name_L3 : constant Node_Id :=
New_Occurrence_Of (L3_Dent, Loc);
Goto_L3 : constant Node_Id :=
Make_Goto_Statement (Loc,
Name => Name_L3);
H_Stmts : constant List_Id := Statements (Handler);
begin
Set_Exception_Junk (Labl_L1);
Set_Exception_Junk (Goto_L3);
-- Note: we do NOT set Exception_Junk in Goto_L1, since
-- this is a real transfer of control that we want the
-- Sem_Ch6.Check_Returns procedure to recognize properly.
-- Replace handler by a goto L1. We can mark this as
-- analyzed since it is fully formed, and we don't
-- want it going through any further checks. We save
-- the last statement location in the goto L1 node for
-- the benefit of Sem_Ch6.Check_Returns.
Set_Statements (Handler, New_List (Goto_L1));
Set_Analyzed (Goto_L1);
Set_Etype (Name_L1, Standard_Void_Type);
-- Now replace all the raise statements by goto L1
if Present (Local_Raise_Statements (Handler)) then
Relmt := First_Elmt (Local_Raise_Statements (Handler));
while Present (Relmt) loop
declare
Raise_S : constant Node_Id := Node (Relmt);
RLoc : constant Source_Ptr := Sloc (Raise_S);
Name_L1 : constant Node_Id :=
New_Occurrence_Of (L1_Dent, Loc);
Goto_L1 : constant Node_Id :=
Make_Goto_Statement (RLoc,
Name => Name_L1);
begin
-- Replace raise by goto L1
Set_Analyzed (Goto_L1);
Set_Etype (Name_L1, Standard_Void_Type);
Replace_Raise_By_Goto (Raise_S, Goto_L1);
end;
Next_Elmt (Relmt);
end loop;
end if;
-- Add a goto L3 at end of statement list in block. The
-- first time, this is what skips over the exception
-- handlers in the normal case. Subsequent times, it
-- terminates the execution of the previous handler code,
-- and skips subsequent handlers.
Stmts := Statements (HSS);
Insert_After (Last (Stmts), Goto_L3);
Set_Analyzed (Goto_L3);
Set_Etype (Name_L3, Standard_Void_Type);
-- Now we drop the label that marks the handler start,
-- followed by the statements of the handler.
Set_Etype (Identifier (Labl_L1), Standard_Void_Type);
Insert_After_And_Analyze (Last (Stmts), Labl_L1);
declare
Loc : constant Source_Ptr := Sloc (First (H_Stmts));
Blk : constant Node_Id :=
Make_Block_Statement (Loc,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => H_Stmts));
begin
Set_Exception_Junk (Blk);
Insert_After_And_Analyze (Last (Stmts), Blk);
end;
end;
-- Here if we have local raise statements but the handler is
-- not suitable for processing with a local raise. In this
-- case we have to generate possible diagnostics.
elsif Has_Local_Raise (Handler)
and then Local_Raise_Statements (Handler) /= No_Elist
then
Relmt := First_Elmt (Local_Raise_Statements (Handler));
while Present (Relmt) loop
Warn_If_No_Propagation (Node (Relmt));
Next_Elmt (Relmt);
end loop;
end if;
Next (Handler);
end loop;
-- Only remaining step is to drop the L3 label and we are done
Set_Etype (Identifier (Labl_L3), Standard_Void_Type);
-- If we had at least one handler, then we drop the label after
-- the last statement of that handler.
if Stmts /= No_List then
Insert_After_And_Analyze (Last (Stmts), Labl_L3);
-- Otherwise we have removed all the handlers (this results from
-- use of pragma Restrictions (No_Exception_Propagation), and we
-- drop the label at the end of the statements of the HSS.
else
Insert_After_And_Analyze (Last (Statements (HSS)), Labl_L3);
end if;
return;
end;
end Expand_Local_Exception_Handlers;
-----------------------------
-- Prepend_Call_To_Handler --
-----------------------------
procedure Prepend_Call_To_Handler
(Proc : RE_Id;
Args : List_Id := No_List)
is
Ent : constant Entity_Id := RTE (Proc);
begin
-- If we have no Entity, then we are probably in no run time mode or
-- some weird error has occurred. In either case do nothing. Note use
-- of No_Location to hide this code from the debugger, so single
-- stepping doesn't jump back and forth.
if Present (Ent) then
declare
Call : constant Node_Id :=
Make_Procedure_Call_Statement (No_Location,
Name => New_Occurrence_Of (RTE (Proc), No_Location),
Parameter_Associations => Args);
begin
Prepend_To (Statements (Handler), Call);
Analyze (Call, Suppress => All_Checks);
end;
end if;
end Prepend_Call_To_Handler;
---------------------------
-- Replace_Raise_By_Goto --
---------------------------
procedure Replace_Raise_By_Goto (Raise_S : Node_Id; Goto_L1 : Node_Id) is
Loc : constant Source_Ptr := Sloc (Raise_S);
Excep : Entity_Id;
LR : Node_Id;
Cond : Node_Id;
Orig : Node_Id;
begin
-- If we have a null statement, it means that there is no replacement
-- needed (typically this results from a suppressed check).
if Nkind (Raise_S) = N_Null_Statement then
return;
-- Test for Raise_xxx_Error
elsif Nkind (Raise_S) = N_Raise_Constraint_Error then
Excep := Standard_Constraint_Error;
Cond := Condition (Raise_S);
elsif Nkind (Raise_S) = N_Raise_Storage_Error then
Excep := Standard_Storage_Error;
Cond := Condition (Raise_S);
elsif Nkind (Raise_S) = N_Raise_Program_Error then
Excep := Standard_Program_Error;
Cond := Condition (Raise_S);
-- The only other possibility is a node that is or used to be a
-- simple raise statement.
else
Orig := Original_Node (Raise_S);
pragma Assert (Nkind (Orig) = N_Raise_Statement
and then Present (Name (Orig))
and then No (Expression (Orig)));
Excep := Entity (Name (Orig));
Cond := Empty;
end if;
-- Here Excep is the exception to raise, and Cond is the condition
-- First prepare the call to Local_Raise (excep'address).
if RTE_Available (RE_Local_Raise) then
LR :=
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (RTE (RE_Local_Raise), Loc),
Parameter_Associations => New_List (
Unchecked_Convert_To (RTE (RE_Address),
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Excep, Loc),
Attribute_Name => Name_Identity))));
-- Use null statement if Local_Raise not available
else
LR :=
Make_Null_Statement (Loc);
end if;
-- If there is no condition, we rewrite as
-- begin
-- Local_Raise (excep'Identity);
-- goto L1;
-- end;
if No (Cond) then
Rewrite (Raise_S,
Make_Block_Statement (Loc,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (LR, Goto_L1))));
Set_Exception_Junk (Raise_S);
-- If there is a condition, we rewrite as
-- if condition then
-- Local_Raise (excep'Identity);
-- goto L1;
-- end if;
else
Rewrite (Raise_S,
Make_If_Statement (Loc,
Condition => Cond,
Then_Statements => New_List (LR, Goto_L1)));
end if;
Analyze (Raise_S);
end Replace_Raise_By_Goto;
-- Start of processing for Expand_Exception_Handlers
begin
Expand_Local_Exception_Handlers;
-- Loop through handlers
Handler := First_Non_Pragma (Handlrs);
Handler_Loop : while Present (Handler) loop
Process_Statements_For_Controlled_Objects (Handler);
Next_Handler := Next_Non_Pragma (Handler);
-- Remove source handler if gnat debug flag .x is set
if Debug_Flag_Dot_X and then Comes_From_Source (Handler) then
Remove (Handler);
-- Remove handler if no exception propagation, generating a warning
-- if a source generated handler was not the target of a local raise.
else
if Restriction_Active (No_Exception_Propagation)
and then not Has_Local_Raise (Handler)
and then Comes_From_Source (Handler)
and then Warn_On_Non_Local_Exception
then
Warn_No_Exception_Propagation_Active (Handler);
Error_Msg_N
("\?X?this handler can never be entered, "
& "and has been removed", Handler);
end if;
if No_Exception_Propagation_Active then
Remove (Handler);
-- Exception handler is active and retained and must be processed
else
-- If an exception occurrence is present, then we must declare
-- it and initialize it from the value stored in the TSD
-- declare
-- name : Exception_Occurrence;
-- begin
-- Save_Occurrence (name, Get_Current_Excep.all)
-- ...
-- end;
-- This expansion is only performed when using front-end
-- exceptions. Gigi will insert a call to initialize the
-- choice parameter.
if Present (Choice_Parameter (Handler))
and then (Front_End_Exceptions
or else CodePeer_Mode)
then
declare
Cparm : constant Entity_Id := Choice_Parameter (Handler);
Cloc : constant Source_Ptr := Sloc (Cparm);
Hloc : constant Source_Ptr := Sloc (Handler);
Save : Node_Id;
begin
-- Note: No_Location used to hide code from the debugger,
-- so single stepping doesn't jump back and forth.
Save :=
Make_Procedure_Call_Statement (No_Location,
Name =>
New_Occurrence_Of
(RTE (RE_Save_Occurrence), No_Location),
Parameter_Associations => New_List (
New_Occurrence_Of (Cparm, No_Location),
Make_Explicit_Dereference (No_Location,
Prefix =>
Make_Function_Call (No_Location,
Name =>
Make_Explicit_Dereference (No_Location,
Prefix =>
New_Occurrence_Of
(RTE (RE_Get_Current_Excep),
No_Location))))));
Mark_Rewrite_Insertion (Save);
Prepend (Save, Statements (Handler));
Obj_Decl :=
Make_Object_Declaration (Cloc,
Defining_Identifier => Cparm,
Object_Definition =>
New_Occurrence_Of
(RTE (RE_Exception_Occurrence), Cloc));
Set_No_Initialization (Obj_Decl, True);
Rewrite (Handler,
Make_Exception_Handler (Hloc,
Choice_Parameter => Empty,
Exception_Choices => Exception_Choices (Handler),
Statements => New_List (
Make_Block_Statement (Hloc,
Declarations => New_List (Obj_Decl),
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Hloc,
Statements => Statements (Handler))))));
-- Local raise statements can't occur, since exception
-- handlers with choice parameters are not allowed when
-- No_Exception_Propagation applies, so set attributes
-- accordingly.
Set_Local_Raise_Statements (Handler, No_Elist);
Set_Local_Raise_Not_OK (Handler);
Analyze_List
(Statements (Handler), Suppress => All_Checks);
end;
end if;
-- For the normal case, we have to worry about the state of
-- abort deferral. Generally, we defer abort during runtime
-- handling of exceptions. When control is passed to the
-- handler, then in the normal case we undefer aborts. In
-- any case this entire handling is relevant only if aborts
-- are allowed.
if Abort_Allowed
and then not ZCX_Exceptions
then
-- There are some special cases in which we do not do the
-- undefer. In particular a finalization (AT END) handler
-- wants to operate with aborts still deferred.
-- We also suppress the call if this is the special handler
-- for Abort_Signal, since if we are aborting, we want to
-- keep aborts deferred (one abort is enough).
-- If abort really needs to be deferred the expander must
-- add this call explicitly, see
-- Expand_N_Asynchronous_Select.
Others_Choice :=
Nkind (First (Exception_Choices (Handler))) =
N_Others_Choice;
if (Others_Choice
or else Entity (First (Exception_Choices (Handler))) /=
Stand.Abort_Signal)
and then not
(Others_Choice
and then
All_Others (First (Exception_Choices (Handler))))
then
Prepend_Call_To_Handler (RE_Abort_Undefer);
end if;
end if;
end if;
end if;
Handler := Next_Handler;
end loop Handler_Loop;
-- If all handlers got removed, then remove the list. Note we cannot
-- reference HSS here, since expanding local handlers may have buried
-- the handlers in an inner block.
if Is_Empty_List (Handlrs) then
Set_Exception_Handlers (Parent (Handlrs), No_List);
end if;
end Expand_Exception_Handlers;
------------------------------------
-- Expand_N_Exception_Declaration --
------------------------------------
-- Generates:
-- exceptE : constant String := "A.B.EXCEP"; -- static data
-- except : exception_data :=
-- (Handled_By_Other => False,
-- Lang => 'A',
-- Name_Length => exceptE'Length,
-- Full_Name => exceptE'Address,
-- HTable_Ptr => null,
-- Foreign_Data => null,
-- Raise_Hook => null);
-- (protecting test only needed if not at library level)
-- exceptF : Boolean := True -- static data
-- if exceptF then
-- exceptF := False;
-- Register_Exception (except'Unchecked_Access);
-- end if;
procedure Expand_N_Exception_Declaration (N : Node_Id) is
Id : constant Entity_Id := Defining_Identifier (N);
Loc : constant Source_Ptr := Sloc (N);
procedure Force_Static_Allocation_Of_Referenced_Objects
(Aggregate : Node_Id);
-- A specialized solution to one particular case of an ugly problem
--
-- The given aggregate includes an Unchecked_Conversion as one of the
-- component values. The call to Analyze_And_Resolve below ends up
-- calling Exp_Ch4.Expand_N_Unchecked_Type_Conversion, which may decide
-- to introduce a (constant) temporary and then obtain the component
-- value by evaluating the temporary.
--
-- In the case of an exception declared within a subprogram (or any
-- other dynamic scope), this is a bad transformation. The exception
-- object is marked as being Statically_Allocated but the temporary is
-- not. If the initial value of a Statically_Allocated declaration
-- references a dynamically allocated object, this prevents static
-- initialization of the object.
--
-- We cope with this here by marking the temporary Statically_Allocated.
-- It might seem cleaner to generalize this utility and then use it to
-- enforce a rule that the entities referenced in the declaration of any
-- "hoisted" (i.e., Is_Statically_Allocated and not Is_Library_Level)
-- entity must also be either Library_Level or hoisted. It turns out
-- that this would be incompatible with the current treatment of an
-- object which is local to a subprogram, subject to an Export pragma,
-- not subject to an address clause, and whose declaration contains
-- references to other local (non-hoisted) objects (e.g., in the initial
-- value expression).
function Null_String return String_Id;
-- Build a null-terminated empty string
---------------------------------------------------
-- Force_Static_Allocation_Of_Referenced_Objects --
---------------------------------------------------
procedure Force_Static_Allocation_Of_Referenced_Objects
(Aggregate : Node_Id)
is
function Fixup_Node (N : Node_Id) return Traverse_Result;
-- If the given node references a dynamically allocated object, then
-- correct the declaration of the object.
----------------
-- Fixup_Node --
----------------
function Fixup_Node (N : Node_Id) return Traverse_Result is
begin
if Nkind (N) in N_Has_Entity
and then Present (Entity (N))
and then not Is_Library_Level_Entity (Entity (N))
-- Note: the following test is not needed but it seems cleaner
-- to do this test (this would be more important if procedure
-- Force_Static_Allocation_Of_Referenced_Objects recursively
-- traversed the declaration of an entity after marking it as
-- statically allocated).
and then not Is_Statically_Allocated (Entity (N))
then
Set_Is_Statically_Allocated (Entity (N));
end if;
return OK;
end Fixup_Node;
procedure Fixup_Tree is new Traverse_Proc (Fixup_Node);
-- Start of processing for Force_Static_Allocation_Of_Referenced_Objects
begin
Fixup_Tree (Aggregate);
end Force_Static_Allocation_Of_Referenced_Objects;
-----------------
-- Null_String --
-----------------
function Null_String return String_Id is
begin
Start_String;
Store_String_Char (Get_Char_Code (ASCII.NUL));
return End_String;
end Null_String;
-- Local variables
Ex_Id : Entity_Id;
Ex_Val : String_Id;
Flag_Id : Entity_Id;
L : List_Id;
-- Start of processing for Expand_N_Exception_Declaration
begin
-- Nothing to do when generating C code
if Modify_Tree_For_C then
return;
end if;
-- Definition of the external name: nam : constant String := "A.B.NAME";
Ex_Id :=
Make_Defining_Identifier (Loc, New_External_Name (Chars (Id), 'E'));
-- Do not generate an external name if the exception declaration is
-- subject to pragma Discard_Names. Use a null-terminated empty name
-- to ensure that Ada.Exceptions.Exception_Name functions properly.
if Global_Discard_Names or else Discard_Names (Ex_Id) then
Ex_Val := Null_String;
-- Otherwise generate the fully qualified name of the exception
else
Ex_Val := Fully_Qualified_Name_String (Id);
end if;
Insert_Action (N,
Make_Object_Declaration (Loc,
Defining_Identifier => Ex_Id,
Constant_Present => True,
Object_Definition => New_Occurrence_Of (Standard_String, Loc),
Expression => Make_String_Literal (Loc, Ex_Val)));
Set_Is_Statically_Allocated (Ex_Id);
-- Create the aggregate list for type Standard.Exception_Type:
-- Handled_By_Other component: False
L := Empty_List;
Append_To (L, New_Occurrence_Of (Standard_False, Loc));
-- Lang component: 'A'
Append_To (L,
Make_Character_Literal (Loc,
Chars => Name_uA,
Char_Literal_Value => UI_From_Int (Character'Pos ('A'))));
-- Name_Length component: Nam'Length
Append_To (L,
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Ex_Id, Loc),
Attribute_Name => Name_Length));
-- Full_Name component: Standard.A_Char!(Nam'Address)
-- The unchecked conversion causes capacity issues for CodePeer in some
-- cases and is never useful, so we set the Full_Name component to null
-- instead for CodePeer.
if CodePeer_Mode then
Append_To (L, Make_Null (Loc));
else
Append_To (L, Unchecked_Convert_To (Standard_A_Char,
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Ex_Id, Loc),
Attribute_Name => Name_Address)));
end if;
-- HTable_Ptr component: null
Append_To (L, Make_Null (Loc));
-- Foreign_Data component: null
Append_To (L, Make_Null (Loc));
-- Raise_Hook component: null
Append_To (L, Make_Null (Loc));
Set_Expression (N, Make_Aggregate (Loc, Expressions => L));
Analyze_And_Resolve (Expression (N), Etype (Id));
Force_Static_Allocation_Of_Referenced_Objects (Expression (N));
-- Register_Exception (except'Unchecked_Access);
if not No_Exception_Handlers_Set
and then not Restriction_Active (No_Exception_Registration)
then
L := New_List (
Make_Procedure_Call_Statement (Loc,
Name =>
New_Occurrence_Of (RTE (RE_Register_Exception), Loc),
Parameter_Associations => New_List (
Unchecked_Convert_To (RTE (RE_Exception_Data_Ptr),
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Id, Loc),
Attribute_Name => Name_Unrestricted_Access)))));
Set_Register_Exception_Call (Id, First (L));
if not Is_Library_Level_Entity (Id) then
Flag_Id :=
Make_Defining_Identifier (Loc,
Chars => New_External_Name (Chars (Id), 'F'));
Insert_Action (N,
Make_Object_Declaration (Loc,
Defining_Identifier => Flag_Id,
Object_Definition =>
New_Occurrence_Of (Standard_Boolean, Loc),
Expression =>
New_Occurrence_Of (Standard_True, Loc)));
Set_Is_Statically_Allocated (Flag_Id);
Append_To (L,
Make_Assignment_Statement (Loc,
Name => New_Occurrence_Of (Flag_Id, Loc),
Expression => New_Occurrence_Of (Standard_False, Loc)));
Insert_After_And_Analyze (N,
Make_Implicit_If_Statement (N,
Condition => New_Occurrence_Of (Flag_Id, Loc),
Then_Statements => L));
else
Insert_List_After_And_Analyze (N, L);
end if;
end if;
end Expand_N_Exception_Declaration;
---------------------------------------------
-- Expand_N_Handled_Sequence_Of_Statements --
---------------------------------------------
procedure Expand_N_Handled_Sequence_Of_Statements (N : Node_Id) is
begin
-- Expand exception handlers
if Present (Exception_Handlers (N))
and then not Restriction_Active (No_Exception_Handlers)
then
Expand_Exception_Handlers (N);
end if;
-- If local exceptions are being expanded, the previous call will
-- have rewritten the construct as a block and reanalyzed it. No
-- further expansion is needed.
if Analyzed (N) then
return;
end if;
-- Add clean up actions if required
if not Nkind_In (Parent (N), N_Package_Body,
N_Accept_Statement,
N_Extended_Return_Statement)
and then not Delay_Cleanups (Current_Scope)
-- No cleanup action needed in thunks associated with interfaces
-- because they only displace the pointer to the object.
and then not Is_Thunk (Current_Scope)
then
Expand_Cleanup_Actions (Parent (N));
else
Set_First_Real_Statement (N, First (Statements (N)));
end if;
end Expand_N_Handled_Sequence_Of_Statements;
-------------------------------------
-- Expand_N_Raise_Constraint_Error --
-------------------------------------
procedure Expand_N_Raise_Constraint_Error (N : Node_Id) is
begin
-- We adjust the condition to deal with the C/Fortran boolean case. This
-- may well not be necessary, as all such conditions are generated by
-- the expander and probably are all standard boolean, but who knows
-- what strange optimization in future may require this adjustment.
Adjust_Condition (Condition (N));
-- Now deal with possible local raise handling
Possible_Local_Raise (N, Standard_Constraint_Error);
end Expand_N_Raise_Constraint_Error;
-------------------------------
-- Expand_N_Raise_Expression --
-------------------------------
procedure Expand_N_Raise_Expression (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
RCE : Node_Id;
begin
Possible_Local_Raise (N, Entity (Name (N)));
-- Later we must teach the back end/gigi how to deal with this, but
-- for now we will assume the type is Standard_Boolean and transform
-- the node to:
-- do
-- raise X [with string]
-- in
-- raise Constraint_Error;
-- unless the flag Convert_To_Return_False is set, in which case
-- the transformation is to:
-- do
-- return False;
-- in
-- raise Constraint_Error;
-- The raise constraint error can never be executed. It is just a dummy
-- node that can be labeled with an arbitrary type.
RCE := Make_Raise_Constraint_Error (Loc, Reason => CE_Explicit_Raise);
Set_Etype (RCE, Typ);
if Convert_To_Return_False (N) then
Rewrite (N,
Make_Expression_With_Actions (Loc,
Actions => New_List (
Make_Simple_Return_Statement (Loc,
Expression => New_Occurrence_Of (Standard_False, Loc))),
Expression => RCE));
else
Rewrite (N,
Make_Expression_With_Actions (Loc,
Actions => New_List (
Make_Raise_Statement (Loc,
Name => Name (N),
Expression => Expression (N))),
Expression => RCE));
end if;
Analyze_And_Resolve (N, Typ);
end Expand_N_Raise_Expression;
----------------------------------
-- Expand_N_Raise_Program_Error --
----------------------------------
procedure Expand_N_Raise_Program_Error (N : Node_Id) is
begin
-- We adjust the condition to deal with the C/Fortran boolean case. This
-- may well not be necessary, as all such conditions are generated by
-- the expander and probably are all standard boolean, but who knows
-- what strange optimization in future may require this adjustment.
Adjust_Condition (Condition (N));
-- Now deal with possible local raise handling
Possible_Local_Raise (N, Standard_Program_Error);
end Expand_N_Raise_Program_Error;
------------------------------
-- Expand_N_Raise_Statement --
------------------------------
procedure Expand_N_Raise_Statement (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Ehand : Node_Id;
E : Entity_Id;
Str : String_Id;
H : Node_Id;
Src : Boolean;
begin
-- Processing for locally handled exception (exclude reraise case)
if Present (Name (N)) and then Nkind (Name (N)) = N_Identifier then
if Debug_Flag_Dot_G
or else Restriction_Active (No_Exception_Propagation)
then
-- If we have a local handler, then note that this is potentially
-- able to be transformed into a goto statement.
H := Find_Local_Handler (Entity (Name (N)), N);
if Present (H) then
if Local_Raise_Statements (H) = No_Elist then
Set_Local_Raise_Statements (H, New_Elmt_List);
end if;
-- Append the new entry if it is not there already. Sometimes
-- we have situations where due to reexpansion, the same node
-- is analyzed twice and would otherwise be added twice.
Append_Unique_Elmt (N, Local_Raise_Statements (H));
Set_Has_Local_Raise (H);
-- If no local handler, then generate no propagation warning
else
Warn_If_No_Propagation (N);
end if;
end if;
end if;
-- If a string expression is present, then the raise statement is
-- converted to a call:
-- Raise_Exception (exception-name'Identity, string);
-- and there is nothing else to do.
if Present (Expression (N)) then
-- Adjust message to deal with Prefix_Exception_Messages. We only
-- add the prefix to string literals, if the message is being
-- constructed, we assume it already deals with uniqueness.
if Prefix_Exception_Messages
and then Nkind (Expression (N)) = N_String_Literal
then
declare
Buf : Bounded_String;
begin
Add_Source_Info (Buf, Loc, Name_Enclosing_Entity);
Append (Buf, ": ");
Append (Buf, Strval (Expression (N)));
Rewrite (Expression (N), Make_String_Literal (Loc, +Buf));
Analyze_And_Resolve (Expression (N), Standard_String);
end;
end if;
-- Avoid passing exception-name'identity in runtimes in which this
-- argument is not used. This avoids generating undefined references
-- to these exceptions when compiling with no optimization
if Configurable_Run_Time_On_Target
and then (Restriction_Active (No_Exception_Handlers)
or else
Restriction_Active (No_Exception_Propagation))
then
Rewrite (N,
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
Parameter_Associations => New_List (
New_Occurrence_Of (RTE (RE_Null_Id), Loc),
Expression (N))));
else
Rewrite (N,
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
Parameter_Associations => New_List (
Make_Attribute_Reference (Loc,
Prefix => Name (N),
Attribute_Name => Name_Identity),
Expression (N))));
end if;
Analyze (N);
return;
end if;
-- Remaining processing is for the case where no string expression is
-- present.
-- Don't expand a raise statement that does not come from source if we
-- have already had configurable run-time violations, since most likely
-- it will be junk cascaded nonsense.
if Configurable_Run_Time_Violations > 0
and then not Comes_From_Source (N)
then
return;
end if;
-- Convert explicit raise of Program_Error, Constraint_Error, and
-- Storage_Error into the corresponding raise (in High_Integrity_Mode
-- all other raises will get normal expansion and be disallowed,
-- but this is also faster in all modes). Propagate Comes_From_Source
-- flag to the new node.
if Present (Name (N)) and then Nkind (Name (N)) = N_Identifier then
Src := Comes_From_Source (N);
if Entity (Name (N)) = Standard_Constraint_Error then
Rewrite (N,
Make_Raise_Constraint_Error (Loc, Reason => CE_Explicit_Raise));
Set_Comes_From_Source (N, Src);
Analyze (N);
return;
elsif Entity (Name (N)) = Standard_Program_Error then
Rewrite (N,
Make_Raise_Program_Error (Loc, Reason => PE_Explicit_Raise));
Set_Comes_From_Source (N, Src);
Analyze (N);
return;
elsif Entity (Name (N)) = Standard_Storage_Error then
Rewrite (N,
Make_Raise_Storage_Error (Loc, Reason => SE_Explicit_Raise));
Set_Comes_From_Source (N, Src);
Analyze (N);
return;
end if;
end if;
-- Case of name present, in this case we expand raise name to
-- Raise_Exception (name'Identity, location_string);
-- where location_string identifies the file/line of the raise
if Present (Name (N)) then
declare
Id : Entity_Id := Entity (Name (N));
Buf : Bounded_String;
begin
Build_Location_String (Buf, Loc);
-- If the exception is a renaming, use the exception that it
-- renames (which might be a predefined exception, e.g.).
if Present (Renamed_Object (Id)) then
Id := Renamed_Object (Id);
end if;
-- Build a C-compatible string in case of no exception handlers,
-- since this is what the last chance handler is expecting.
if No_Exception_Handlers_Set then
-- Generate an empty message if configuration pragma
-- Suppress_Exception_Locations is set for this unit.
if Opt.Exception_Locations_Suppressed then
Buf.Length := 0;
end if;
Append (Buf, ASCII.NUL);
end if;
if Opt.Exception_Locations_Suppressed then
Buf.Length := 0;
end if;
Str := String_From_Name_Buffer (Buf);
-- Convert raise to call to the Raise_Exception routine
Rewrite (N,
Make_Procedure_Call_Statement (Loc,
Name =>
New_Occurrence_Of (RTE (RE_Raise_Exception), Loc),
Parameter_Associations => New_List (
Make_Attribute_Reference (Loc,
Prefix => Name (N),
Attribute_Name => Name_Identity),
Make_String_Literal (Loc, Strval => Str))));
end;
-- Case of no name present (reraise). We rewrite the raise to:
-- Reraise_Occurrence_Always (EO);
-- where EO is the current exception occurrence. If the current handler
-- does not have a choice parameter specification, then we provide one.
else
-- Bypass expansion to a run-time call when back-end exception
-- handling is active, unless the target is CodePeer or GNATprove.
-- In CodePeer, raising an exception is treated as an error, while in
-- GNATprove all code with exceptions falls outside the subset of
-- code which can be formally analyzed.
if not CodePeer_Mode
and then Back_End_Exceptions
then
return;
end if;
-- Find innermost enclosing exception handler (there must be one,
-- since the semantics has already verified that this raise statement
-- is valid, and a raise with no arguments is only permitted in the
-- context of an exception handler.
Ehand := Parent (N);
while Nkind (Ehand) /= N_Exception_Handler loop
Ehand := Parent (Ehand);
end loop;
-- Make exception choice parameter if none present. Note that we do
-- not need to put the entity on the entity chain, since no one will
-- be referencing this entity by normal visibility methods.
if No (Choice_Parameter (Ehand)) then
E := Make_Temporary (Loc, 'E');
Set_Choice_Parameter (Ehand, E);
Set_Ekind (E, E_Variable);
Set_Etype (E, RTE (RE_Exception_Occurrence));
Set_Scope (E, Current_Scope);
end if;
-- Now rewrite the raise as a call to Reraise. A special case arises
-- if this raise statement occurs in the context of a handler for
-- all others (i.e. an at end handler). in this case we avoid
-- the call to defer abort, cleanup routines are expected to be
-- called in this case with aborts deferred.
declare
Ech : constant Node_Id := First (Exception_Choices (Ehand));
Ent : Entity_Id;
begin
if Nkind (Ech) = N_Others_Choice
and then All_Others (Ech)
then
Ent := RTE (RE_Reraise_Occurrence_No_Defer);
else
Ent := RTE (RE_Reraise_Occurrence_Always);
end if;
Rewrite (N,
Make_Procedure_Call_Statement (Loc,
Name => New_Occurrence_Of (Ent, Loc),
Parameter_Associations => New_List (
New_Occurrence_Of (Choice_Parameter (Ehand), Loc))));
end;
end if;
Analyze (N);
end Expand_N_Raise_Statement;
----------------------------------
-- Expand_N_Raise_Storage_Error --
----------------------------------
procedure Expand_N_Raise_Storage_Error (N : Node_Id) is
begin
-- We adjust the condition to deal with the C/Fortran boolean case. This
-- may well not be necessary, as all such conditions are generated by
-- the expander and probably are all standard boolean, but who knows
-- what strange optimization in future may require this adjustment.
Adjust_Condition (Condition (N));
-- Now deal with possible local raise handling
Possible_Local_Raise (N, Standard_Storage_Error);
end Expand_N_Raise_Storage_Error;
--------------------------
-- Possible_Local_Raise --
--------------------------
procedure Possible_Local_Raise (N : Node_Id; E : Entity_Id) is
begin
-- Nothing to do if local raise optimization not active
if not Debug_Flag_Dot_G
and then not Restriction_Active (No_Exception_Propagation)
then
return;
end if;
-- Nothing to do if original node was an explicit raise, because in
-- that case, we already generated the required warning for the raise.
if Nkind (Original_Node (N)) = N_Raise_Statement then
return;
end if;
-- Otherwise see if we have a local handler for the exception
declare
H : constant Node_Id := Find_Local_Handler (E, N);
begin
-- If so, mark that it has a local raise
if Present (H) then
Set_Has_Local_Raise (H, True);
-- Otherwise, if the No_Exception_Propagation restriction is active
-- and the warning is enabled, generate the appropriate warnings.
elsif Warn_On_Non_Local_Exception
and then Restriction_Active (No_Exception_Propagation)
then
Warn_No_Exception_Propagation_Active (N);
if Configurable_Run_Time_Mode then
Error_Msg_NE
("\?X?& may call Last_Chance_Handler", N, E);
else
Error_Msg_NE
("\?X?& may result in unhandled exception", N, E);
end if;
end if;
end;
end Possible_Local_Raise;
------------------------
-- Find_Local_Handler --
------------------------
function Find_Local_Handler
(Ename : Entity_Id;
Nod : Node_Id) return Node_Id
is
N : Node_Id;
P : Node_Id;
H : Node_Id;
C : Node_Id;
SSE : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
-- This is used to test for wrapped actions below
ERaise : Entity_Id;
EHandle : Entity_Id;
-- The entity Id's for the exception we are raising and handling, using
-- the renamed exception if a Renamed_Entity is present.
begin
-- Never any local handler if all handlers removed
if Debug_Flag_Dot_X then
return Empty;
end if;
-- Get the exception we are raising, allowing for renaming
ERaise := Get_Renamed_Entity (Ename);
-- We need to check if the node we are looking at is contained in
--
-- Loop to search up the tree
N := Nod;
loop
P := Parent (N);
-- If we get to the top of the tree, or to a subprogram, task, entry,
-- protected body, or accept statement without having found a
-- matching handler, then there is no local handler.
if No (P)
or else Nkind (P) = N_Subprogram_Body
or else Nkind (P) = N_Task_Body
or else Nkind (P) = N_Protected_Body
or else Nkind (P) = N_Entry_Body
or else Nkind (P) = N_Accept_Statement
then
return Empty;
-- Test for handled sequence of statements with at least one
-- exception handler which might be the one we are looking for.
elsif Nkind (P) = N_Handled_Sequence_Of_Statements
and then Present (Exception_Handlers (P))
then
-- Before we proceed we need to check if the node N is covered
-- by the statement part of P rather than one of its exception
-- handlers (an exception handler obviously does not cover its
-- own statements).
-- This test is more delicate than might be thought. It is not
-- just a matter of checking the Statements (P), because the node
-- might be waiting to be wrapped in a transient scope, in which
-- case it will end up in the block statements, even though it
-- is not there now.
if Is_List_Member (N) then
declare
LCN : constant List_Id := List_Containing (N);
begin
if LCN = Statements (P)
or else
LCN = SSE.Actions_To_Be_Wrapped (Before)
or else
LCN = SSE.Actions_To_Be_Wrapped (After)
or else
LCN = SSE.Actions_To_Be_Wrapped (Cleanup)
then
-- Loop through exception handlers
H := First (Exception_Handlers (P));
while Present (H) loop
-- Guard against other constructs appearing in the
-- list of exception handlers.
if Nkind (H) = N_Exception_Handler then
-- Loop through choices in one handler
C := First (Exception_Choices (H));
while Present (C) loop
-- Deal with others case
if Nkind (C) = N_Others_Choice then
-- Matching others handler, but we need
-- to ensure there is no choice parameter.
-- If there is, then we don't have a local
-- handler after all (since we do not allow
-- choice parameters for local handlers).
if No (Choice_Parameter (H)) then
return H;
else
return Empty;
end if;
-- If not others must be entity name
elsif Nkind (C) /= N_Others_Choice then
pragma Assert (Is_Entity_Name (C));
pragma Assert (Present (Entity (C)));
-- Get exception being handled, dealing with
-- renaming.
EHandle := Get_Renamed_Entity (Entity (C));
-- If match, then check choice parameter
if ERaise = EHandle then
if No (Choice_Parameter (H)) then
return H;
else
return Empty;
end if;
end if;
end if;
Next (C);
end loop;
end if;
Next (H);
end loop;
end if;
end;
end if;
end if;
N := P;
end loop;
end Find_Local_Handler;
---------------------------------
-- Get_Local_Raise_Call_Entity --
---------------------------------
-- Note: this is primarily provided for use by the back end in generating
-- calls to Local_Raise. But it would be too late in the back end to call
-- RTE if this actually caused a load/analyze of the unit. So what we do
-- is to ensure there is a dummy call to this function during front end
-- processing so that the unit gets loaded then, and not later.
Local_Raise_Call_Entity : Entity_Id;
Local_Raise_Call_Entity_Set : Boolean := False;
function Get_Local_Raise_Call_Entity return Entity_Id is
begin
if not Local_Raise_Call_Entity_Set then
Local_Raise_Call_Entity_Set := True;
if RTE_Available (RE_Local_Raise) then
Local_Raise_Call_Entity := RTE (RE_Local_Raise);
else
Local_Raise_Call_Entity := Empty;
end if;
end if;
return Local_Raise_Call_Entity;
end Get_Local_Raise_Call_Entity;
-----------------------------
-- Get_RT_Exception_Entity --
-----------------------------
function Get_RT_Exception_Entity (R : RT_Exception_Code) return Entity_Id is
begin
case Rkind (R) is
when CE_Reason => return Standard_Constraint_Error;
when PE_Reason => return Standard_Program_Error;
when SE_Reason => return Standard_Storage_Error;
end case;
end Get_RT_Exception_Entity;
---------------------------
-- Get_RT_Exception_Name --
---------------------------
procedure Get_RT_Exception_Name (Code : RT_Exception_Code) is
begin
case Code is
when CE_Access_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Access_Check");
when CE_Access_Parameter_Is_Null =>
Add_Str_To_Name_Buffer ("CE_Null_Access_Parameter");
when CE_Discriminant_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Discriminant_Check");
when CE_Divide_By_Zero =>
Add_Str_To_Name_Buffer ("CE_Divide_By_Zero");
when CE_Explicit_Raise =>
Add_Str_To_Name_Buffer ("CE_Explicit_Raise");
when CE_Index_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Index_Check");
when CE_Invalid_Data =>
Add_Str_To_Name_Buffer ("CE_Invalid_Data");
when CE_Length_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Length_Check");
when CE_Null_Exception_Id =>
Add_Str_To_Name_Buffer ("CE_Null_Exception_Id");
when CE_Null_Not_Allowed =>
Add_Str_To_Name_Buffer ("CE_Null_Not_Allowed");
when CE_Overflow_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Overflow_Check");
when CE_Partition_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Partition_Check");
when CE_Range_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Range_Check");
when CE_Tag_Check_Failed =>
Add_Str_To_Name_Buffer ("CE_Tag_Check");
when PE_Access_Before_Elaboration =>
Add_Str_To_Name_Buffer ("PE_Access_Before_Elaboration");
when PE_Accessibility_Check_Failed =>
Add_Str_To_Name_Buffer ("PE_Accessibility_Check");
when PE_Address_Of_Intrinsic =>
Add_Str_To_Name_Buffer ("PE_Address_Of_Intrinsic");
when PE_Aliased_Parameters =>
Add_Str_To_Name_Buffer ("PE_Aliased_Parameters");
when PE_All_Guards_Closed =>
Add_Str_To_Name_Buffer ("PE_All_Guards_Closed");
when PE_Bad_Predicated_Generic_Type =>
Add_Str_To_Name_Buffer ("PE_Bad_Predicated_Generic_Type");
when PE_Current_Task_In_Entry_Body =>
Add_Str_To_Name_Buffer ("PE_Current_Task_In_Entry_Body");
when PE_Duplicated_Entry_Address =>
Add_Str_To_Name_Buffer ("PE_Duplicated_Entry_Address");
when PE_Explicit_Raise =>
Add_Str_To_Name_Buffer ("PE_Explicit_Raise");
when PE_Finalize_Raised_Exception =>
Add_Str_To_Name_Buffer ("PE_Finalize_Raised_Exception");
when PE_Implicit_Return =>
Add_Str_To_Name_Buffer ("PE_Implicit_Return");
when PE_Misaligned_Address_Value =>
Add_Str_To_Name_Buffer ("PE_Misaligned_Address_Value");
when PE_Missing_Return =>
Add_Str_To_Name_Buffer ("PE_Missing_Return");
when PE_Non_Transportable_Actual =>
Add_Str_To_Name_Buffer ("PE_Non_Transportable_Actual");
when PE_Overlaid_Controlled_Object =>
Add_Str_To_Name_Buffer ("PE_Overlaid_Controlled_Object");
when PE_Potentially_Blocking_Operation =>
Add_Str_To_Name_Buffer ("PE_Potentially_Blocking_Operation");
when PE_Stream_Operation_Not_Allowed =>
Add_Str_To_Name_Buffer ("PE_Stream_Operation_Not_Allowed");
when PE_Stubbed_Subprogram_Called =>
Add_Str_To_Name_Buffer ("PE_Stubbed_Subprogram_Called");
when PE_Unchecked_Union_Restriction =>
Add_Str_To_Name_Buffer ("PE_Unchecked_Union_Restriction");
when SE_Empty_Storage_Pool =>
Add_Str_To_Name_Buffer ("SE_Empty_Storage_Pool");
when SE_Explicit_Raise =>
Add_Str_To_Name_Buffer ("SE_Explicit_Raise");
when SE_Infinite_Recursion =>
Add_Str_To_Name_Buffer ("SE_Infinite_Recursion");
when SE_Object_Too_Large =>
Add_Str_To_Name_Buffer ("SE_Object_Too_Large");
end case;
end Get_RT_Exception_Name;
----------------------------
-- Warn_If_No_Propagation --
----------------------------
procedure Warn_If_No_Propagation (N : Node_Id) is
begin
if Restriction_Check_Required (No_Exception_Propagation)
and then Warn_On_Non_Local_Exception
then
Warn_No_Exception_Propagation_Active (N);
if Configurable_Run_Time_Mode then
Error_Msg_N
("\?X?Last_Chance_Handler will be called on exception", N);
else
Error_Msg_N
("\?X?execution may raise unhandled exception", N);
end if;
end if;
end Warn_If_No_Propagation;
------------------------------------------
-- Warn_No_Exception_Propagation_Active --
------------------------------------------
procedure Warn_No_Exception_Propagation_Active (N : Node_Id) is
begin
Error_Msg_N
("?X?pragma Restrictions (No_Exception_Propagation) in effect", N);
end Warn_No_Exception_Propagation_Active;
end Exp_Ch11;
|