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 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
|
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- A C C E S S I B I L I T Y --
-- --
-- B o d y --
-- --
-- Copyright (C) 2022-2024, 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 Checks; use Checks;
with Debug; use Debug;
with Einfo; use Einfo;
with Einfo.Entities; use Einfo.Entities;
with Elists; use Elists;
with Errout; use Errout;
with Einfo.Utils; use Einfo.Utils;
with Exp_Atag; use Exp_Atag;
with Exp_Ch3; use Exp_Ch3;
with Exp_Ch7; use Exp_Ch7;
with Exp_Tss; use Exp_Tss;
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 Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Ch8; use Sem_Ch8;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
with Sinfo.Nodes; use Sinfo.Nodes;
with Sinfo.Utils; use Sinfo.Utils;
with Snames; use Snames;
with Stand; use Stand;
with Tbuild; use Tbuild;
package body Accessibility is
---------------------------
-- Accessibility_Message --
---------------------------
procedure Accessibility_Message (N : Node_Id; Typ : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
P : constant Node_Id := Prefix (N);
Indic : Node_Id := Parent (Parent (N));
begin
-- In an instance, this is a runtime check, but one we know will fail,
-- so generate an appropriate warning.
if In_Instance_Body then
Error_Msg_Warn := SPARK_Mode /= On;
Error_Msg_F
("non-local pointer cannot point to local object<<", P);
Error_Msg_F ("\Program_Error [<<", P);
Rewrite (N,
Make_Raise_Program_Error (Loc,
Reason => PE_Accessibility_Check_Failed));
Set_Etype (N, Typ);
return;
else
Error_Msg_F ("non-local pointer cannot point to local object", P);
-- Check for case where we have a missing access definition
if Is_Record_Type (Current_Scope)
and then
Nkind (Parent (N)) in N_Discriminant_Association
| N_Index_Or_Discriminant_Constraint
then
Indic := Parent (Parent (N));
while Present (Indic)
and then Nkind (Indic) /= N_Subtype_Indication
loop
Indic := Parent (Indic);
end loop;
if Present (Indic) then
Error_Msg_NE
("\use an access definition for" &
" the access discriminant of&",
N, Entity (Subtype_Mark (Indic)));
end if;
end if;
end if;
end Accessibility_Message;
-------------------------
-- Accessibility_Level --
-------------------------
function Accessibility_Level
(Expr : Node_Id;
Level : Accessibility_Level_Kind;
In_Return_Context : Boolean := False;
Allow_Alt_Model : Boolean := True) return Node_Id
is
Loc : constant Source_Ptr := Sloc (Expr);
function Accessibility_Level (Expr : Node_Id) return Node_Id is
(Accessibility_Level
(Expr, Level, In_Return_Context, Allow_Alt_Model));
-- Renaming of the enclosing function to facilitate recursive calls
function Make_Level_Literal (Level : Uint) return Node_Id;
-- Construct an integer literal representing an accessibility level with
-- its type set to Natural.
function Innermost_Master_Scope_Depth (N : Node_Id) return Uint;
-- Returns the scope depth of the given node's innermost enclosing scope
-- (effectively the accessibility level of the innermost enclosing
-- master).
function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id;
-- Centralized processing of subprogram calls which may appear in prefix
-- notation.
function Typ_Access_Level (Typ : Entity_Id) return Uint
is (Type_Access_Level (Typ, Allow_Alt_Model));
-- Renaming of Type_Access_Level with Allow_Alt_Model specified to avoid
-- passing the parameter specifically in every call.
----------------------------------
-- Innermost_Master_Scope_Depth --
----------------------------------
function Innermost_Master_Scope_Depth (N : Node_Id) return Uint is
Encl_Scop : Entity_Id;
Ent : Entity_Id;
Node_Par : Node_Id := Parent (N);
Master_Lvl_Modifier : Int := 0;
begin
-- Locate the nearest enclosing node (by traversing Parents)
-- that Defining_Entity can be applied to, and return the
-- depth of that entity's nearest enclosing scope.
-- The RM 7.6.1(3) definition of "master" includes statements
-- and conditions for loops among other things. Are these cases
-- detected properly ???
while Present (Node_Par) loop
Ent := Defining_Entity_Or_Empty (Node_Par);
if Present (Ent) then
-- X'Old is nested within the current subprogram, so we do not
-- want Find_Enclosing_Scope of that subprogram. If this is an
-- allocator, then we're looking for the innermost master of
-- the call, so again we do not want Find_Enclosing_Scope.
if (Nkind (N) = N_Attribute_Reference
and then Attribute_Name (N) = Name_Old)
or else Nkind (N) = N_Allocator
then
Encl_Scop := Ent;
else
Encl_Scop := Find_Enclosing_Scope (Ent);
end if;
-- Ignore transient scopes made during expansion while also
-- taking into account certain expansions - like iterators
-- which get expanded into renamings and thus not marked
-- as coming from source.
if Comes_From_Source (Node_Par)
or else (Nkind (Node_Par) = N_Object_Renaming_Declaration
and then Comes_From_Iterator (Node_Par))
then
-- Note that in some rare cases the scope depth may not be
-- set, for example, when we are in the middle of analyzing
-- a type and the enclosing scope is said type. In that case
-- simply return zero for the outermost scope.
if Scope_Depth_Set (Encl_Scop) then
return Scope_Depth (Encl_Scop) + Master_Lvl_Modifier;
else
return Uint_0;
end if;
end if;
-- For a return statement within a function, return
-- the depth of the function itself. This is not just
-- a small optimization, but matters when analyzing
-- the expression in an expression function before
-- the body is created.
elsif Nkind (Node_Par) in N_Extended_Return_Statement
| N_Simple_Return_Statement
then
return Scope_Depth (Enclosing_Subprogram (Node_Par));
-- Statements are counted as masters
elsif Is_Master (Node_Par) then
Master_Lvl_Modifier := Master_Lvl_Modifier + 1;
end if;
Node_Par := Parent (Node_Par);
end loop;
-- Should never reach the following return
pragma Assert (False);
return Scope_Depth (Current_Scope) + 1;
end Innermost_Master_Scope_Depth;
------------------------
-- Make_Level_Literal --
------------------------
function Make_Level_Literal (Level : Uint) return Node_Id is
Result : constant Node_Id := Make_Integer_Literal (Loc, Level);
begin
Set_Etype (Result, Standard_Natural);
return Result;
end Make_Level_Literal;
--------------------------------------
-- Function_Call_Or_Allocator_Level --
--------------------------------------
function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id is
Par : Node_Id;
Prev_Par : Node_Id;
begin
-- Results of functions are objects, so we either get the
-- accessibility of the function or, in case of a call which is
-- indirect, the level of the access-to-subprogram type.
-- This code looks wrong ???
if Nkind (N) = N_Function_Call
and then Ada_Version < Ada_2005
then
if Is_Entity_Name (Name (N)) then
return Make_Level_Literal
(Subprogram_Access_Level (Entity (Name (N))));
else
return Make_Level_Literal
(Typ_Access_Level (Etype (Prefix (Name (N)))));
end if;
-- We ignore coextensions as they cannot be implemented under the
-- "small-integer" model.
elsif Nkind (N) = N_Allocator
and then (Is_Static_Coextension (N)
or else Is_Dynamic_Coextension (N))
then
return Make_Level_Literal (Scope_Depth (Standard_Standard));
end if;
-- Named access types have a designated level
if Is_Named_Access_Type (Etype (N)) then
return Make_Level_Literal (Typ_Access_Level (Etype (N)));
-- Otherwise, the level is dictated by RM 3.10.2 (10.7/3)
else
-- Check No_Dynamic_Accessibility_Checks restriction override for
-- alternative accessibility model.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (N)
and then Is_Anonymous_Access_Type (Etype (N))
then
-- In the alternative model the level is that of the
-- designated type.
if Debug_Flag_Underscore_B then
return Make_Level_Literal (Typ_Access_Level (Etype (N)));
-- For function calls the level is that of the innermost
-- master, otherwise (for allocators etc.) we get the level
-- of the corresponding anonymous access type, which is
-- calculated through the normal path of execution.
elsif Nkind (N) = N_Function_Call then
return Make_Level_Literal
(Innermost_Master_Scope_Depth (Expr));
end if;
end if;
if Nkind (N) = N_Function_Call then
-- Dynamic checks are generated when we are within a return
-- value or we are in a function call within an anonymous
-- access discriminant constraint of a return object (signified
-- by In_Return_Context) on the side of the callee.
-- So, in this case, return accessibility level of the
-- enclosing subprogram.
if In_Return_Value (N)
or else In_Return_Context
then
return Make_Level_Literal
(Subprogram_Access_Level (Current_Subprogram));
end if;
end if;
-- When the call is being dereferenced the level is that of the
-- enclosing master of the dereferenced call.
if Nkind (Parent (N)) in N_Explicit_Dereference
| N_Indexed_Component
| N_Selected_Component
then
return Make_Level_Literal
(Innermost_Master_Scope_Depth (Expr));
end if;
-- Find any relevant enclosing parent nodes that designate an
-- object being initialized.
-- Note: The above is only relevant if the result is used "in its
-- entirety" as RM 3.10.2 (10.2/3) states. However, this is
-- accounted for in the case statement in the main body of
-- Accessibility_Level for N_Selected_Component.
Par := Parent (Expr);
Prev_Par := Empty;
while Present (Par) loop
-- Detect an expanded implicit conversion, typically this
-- occurs on implicitly converted actuals in calls.
-- Does this catch all implicit conversions ???
if Nkind (Par) = N_Type_Conversion
and then Is_Named_Access_Type (Etype (Par))
then
return Make_Level_Literal
(Typ_Access_Level (Etype (Par)));
end if;
-- Jump out when we hit an object declaration or the right-hand
-- side of an assignment, or a construct such as an aggregate
-- subtype indication which would be the result is not used
-- "in its entirety."
exit when Nkind (Par) in N_Object_Declaration
or else (Nkind (Par) = N_Assignment_Statement
and then Name (Par) /= Prev_Par);
Prev_Par := Par;
Par := Parent (Par);
end loop;
-- Assignment statements are handled in a similar way in
-- accordance to the left-hand part. However, strictly speaking,
-- this is illegal according to the RM, but this change is needed
-- to pass an ACATS C-test and is useful in general ???
case Nkind (Par) is
when N_Object_Declaration =>
return Make_Level_Literal
(Scope_Depth
(Scope (Defining_Identifier (Par))));
when N_Assignment_Statement =>
-- Return the accessibility level of the left-hand part
return Accessibility_Level
(Expr => Name (Par),
Level => Object_Decl_Level,
In_Return_Context => In_Return_Context);
when others =>
return Make_Level_Literal
(Innermost_Master_Scope_Depth (Expr));
end case;
end if;
end Function_Call_Or_Allocator_Level;
-- Local variables
E : Node_Id := Original_Node (Expr);
Pre : Node_Id;
-- Start of processing for Accessibility_Level
begin
-- We could be looking at a reference to a formal due to the expansion
-- of entries and other cases, so obtain the renaming if necessary.
if Present (Param_Entity (Expr)) then
E := Param_Entity (Expr);
end if;
-- Extract the entity
if Nkind (E) in N_Has_Entity and then Present (Entity (E)) then
E := Entity (E);
-- Deal with a possible renaming of a private protected component
if Ekind (E) in E_Constant | E_Variable and then Is_Prival (E) then
E := Prival_Link (E);
end if;
end if;
-- Perform the processing on the expression
case Nkind (E) is
-- The level of an aggregate is that of the innermost master that
-- evaluates it as defined in RM 3.10.2 (10/4).
when N_Aggregate =>
return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
-- The accessibility level is that of the access type, except for
-- anonymous allocators which have special rules defined in RM 3.10.2
-- (14/3).
when N_Allocator =>
return Function_Call_Or_Allocator_Level (E);
-- We could reach this point for two reasons. Either the expression
-- applies to a special attribute ('Loop_Entry, 'Result, or 'Old), or
-- we are looking at the access attributes directly ('Access,
-- 'Address, or 'Unchecked_Access).
when N_Attribute_Reference =>
Pre := Original_Node (Prefix (E));
-- Regular 'Access attribute presence means we have to look at the
-- prefix.
if Attribute_Name (E) = Name_Access then
return Accessibility_Level (Prefix (E));
-- Unchecked or unrestricted attributes have unlimited depth
elsif Attribute_Name (E) in Name_Address
| Name_Unchecked_Access
| Name_Unrestricted_Access
then
return Make_Level_Literal (Scope_Depth (Standard_Standard));
-- 'Access can be taken further against other special attributes,
-- so handle these cases explicitly.
elsif Attribute_Name (E)
in Name_Old | Name_Loop_Entry | Name_Result
then
-- Named access types
if Is_Named_Access_Type (Etype (Pre)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (Pre)));
-- Anonymous access types
elsif Nkind (Pre) in N_Has_Entity
and then Ekind (Entity (Pre)) not in Subprogram_Kind
and then Present (Get_Dynamic_Accessibility (Entity (Pre)))
and then Level = Dynamic_Level
then
pragma Assert (Is_Anonymous_Access_Type (Etype (Pre)));
return New_Occurrence_Of
(Get_Dynamic_Accessibility (Entity (Pre)), Loc);
-- Otherwise the level is treated in a similar way as
-- aggregates according to RM 6.1.1 (35.1/4) which concerns
-- an implicit constant declaration - in turn defining the
-- accessibility level to be that of the implicit constant
-- declaration.
else
return Make_Level_Literal
(Innermost_Master_Scope_Depth (Expr));
end if;
else
raise Program_Error;
end if;
-- This is the "base case" for accessibility level calculations which
-- means we are near the end of our recursive traversal.
when N_Defining_Identifier =>
-- A dynamic check is performed on the side of the callee when we
-- are within a return statement, so return a library-level
-- accessibility level to null out checks on the side of the
-- caller.
if Is_Explicitly_Aliased (E)
and then (In_Return_Context
or else (Level /= Dynamic_Level
and then In_Return_Value (Expr)))
then
return Make_Level_Literal (Scope_Depth (Standard_Standard));
-- Something went wrong and an extra accessibility formal has not
-- been generated when one should have ???
elsif Is_Formal (E)
and then No (Get_Dynamic_Accessibility (E))
and then Ekind (Etype (E)) = E_Anonymous_Access_Type
then
return Make_Level_Literal (Scope_Depth (Standard_Standard));
-- Stand-alone object of an anonymous access type "SAOAAT"
elsif (Is_Formal (E)
or else Ekind (E) in E_Variable
| E_Constant)
and then Present (Get_Dynamic_Accessibility (E))
and then (Level = Dynamic_Level
or else Level = Zero_On_Dynamic_Level)
then
if Level = Zero_On_Dynamic_Level then
return Make_Level_Literal
(Scope_Depth (Standard_Standard));
end if;
-- No_Dynamic_Accessibility_Checks restriction override for
-- alternative accessibility model.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (E)
then
-- In the alternative model the level is that of the
-- designated type entity's context.
if Debug_Flag_Underscore_B then
return Make_Level_Literal (Typ_Access_Level (Etype (E)));
-- Otherwise the level depends on the entity's context
elsif Is_Formal (E) then
return Make_Level_Literal
(Subprogram_Access_Level
(Enclosing_Subprogram (E)));
else
return Make_Level_Literal
(Scope_Depth (Enclosing_Dynamic_Scope (E)));
end if;
end if;
-- Return the dynamic level in the normal case
return New_Occurrence_Of
(Get_Dynamic_Accessibility (E), Loc);
-- Initialization procedures have a special extra accessibility
-- parameter associated with the level at which the object
-- being initialized exists
elsif Ekind (E) = E_Record_Type
and then Is_Limited_Record (E)
and then Current_Scope = Init_Proc (E)
and then Present (Init_Proc_Level_Formal (Current_Scope))
then
return New_Occurrence_Of
(Init_Proc_Level_Formal (Current_Scope), Loc);
-- Current instance of the type is deeper than that of the type
-- according to RM 3.10.2 (21).
elsif Is_Type (E) then
-- When restriction No_Dynamic_Accessibility_Checks is active
-- along with -gnatd_b.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (E)
and then Debug_Flag_Underscore_B
then
return Make_Level_Literal (Typ_Access_Level (E));
end if;
-- Normal path
return Make_Level_Literal (Typ_Access_Level (E) + 1);
-- Move up the renamed entity or object if it came from source
-- since expansion may have created a dummy renaming under
-- certain circumstances.
-- Note: We check if the original node of the renaming comes
-- from source because the node may have been rewritten.
elsif Present (Renamed_Entity_Or_Object (E))
and then Comes_From_Source
(Original_Node (Renamed_Entity_Or_Object (E)))
then
return Accessibility_Level (Renamed_Entity_Or_Object (E));
-- Named access types get their level from their associated type
elsif Is_Named_Access_Type (Etype (E)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (E)));
-- Check if E is an expansion-generated renaming of an iterator
-- by examining Related_Expression. If so, determine the
-- accessibility level based on the original expression.
elsif Ekind (E) in E_Constant | E_Variable
and then Present (Related_Expression (E))
then
return Accessibility_Level (Related_Expression (E));
elsif Level = Dynamic_Level
and then Ekind (E) in E_In_Parameter | E_In_Out_Parameter
and then Present (Init_Proc_Level_Formal (Scope (E)))
then
return New_Occurrence_Of
(Init_Proc_Level_Formal (Scope (E)), Loc);
-- Normal object - get the level of the enclosing scope
else
return Make_Level_Literal
(Scope_Depth (Enclosing_Dynamic_Scope (E)));
end if;
-- Handle indexed and selected components including the special cases
-- whereby there is an implicit dereference, a component of a
-- composite type, or a function call in prefix notation.
-- We don't handle function calls in prefix notation correctly ???
when N_Indexed_Component | N_Selected_Component | N_Slice =>
Pre := Prefix (E);
-- Fetch the original node when the prefix comes from the result
-- of expanding a function call since we want to find the level
-- of the original source call.
if not Comes_From_Source (Pre)
and then Nkind (Original_Node (Pre)) = N_Function_Call
then
Pre := Original_Node (Pre);
end if;
-- When E is an indexed component or selected component and
-- the current Expr is a function call, we know that we are
-- looking at an expanded call in prefix notation.
if Nkind (Expr) = N_Function_Call then
return Function_Call_Or_Allocator_Level (Expr);
-- If the prefix is a named access type, then we are dealing
-- with an implicit deferences. In that case the level is that
-- of the named access type in the prefix.
elsif Is_Named_Access_Type (Etype (Pre)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (Pre)));
-- The current expression is a named access type, so there is no
-- reason to look at the prefix. Instead obtain the level of E's
-- named access type.
elsif Is_Named_Access_Type (Etype (E)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (E)));
-- A nondiscriminant selected component where the component
-- is an anonymous access type means that its associated
-- level is that of the containing type - see RM 3.10.2 (16).
-- Note that when restriction No_Dynamic_Accessibility_Checks is
-- in effect we treat discriminant components as regular
-- components.
elsif
(Nkind (E) = N_Selected_Component
and then Ekind (Etype (E)) = E_Anonymous_Access_Type
and then Ekind (Etype (Pre)) /= E_Anonymous_Access_Type
and then (not (Nkind (Selector_Name (E)) in N_Has_Entity
and then Ekind (Entity (Selector_Name (E)))
= E_Discriminant)
-- The alternative accessibility models both treat
-- discriminants as regular components.
or else (No_Dynamic_Accessibility_Checks_Enabled (E)
and then Allow_Alt_Model)))
-- Arrays featuring components of anonymous access components
-- get their corresponding level from their containing type's
-- declaration.
or else
(Nkind (E) = N_Indexed_Component
and then Ekind (Etype (E)) = E_Anonymous_Access_Type
and then Ekind (Etype (Pre)) in Array_Kind
and then Ekind (Component_Type (Base_Type (Etype (Pre))))
= E_Anonymous_Access_Type)
then
-- When restriction No_Dynamic_Accessibility_Checks is active
-- and -gnatd_b set, the level is that of the designated type.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (E)
and then Debug_Flag_Underscore_B
then
return Make_Level_Literal
(Typ_Access_Level (Etype (E)));
end if;
-- Otherwise proceed normally
return Make_Level_Literal
(Typ_Access_Level (Etype (Prefix (E))));
-- The accessibility calculation routine that handles function
-- calls (Function_Call_Level) assumes, in the case the
-- result is of an anonymous access type, that the result will be
-- used "in its entirety" when the call is present within an
-- assignment or object declaration.
-- To properly handle cases where the result is not used in its
-- entirety, we test if the prefix of the component in question is
-- a function call, which tells us that one of its components has
-- been identified and is being accessed. Therefore we can
-- conclude that the result is not used "in its entirety"
-- according to RM 3.10.2 (10.2/3).
elsif Nkind (Pre) = N_Function_Call
and then not Is_Named_Access_Type (Etype (Pre))
then
-- Dynamic checks are generated when we are within a return
-- value or we are in a function call within an anonymous
-- access discriminant constraint of a return object (signified
-- by In_Return_Context) on the side of the callee.
-- So, in this case, return a library accessibility level to
-- null out the check on the side of the caller.
if (In_Return_Value (E)
or else In_Return_Context)
and then Level /= Dynamic_Level
then
return Make_Level_Literal
(Scope_Depth (Standard_Standard));
end if;
return Make_Level_Literal
(Innermost_Master_Scope_Depth (Expr));
-- Otherwise, continue recursing over the expression prefixes
else
return Accessibility_Level (Prefix (E));
end if;
-- Qualified expressions
when N_Qualified_Expression =>
if Is_Named_Access_Type (Etype (E)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (E)));
else
return Accessibility_Level (Expression (E));
end if;
-- Handle function calls
when N_Function_Call =>
return Function_Call_Or_Allocator_Level (E);
-- Explicit dereference accessibility level calculation
when N_Explicit_Dereference =>
Pre := Original_Node (Prefix (E));
-- The prefix is a named access type so the level is taken from
-- its type.
if Is_Named_Access_Type (Etype (Pre)) then
return Make_Level_Literal (Typ_Access_Level (Etype (Pre)));
-- Otherwise, recurse deeper
else
return Accessibility_Level (Prefix (E));
end if;
-- Type conversions
when N_Type_Conversion | N_Unchecked_Type_Conversion =>
-- View conversions are special in that they require use to
-- inspect the expression of the type conversion.
-- Allocators of anonymous access types are internally generated,
-- so recurse deeper in that case as well.
if Is_View_Conversion (E)
or else Ekind (Etype (E)) = E_Anonymous_Access_Type
then
return Accessibility_Level (Expression (E));
-- We don't care about the master if we are looking at a named
-- access type.
elsif Is_Named_Access_Type (Etype (E)) then
return Make_Level_Literal
(Typ_Access_Level (Etype (E)));
-- In section RM 3.10.2 (10/4) the accessibility rules for
-- aggregates and value conversions are outlined. Are these
-- followed in the case of initialization of an object ???
-- Should use Innermost_Master_Scope_Depth ???
else
return Accessibility_Level (Current_Scope);
end if;
-- Default to the type accessibility level for the type of the
-- expression's entity.
when others =>
return Make_Level_Literal (Typ_Access_Level (Etype (E)));
end case;
end Accessibility_Level;
-------------------------------
-- Apply_Accessibility_Check --
-------------------------------
procedure Apply_Accessibility_Check
(N : Node_Id;
Typ : Entity_Id;
Insert_Node : Node_Id)
is
Loc : constant Source_Ptr := Sloc (N);
Check_Cond : Node_Id;
Param_Ent : Entity_Id := Param_Entity (N);
Param_Level : Node_Id;
Type_Level : Node_Id;
begin
-- Verify we haven't tried to add a dynamic accessibility check when we
-- shouldn't.
pragma Assert (not No_Dynamic_Accessibility_Checks_Enabled (N));
if Ada_Version >= Ada_2012
and then No (Param_Ent)
and then Is_Entity_Name (N)
and then Ekind (Entity (N)) in E_Constant | E_Variable
and then Present (Effective_Extra_Accessibility (Entity (N)))
then
Param_Ent := Entity (N);
while Present (Renamed_Object (Param_Ent)) loop
-- Renamed_Object must return an Entity_Name here
-- because of preceding "Present (E_E_A (...))" test.
Param_Ent := Entity (Renamed_Object (Param_Ent));
end loop;
end if;
if Inside_A_Generic then
return;
-- Only apply the run-time check if the access parameter has an
-- associated extra access level parameter and when accessibility checks
-- are enabled.
elsif Present (Param_Ent)
and then Present (Get_Dynamic_Accessibility (Param_Ent))
and then not Accessibility_Checks_Suppressed (Param_Ent)
and then not Accessibility_Checks_Suppressed (Typ)
then
-- Obtain the parameter's accessibility level
Param_Level :=
New_Occurrence_Of (Get_Dynamic_Accessibility (Param_Ent), Loc);
-- Use the dynamic accessibility parameter for the function's result
-- when one has been created instead of statically referring to the
-- deepest type level so as to appropriatly handle the rules for
-- RM 3.10.2 (10.1/3).
if Ekind (Scope (Param_Ent)) = E_Function
and then In_Return_Value (N)
and then Ekind (Typ) = E_Anonymous_Access_Type
then
-- Associate the level of the result type to the extra result
-- accessibility parameter belonging to the current function.
if Present (Extra_Accessibility_Of_Result (Scope (Param_Ent))) then
Type_Level :=
New_Occurrence_Of
(Extra_Accessibility_Of_Result (Scope (Param_Ent)), Loc);
-- In Ada 2005 and earlier modes, a result extra accessibility
-- parameter is not generated and no dynamic check is performed.
else
return;
end if;
-- Otherwise get the type's accessibility level normally
else
Type_Level :=
Make_Integer_Literal (Loc, Deepest_Type_Access_Level (Typ));
end if;
-- Raise Program_Error if the accessibility level of the access
-- parameter is deeper than the level of the target access type.
Check_Cond :=
Make_Op_Gt (Loc,
Left_Opnd => Param_Level,
Right_Opnd => Type_Level);
Insert_Action (Insert_Node,
Make_Raise_Program_Error (Loc,
Condition => Check_Cond,
Reason => PE_Accessibility_Check_Failed));
Analyze_And_Resolve (N);
-- If constant folding has happened on the condition for the
-- generated error, then warn about it being unconditional.
if Nkind (Check_Cond) = N_Identifier
and then Entity (Check_Cond) = Standard_True
then
Error_Msg_Warn := SPARK_Mode /= On;
Error_Msg_N ("accessibility check fails<<", N);
Error_Msg_N ("\Program_Error [<<", N);
end if;
end if;
end Apply_Accessibility_Check;
---------------------------------------------
-- Apply_Accessibility_Check_For_Allocator --
---------------------------------------------
procedure Apply_Accessibility_Check_For_Allocator
(N : Node_Id;
Exp : Node_Id;
Ref : Node_Id;
Built_In_Place : Boolean := False)
is
Loc : constant Source_Ptr := Sloc (N);
PtrT : constant Entity_Id := Etype (N);
DesigT : constant Entity_Id := Designated_Type (PtrT);
Pool_Id : constant Entity_Id := Associated_Storage_Pool (PtrT);
Cond : Node_Id;
Fin_Call : Node_Id;
Free_Stmt : Node_Id;
Obj_Ref : Node_Id;
Stmts : List_Id;
begin
if Ada_Version >= Ada_2005
and then Is_Class_Wide_Type (DesigT)
and then Tagged_Type_Expansion
and then not Scope_Suppress.Suppress (Accessibility_Check)
and then not No_Dynamic_Accessibility_Checks_Enabled (Ref)
and then
(Type_Access_Level (Etype (Exp)) > Type_Access_Level (PtrT)
or else
(Is_Class_Wide_Type (Etype (Exp))
and then Scope (PtrT) /= Current_Scope))
then
-- If the allocator was built in place, Ref is already a reference
-- to the access object initialized to the result of the allocator
-- (see Exp_Ch6.Make_Build_In_Place_Call_In_Allocator). We call
-- Remove_Side_Effects for cases where the build-in-place call may
-- still be the prefix of the reference (to avoid generating
-- duplicate calls). Otherwise, it is the entity associated with
-- the object containing the address of the allocated object.
if Built_In_Place then
Remove_Side_Effects (Ref);
Obj_Ref := New_Copy_Tree (Ref);
else
Obj_Ref := New_Occurrence_Of (Ref, Loc);
end if;
-- For access to interface types we must generate code to displace
-- the pointer to the base of the object since the subsequent code
-- references components located in the TSD of the object (which
-- is associated with the primary dispatch table --see a-tags.ads)
-- and also generates code invoking Free, which requires also a
-- reference to the base of the unallocated object.
if Is_Interface (DesigT) and then Tagged_Type_Expansion then
Obj_Ref :=
Unchecked_Convert_To (Etype (Obj_Ref),
Make_Function_Call (Loc,
Name =>
New_Occurrence_Of (RTE (RE_Base_Address), Loc),
Parameter_Associations => New_List (
Unchecked_Convert_To (RTE (RE_Address),
New_Copy_Tree (Obj_Ref)))));
end if;
-- Step 1: Create the object clean up code
Stmts := New_List;
-- Deallocate the object if the accessibility check fails. This is
-- done only on targets or profiles that support deallocation.
-- Free (Obj_Ref);
if RTE_Available (RE_Free) then
Free_Stmt := Make_Free_Statement (Loc, New_Copy_Tree (Obj_Ref));
Set_Storage_Pool (Free_Stmt, Pool_Id);
Append_To (Stmts, Free_Stmt);
-- The target or profile cannot deallocate objects
else
Free_Stmt := Empty;
end if;
-- Finalize the object if applicable. Generate:
-- [Deep_]Finalize (Obj_Ref.all);
if Needs_Finalization (DesigT)
and then not No_Heap_Finalization (PtrT)
then
Fin_Call :=
Make_Final_Call
(Obj_Ref =>
Make_Explicit_Dereference (Loc, New_Copy (Obj_Ref)),
Typ => DesigT);
-- Guard against a missing [Deep_]Finalize when the designated
-- type was not properly frozen.
if No (Fin_Call) then
Fin_Call := Make_Null_Statement (Loc);
end if;
-- When the target or profile supports deallocation, wrap the
-- finalization call in a block to ensure proper deallocation even
-- if finalization fails. Generate:
-- begin
-- <Fin_Call>
-- exception
-- when others =>
-- <Free_Stmt>
-- raise;
-- end;
if Present (Free_Stmt) then
Fin_Call :=
Make_Block_Statement (Loc,
Handled_Statement_Sequence =>
Make_Handled_Sequence_Of_Statements (Loc,
Statements => New_List (Fin_Call),
Exception_Handlers => New_List (
Make_Exception_Handler (Loc,
Exception_Choices => New_List (
Make_Others_Choice (Loc)),
Statements => New_List (
New_Copy_Tree (Free_Stmt),
Make_Raise_Statement (Loc))))));
end if;
Prepend_To (Stmts, Fin_Call);
end if;
-- Signal the accessibility failure through a Program_Error
Append_To (Stmts,
Make_Raise_Program_Error (Loc,
Reason => PE_Accessibility_Check_Failed));
-- Step 2: Create the accessibility comparison
-- Generate:
-- Ref'Tag
Obj_Ref :=
Make_Attribute_Reference (Loc,
Prefix => Obj_Ref,
Attribute_Name => Name_Tag);
-- For tagged types, determine the accessibility level by looking at
-- the type specific data of the dispatch table. Generate:
-- Type_Specific_Data (Address (Ref'Tag)).Access_Level
if Tagged_Type_Expansion then
Cond := Build_Get_Access_Level (Loc, Obj_Ref);
-- Use a runtime call to determine the accessibility level when
-- compiling on virtual machine targets. Generate:
-- Get_Access_Level (Ref'Tag)
else
Cond :=
Make_Function_Call (Loc,
Name =>
New_Occurrence_Of (RTE (RE_Get_Access_Level), Loc),
Parameter_Associations => New_List (Obj_Ref));
end if;
Cond :=
Make_Op_Gt (Loc,
Left_Opnd => Cond,
Right_Opnd => Accessibility_Level (N, Dynamic_Level));
-- Due to the complexity and side effects of the check, utilize an if
-- statement instead of the regular Program_Error circuitry.
Insert_Action (N,
Make_Implicit_If_Statement (N,
Condition => Cond,
Then_Statements => Stmts));
end if;
end Apply_Accessibility_Check_For_Allocator;
------------------------------------------
-- Check_Return_Construct_Accessibility --
------------------------------------------
procedure Check_Return_Construct_Accessibility
(Return_Stmt : Node_Id;
Stm_Entity : Entity_Id)
is
Loc : constant Source_Ptr := Sloc (Return_Stmt);
Scope_Id : constant Entity_Id := Return_Applies_To (Stm_Entity);
R_Type : constant Entity_Id := Etype (Scope_Id);
-- Function result subtype
function First_Selector (Assoc : Node_Id) return Node_Id;
-- Obtain the first selector or choice from a given association
function Is_Formal_Of_Current_Function
(Assoc_Expr : Node_Id) return Boolean;
-- Predicate to test if a given expression associated with a
-- discriminant is a formal parameter to the function in which the
-- return construct we checking applies to.
--------------------
-- First_Selector --
--------------------
function First_Selector (Assoc : Node_Id) return Node_Id is
begin
if Nkind (Assoc) = N_Component_Association then
return First (Choices (Assoc));
elsif Nkind (Assoc) = N_Discriminant_Association then
return (First (Selector_Names (Assoc)));
else
raise Program_Error;
end if;
end First_Selector;
-----------------------------------
-- Is_Formal_Of_Current_Function --
-----------------------------------
function Is_Formal_Of_Current_Function
(Assoc_Expr : Node_Id) return Boolean is
begin
return Is_Entity_Name (Assoc_Expr)
and then Enclosing_Subprogram
(Entity (Assoc_Expr)) = Scope_Id
and then Is_Formal (Entity (Assoc_Expr));
end Is_Formal_Of_Current_Function;
-- Local declarations
Assoc : Node_Id := Empty;
-- Assoc should perhaps be renamed and declared as a
-- Node_Or_Entity_Id since it encompasses not only component and
-- discriminant associations, but also discriminant components within
-- a type declaration or subtype indication ???
Assoc_Expr : Node_Id;
Assoc_Present : Boolean := False;
Check_Cond : Node_Id;
Unseen_Disc_Count : Nat := 0;
Seen_Discs : Elist_Id;
Disc : Entity_Id;
First_Disc : Entity_Id;
Obj_Decl : Node_Id;
Return_Con : Node_Id;
Unqual : Node_Id;
-- Start of processing for Check_Return_Construct_Accessibility
begin
-- Only perform checks on record types with access discriminants and
-- non-internally generated functions.
if not Is_Record_Type (R_Type)
or else not Has_Anonymous_Access_Discriminant (R_Type)
or else not Comes_From_Source (Return_Stmt)
then
return;
end if;
-- We are only interested in return statements
if Nkind (Return_Stmt) not in
N_Extended_Return_Statement | N_Simple_Return_Statement
then
return;
end if;
-- Fetch the object from the return statement, in the case of a
-- simple return statement the expression is part of the node.
if Nkind (Return_Stmt) = N_Extended_Return_Statement then
-- Obtain the object definition from the expanded extended return
Return_Con := First (Return_Object_Declarations (Return_Stmt));
while Present (Return_Con) loop
-- Inspect the original node to avoid object declarations
-- expanded into renamings.
if Nkind (Original_Node (Return_Con)) = N_Object_Declaration
and then Comes_From_Source (Original_Node (Return_Con))
then
exit;
end if;
Nlists.Next (Return_Con);
end loop;
pragma Assert (Present (Return_Con));
-- Could be dealing with a renaming
Return_Con := Original_Node (Return_Con);
else
Return_Con := Expression (Return_Stmt);
end if;
-- Obtain the accessibility levels of the expressions associated
-- with all anonymous access discriminants, then generate a
-- dynamic check or static error when relevant.
-- Note the repeated use of Original_Node to avoid checking
-- expanded code.
Unqual := Original_Node (Unqualify (Original_Node (Return_Con)));
-- Get the corresponding declaration based on the return object's
-- identifier.
if Nkind (Unqual) = N_Identifier
and then Nkind (Parent (Entity (Unqual)))
in N_Object_Declaration
| N_Object_Renaming_Declaration
then
Obj_Decl := Original_Node (Parent (Entity (Unqual)));
-- We were passed the object declaration directly, so use it
elsif Nkind (Unqual) in N_Object_Declaration
| N_Object_Renaming_Declaration
then
Obj_Decl := Unqual;
-- Otherwise, we are looking at something else
else
Obj_Decl := Empty;
end if;
-- Hop up object renamings when present
if Present (Obj_Decl)
and then Nkind (Obj_Decl) = N_Object_Renaming_Declaration
then
while Nkind (Obj_Decl) = N_Object_Renaming_Declaration loop
if Nkind (Name (Obj_Decl)) not in N_Entity then
-- We may be looking at the expansion of iterators or
-- some other internally generated construct, so it is safe
-- to ignore checks ???
if not Comes_From_Source (Obj_Decl) then
return;
end if;
Obj_Decl := Original_Node
(Declaration_Node
(Ultimate_Prefix (Name (Obj_Decl))));
-- Move up to the next declaration based on the object's name
else
Obj_Decl := Original_Node
(Declaration_Node (Name (Obj_Decl)));
end if;
end loop;
end if;
-- Obtain the discriminant values from the return aggregate
-- Do we cover extension aggregates correctly ???
if Nkind (Unqual) = N_Aggregate then
if Present (Expressions (Unqual)) then
Assoc := First (Expressions (Unqual));
else
Assoc := First (Component_Associations (Unqual));
end if;
-- There is an object declaration for the return object
elsif Present (Obj_Decl) then
-- When a subtype indication is present in an object declaration
-- it must contain the object's discriminants.
if Nkind (Object_Definition (Obj_Decl)) = N_Subtype_Indication then
Assoc := First
(Constraints
(Constraint
(Object_Definition (Obj_Decl))));
-- The object declaration contains an aggregate
elsif Present (Expression (Obj_Decl)) then
if Nkind (Unqualify (Expression (Obj_Decl))) = N_Aggregate then
-- Grab the first associated discriminant expresion
if Present
(Expressions (Unqualify (Expression (Obj_Decl))))
then
Assoc := First
(Expressions
(Unqualify (Expression (Obj_Decl))));
else
Assoc := First
(Component_Associations
(Unqualify (Expression (Obj_Decl))));
end if;
-- Otherwise, this is something else
else
return;
end if;
-- There are no supplied discriminants in the object declaration,
-- so get them from the type definition since they must be default
-- initialized.
-- Do we handle constrained subtypes correctly ???
elsif Nkind (Unqual) = N_Object_Declaration then
Assoc := First_Discriminant
(Etype (Object_Definition (Obj_Decl)));
else
Assoc := First_Discriminant (Etype (Unqual));
end if;
-- When we are not looking at an aggregate or an identifier, return
-- since any other construct (like a function call) is not
-- applicable since checks will be performed on the side of the
-- callee.
else
return;
end if;
-- Obtain the discriminants so we know the actual type in case the
-- value of their associated expression gets implicitly converted.
if No (Obj_Decl) then
pragma Assert (Nkind (Unqual) = N_Aggregate);
Disc := First_Discriminant (Etype (Unqual));
else
Disc := First_Discriminant
(Etype (Defining_Identifier (Obj_Decl)));
end if;
-- Preserve the first discriminant for checking named associations
First_Disc := Disc;
-- Count the number of discriminants for processing an aggregate
-- which includes an others.
Disc := First_Disc;
while Present (Disc) loop
Unseen_Disc_Count := Unseen_Disc_Count + 1;
Next_Discriminant (Disc);
end loop;
Seen_Discs := New_Elmt_List;
-- Loop through each of the discriminants and check each expression
-- associated with an anonymous access discriminant.
-- When named associations occur in the return aggregate then
-- discriminants can be in any order, so we need to ensure we do
-- not continue to loop when all discriminants have been seen.
Disc := First_Disc;
while Present (Assoc)
and then (Present (Disc) or else Assoc_Present)
and then Unseen_Disc_Count > 0
loop
-- Handle named associations by searching through the names of
-- the relevant discriminant components.
if Nkind (Assoc)
in N_Component_Association | N_Discriminant_Association
then
Assoc_Expr := Expression (Assoc);
Assoc_Present := True;
-- We currently don't handle box initialized discriminants,
-- however, since default initialized anonymous access
-- discriminants are a corner case, this is ok for now ???
if Nkind (Assoc) = N_Component_Association
and then Box_Present (Assoc)
then
if Nkind (First_Selector (Assoc)) = N_Others_Choice then
Unseen_Disc_Count := 0;
end if;
-- When others is present we must identify a discriminant we
-- haven't already seen so as to get the appropriate type for
-- the static accessibility check.
-- This works because all components within an others clause
-- must have the same type.
elsif Nkind (First_Selector (Assoc)) = N_Others_Choice then
Disc := First_Disc;
Outer : while Present (Disc) loop
declare
Current_Seen_Disc : Elmt_Id;
begin
-- Move through the list of identified discriminants
Current_Seen_Disc := First_Elmt (Seen_Discs);
while Present (Current_Seen_Disc) loop
-- Exit the loop when we found a match
exit when
Chars (Node (Current_Seen_Disc)) = Chars (Disc);
Next_Elmt (Current_Seen_Disc);
end loop;
-- When we have exited the above loop without finding
-- a match then we know that Disc has not been seen.
exit Outer when No (Current_Seen_Disc);
end;
Next_Discriminant (Disc);
end loop Outer;
-- If we got to an others clause with a non-zero
-- discriminant count there must be a discriminant left to
-- check.
pragma Assert (Present (Disc));
-- Set the unseen discriminant count to zero because we know
-- an others clause sets all remaining components of an
-- aggregate.
Unseen_Disc_Count := 0;
-- Move through each of the selectors in the named association
-- and obtain a discriminant for accessibility checking if one
-- is referenced in the list. Also track which discriminants
-- are referenced for the purpose of handling an others clause.
else
declare
Assoc_Choice : Node_Id;
Curr_Disc : Node_Id;
begin
Disc := Empty;
Curr_Disc := First_Disc;
while Present (Curr_Disc) loop
-- Check each of the choices in the associations for a
-- match to the name of the current discriminant.
Assoc_Choice := First_Selector (Assoc);
while Present (Assoc_Choice) loop
-- When the name matches we track that we have seen
-- the discriminant, but instead of exiting the
-- loop we continue iterating to make sure all the
-- discriminants within the named association get
-- tracked.
if Chars (Assoc_Choice) = Chars (Curr_Disc) then
Append_Elmt (Curr_Disc, Seen_Discs);
Disc := Curr_Disc;
Unseen_Disc_Count := Unseen_Disc_Count - 1;
end if;
Next (Assoc_Choice);
end loop;
Next_Discriminant (Curr_Disc);
end loop;
end;
end if;
-- Unwrap the associated expression if we are looking at a default
-- initialized type declaration. In this case Assoc is not really
-- an association, but a component declaration. Should Assoc be
-- renamed in some way to be more clear ???
-- This occurs when the return object does not initialize
-- discriminant and instead relies on the type declaration for
-- their supplied values.
elsif Nkind (Assoc) in N_Entity
and then Ekind (Assoc) = E_Discriminant
then
Append_Elmt (Disc, Seen_Discs);
Assoc_Expr := Discriminant_Default_Value (Assoc);
Unseen_Disc_Count := Unseen_Disc_Count - 1;
-- Otherwise, there is nothing to do because Assoc is an
-- expression within the return aggregate itself.
else
Append_Elmt (Disc, Seen_Discs);
Assoc_Expr := Assoc;
Unseen_Disc_Count := Unseen_Disc_Count - 1;
end if;
-- Check the accessibility level of the expression when the
-- discriminant is of an anonymous access type.
if Present (Assoc_Expr)
and then Present (Disc)
and then Ekind (Etype (Disc)) = E_Anonymous_Access_Type
-- We disable the check when we have a tagged return type and
-- the associated expression for the discriminant is a formal
-- parameter since the check would require us to compare the
-- accessibility level of Assoc_Expr to the level of the
-- Extra_Accessibility_Of_Result of the function - which is
-- currently disabled for functions with tagged return types.
-- This may change in the future ???
-- See Needs_Result_Accessibility_Level for details.
and then not
(No (Extra_Accessibility_Of_Result (Scope_Id))
and then Is_Formal_Of_Current_Function (Assoc_Expr)
and then Is_Tagged_Type (Etype (Scope_Id)))
then
-- Generate a dynamic check based on the extra accessibility of
-- the result or the scope of the current function.
Check_Cond :=
Make_Op_Gt (Loc,
Left_Opnd => Accessibility_Level
(Expr => Assoc_Expr,
Level => Dynamic_Level,
In_Return_Context => True),
Right_Opnd =>
(if Present (Extra_Accessibility_Of_Result (Scope_Id))
-- When Assoc_Expr is a formal we have to look at the
-- extra accessibility-level formal associated with
-- the result.
and then Is_Formal_Of_Current_Function (Assoc_Expr)
then
New_Occurrence_Of
(Extra_Accessibility_Of_Result (Scope_Id), Loc)
-- Otherwise, we compare the level of Assoc_Expr to the
-- scope of the current function.
else
Make_Integer_Literal
(Loc, Scope_Depth (Scope (Scope_Id)))));
Insert_Before_And_Analyze (Return_Stmt,
Make_Raise_Program_Error (Loc,
Condition => Check_Cond,
Reason => PE_Accessibility_Check_Failed));
-- If constant folding has happened on the condition for the
-- generated error, then warn about it being unconditional when
-- we know an error will be raised.
if Nkind (Check_Cond) = N_Identifier
and then Entity (Check_Cond) = Standard_True
then
Error_Msg_N
("access discriminant in return object would be a dangling"
& " reference", Return_Stmt);
end if;
end if;
-- Iterate over the discriminants, except when we have encountered
-- a named association since the discriminant order becomes
-- irrelevant in that case.
if not Assoc_Present then
Next_Discriminant (Disc);
end if;
-- Iterate over associations
if not Is_List_Member (Assoc) then
exit;
else
Nlists.Next (Assoc);
end if;
end loop;
end Check_Return_Construct_Accessibility;
-------------------------------
-- Deepest_Type_Access_Level --
-------------------------------
function Deepest_Type_Access_Level
(Typ : Entity_Id;
Allow_Alt_Model : Boolean := True) return Uint
is
begin
if Ekind (Typ) = E_Anonymous_Access_Type
and then not Is_Local_Anonymous_Access (Typ)
and then Nkind (Associated_Node_For_Itype (Typ)) = N_Object_Declaration
then
-- No_Dynamic_Accessibility_Checks override for alternative
-- accessibility model.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (Typ)
then
return Type_Access_Level (Typ, Allow_Alt_Model);
end if;
-- Typ is the type of an Ada 2012 stand-alone object of an anonymous
-- access type.
return
Scope_Depth (Enclosing_Dynamic_Scope
(Defining_Identifier
(Associated_Node_For_Itype (Typ))));
-- For generic formal type, return Int'Last (infinite).
-- See comment preceding Is_Generic_Type call in Type_Access_Level.
elsif Is_Generic_Type (Root_Type (Typ)) then
return UI_From_Int (Int'Last);
else
return Type_Access_Level (Typ, Allow_Alt_Model);
end if;
end Deepest_Type_Access_Level;
-----------------------------------
-- Effective_Extra_Accessibility --
-----------------------------------
function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id is
begin
if Present (Renamed_Object (Id))
and then Is_Entity_Name (Renamed_Object (Id))
then
return Effective_Extra_Accessibility (Entity (Renamed_Object (Id)));
else
return Extra_Accessibility (Id);
end if;
end Effective_Extra_Accessibility;
-------------------------------
-- Get_Dynamic_Accessibility --
-------------------------------
function Get_Dynamic_Accessibility (E : Entity_Id) return Entity_Id is
begin
-- When minimum accessibility is set for E then we utilize it - except
-- in a few edge cases like the expansion of select statements where
-- generated subprogram may attempt to unnecessarily use a minimum
-- accessibility object declared outside of scope.
-- To avoid these situations where expansion may get complex we verify
-- that the minimum accessibility object is within scope.
if Is_Formal (E)
and then Present (Minimum_Accessibility (E))
and then In_Open_Scopes (Scope (Minimum_Accessibility (E)))
then
return Minimum_Accessibility (E);
end if;
return Extra_Accessibility (E);
end Get_Dynamic_Accessibility;
-----------------------
-- Has_Access_Values --
-----------------------
function Has_Access_Values (T : Entity_Id) return Boolean
is
Typ : constant Entity_Id := Underlying_Type (T);
begin
-- Case of a private type which is not completed yet. This can only
-- happen in the case of a generic formal type appearing directly, or
-- as a component of the type to which this function is being applied
-- at the top level. Return False in this case, since we certainly do
-- not know that the type contains access types.
if No (Typ) then
return False;
elsif Is_Access_Type (Typ) then
return True;
elsif Is_Array_Type (Typ) then
return Has_Access_Values (Component_Type (Typ));
elsif Is_Record_Type (Typ) then
declare
Comp : Entity_Id;
begin
-- Loop to check components
Comp := First_Component_Or_Discriminant (Typ);
while Present (Comp) loop
-- Check for access component, tag field does not count, even
-- though it is implemented internally using an access type.
if Has_Access_Values (Etype (Comp))
and then Chars (Comp) /= Name_uTag
then
return True;
end if;
Next_Component_Or_Discriminant (Comp);
end loop;
end;
return False;
else
return False;
end if;
end Has_Access_Values;
---------------------------------------
-- Has_Anonymous_Access_Discriminant --
---------------------------------------
function Has_Anonymous_Access_Discriminant (Typ : Entity_Id) return Boolean
is
Disc : Node_Id;
begin
if not Has_Discriminants (Typ) then
return False;
end if;
Disc := First_Discriminant (Typ);
while Present (Disc) loop
if Ekind (Etype (Disc)) = E_Anonymous_Access_Type then
return True;
end if;
Next_Discriminant (Disc);
end loop;
return False;
end Has_Anonymous_Access_Discriminant;
--------------------------------------------
-- Has_Unconstrained_Access_Discriminants --
--------------------------------------------
function Has_Unconstrained_Access_Discriminants
(Subtyp : Entity_Id) return Boolean
is
Discr : Entity_Id;
begin
if Has_Discriminants (Subtyp)
and then not Is_Constrained (Subtyp)
then
Discr := First_Discriminant (Subtyp);
while Present (Discr) loop
if Ekind (Etype (Discr)) = E_Anonymous_Access_Type then
return True;
end if;
Next_Discriminant (Discr);
end loop;
end if;
return False;
end Has_Unconstrained_Access_Discriminants;
--------------------------------
-- Is_Anonymous_Access_Actual --
--------------------------------
function Is_Anonymous_Access_Actual (N : Node_Id) return Boolean is
Par : Node_Id;
begin
if Ekind (Etype (N)) /= E_Anonymous_Access_Type then
return False;
end if;
Par := Parent (N);
while Present (Par)
and then Nkind (Par) in N_Case_Expression
| N_If_Expression
| N_Parameter_Association
loop
Par := Parent (Par);
end loop;
return Nkind (Par) in N_Subprogram_Call;
end Is_Anonymous_Access_Actual;
--------------------------------------
-- Is_Special_Aliased_Formal_Access --
--------------------------------------
function Is_Special_Aliased_Formal_Access
(Exp : Node_Id;
In_Return_Context : Boolean := False) return Boolean
is
Scop : constant Entity_Id := Current_Subprogram;
begin
-- Verify the expression is an access reference to 'Access within a
-- return statement as this is the only time an explicitly aliased
-- formal has different semantics.
if Nkind (Exp) /= N_Attribute_Reference
or else Get_Attribute_Id (Attribute_Name (Exp)) /= Attribute_Access
or else not (In_Return_Value (Exp)
or else In_Return_Context)
or else not Needs_Result_Accessibility_Level (Scop)
then
return False;
end if;
-- Check if the prefix of the reference is indeed an explicitly aliased
-- formal parameter for the function Scop. Additionally, we must check
-- that Scop returns an anonymous access type, otherwise the special
-- rules dictating a need for a dynamic check are not in effect.
return Is_Entity_Name (Prefix (Exp))
and then Is_Explicitly_Aliased (Entity (Prefix (Exp)));
end Is_Special_Aliased_Formal_Access;
--------------------------------------
-- Needs_Result_Accessibility_Level --
--------------------------------------
function Needs_Result_Accessibility_Level
(Func_Id : Entity_Id) return Boolean
is
Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
function Has_Unconstrained_Access_Discriminant_Component
(Comp_Typ : Entity_Id) return Boolean;
-- Returns True if any component of the type has an unconstrained access
-- discriminant.
-----------------------------------------------------
-- Has_Unconstrained_Access_Discriminant_Component --
-----------------------------------------------------
function Has_Unconstrained_Access_Discriminant_Component
(Comp_Typ : Entity_Id) return Boolean
is
begin
if not Is_Limited_Type (Comp_Typ) then
return False;
-- Only limited types can have access discriminants with
-- defaults.
elsif Has_Unconstrained_Access_Discriminants (Comp_Typ) then
return True;
elsif Is_Array_Type (Comp_Typ) then
return Has_Unconstrained_Access_Discriminant_Component
(Underlying_Type (Component_Type (Comp_Typ)));
elsif Is_Record_Type (Comp_Typ) then
declare
Comp : Entity_Id;
begin
Comp := First_Component (Comp_Typ);
while Present (Comp) loop
if Has_Unconstrained_Access_Discriminant_Component
(Underlying_Type (Etype (Comp)))
then
return True;
end if;
Next_Component (Comp);
end loop;
end;
end if;
return False;
end Has_Unconstrained_Access_Discriminant_Component;
Disable_Tagged_Cases : constant Boolean := True;
-- Flag used to temporarily disable a "True" result for tagged types.
-- See comments further below for details.
-- Start of processing for Needs_Result_Accessibility_Level
begin
-- False if completion unavailable, which can happen when we are
-- analyzing an abstract subprogram or if the subprogram has
-- delayed freezing.
if No (Func_Typ) then
return False;
-- False if not a function, also handle enum-lit renames case
elsif Func_Typ = Standard_Void_Type
or else Is_Scalar_Type (Func_Typ)
then
return False;
-- Handle a corner case, a cross-dialect subp renaming. For example,
-- an Ada 2012 renaming of an Ada 2005 subprogram. This can occur when
-- an Ada 2005 (or earlier) unit references predefined run-time units.
elsif Present (Alias (Func_Id)) then
-- Unimplemented: a cross-dialect subp renaming which does not set
-- the Alias attribute (e.g., a rename of a dereference of an access
-- to subprogram value). ???
return Present (Extra_Accessibility_Of_Result (Alias (Func_Id)));
-- Remaining cases require Ada 2012 mode, unless they are dispatching
-- operations, since they may be overridden by Ada_2012 primitives.
elsif Ada_Version < Ada_2012
and then not Is_Dispatching_Operation (Func_Id)
then
return False;
-- Handle the situation where a result is an anonymous access type
-- RM 3.10.2 (10.3/3).
elsif Ekind (Func_Typ) = E_Anonymous_Access_Type then
return True;
-- In the case of, say, a null tagged record result type, the need for
-- this extra parameter might not be obvious so this function returns
-- True for all tagged types for compatibility reasons.
-- A function with, say, a tagged null controlling result type might
-- be overridden by a primitive of an extension having an access
-- discriminant and the overrider and overridden must have compatible
-- calling conventions (including implicitly declared parameters).
-- Similarly, values of one access-to-subprogram type might designate
-- both a primitive subprogram of a given type and a function which is,
-- for example, not a primitive subprogram of any type. Again, this
-- requires calling convention compatibility. It might be possible to
-- solve these issues by introducing wrappers, but that is not the
-- approach that was chosen.
-- Note: Despite the reasoning noted above, the extra accessibility
-- parameter for tagged types is disabled for performance reasons.
elsif Is_Tagged_Type (Func_Typ) then
return not Disable_Tagged_Cases;
elsif Has_Unconstrained_Access_Discriminants (Func_Typ) then
return True;
elsif Has_Unconstrained_Access_Discriminant_Component (Func_Typ) then
return True;
-- False for all other cases
else
return False;
end if;
end Needs_Result_Accessibility_Level;
------------------------------------------
-- Prefix_With_Safe_Accessibility_Level --
------------------------------------------
function Prefix_With_Safe_Accessibility_Level
(N : Node_Id;
Typ : Entity_Id) return Boolean
is
P : constant Node_Id := Prefix (N);
Aname : constant Name_Id := Attribute_Name (N);
Attr_Id : constant Attribute_Id := Get_Attribute_Id (Aname);
Btyp : constant Entity_Id := Base_Type (Typ);
function Safe_Value_Conversions return Boolean;
-- Return False if the prefix has a value conversion of an array type
----------------------------
-- Safe_Value_Conversions --
----------------------------
function Safe_Value_Conversions return Boolean is
PP : Node_Id := P;
begin
loop
if Nkind (PP) in N_Selected_Component | N_Indexed_Component then
PP := Prefix (PP);
elsif Comes_From_Source (PP)
and then Nkind (PP) in N_Type_Conversion
| N_Unchecked_Type_Conversion
and then Is_Array_Type (Etype (PP))
then
return False;
elsif Comes_From_Source (PP)
and then Nkind (PP) = N_Qualified_Expression
and then Is_Array_Type (Etype (PP))
and then Nkind (Original_Node (Expression (PP))) in
N_Aggregate | N_Extension_Aggregate
then
return False;
else
exit;
end if;
end loop;
return True;
end Safe_Value_Conversions;
-- Start of processing for Prefix_With_Safe_Accessibility_Level
begin
-- No check required for unchecked and unrestricted access
if Attr_Id = Attribute_Unchecked_Access
or else Attr_Id = Attribute_Unrestricted_Access
then
return True;
-- Check value conversions
elsif Ekind (Btyp) = E_General_Access_Type
and then not Safe_Value_Conversions
then
return False;
end if;
return True;
end Prefix_With_Safe_Accessibility_Level;
-----------------------------
-- Subprogram_Access_Level --
-----------------------------
function Subprogram_Access_Level (Subp : Entity_Id) return Uint is
begin
if Present (Alias (Subp)) then
return Subprogram_Access_Level (Alias (Subp));
else
return Scope_Depth (Enclosing_Dynamic_Scope (Subp));
end if;
end Subprogram_Access_Level;
--------------------------------
-- Static_Accessibility_Level --
--------------------------------
function Static_Accessibility_Level
(Expr : Node_Id;
Level : Static_Accessibility_Level_Kind;
In_Return_Context : Boolean := False) return Uint
is
begin
return Intval
(Accessibility_Level (Expr, Level, In_Return_Context));
end Static_Accessibility_Level;
-----------------------
-- Type_Access_Level --
-----------------------
function Type_Access_Level
(Typ : Entity_Id;
Allow_Alt_Model : Boolean := True;
Assoc_Ent : Entity_Id := Empty) return Uint
is
Btyp : Entity_Id := Base_Type (Typ);
Def_Ent : Entity_Id;
begin
-- Ada 2005 (AI-230): For most cases of anonymous access types, we
-- simply use the level where the type is declared. This is true for
-- stand-alone object declarations, and for anonymous access types
-- associated with components the level is the same as that of the
-- enclosing composite type. However, special treatment is needed for
-- the cases of access parameters, return objects of an anonymous access
-- type, and, in Ada 95, access discriminants of limited types.
if Is_Access_Type (Btyp) then
if Ekind (Btyp) = E_Anonymous_Access_Type then
-- No_Dynamic_Accessibility_Checks restriction override for
-- alternative accessibility model.
if Allow_Alt_Model
and then No_Dynamic_Accessibility_Checks_Enabled (Btyp)
then
-- In the -gnatd_b model, the level of an anonymous access
-- type is always that of the designated type.
if Debug_Flag_Underscore_B then
return Type_Access_Level
(Designated_Type (Btyp), Allow_Alt_Model);
end if;
-- When an anonymous access type's Assoc_Ent is specified,
-- calculate the result based on the general accessibility
-- level routine.
-- We would like to use Associated_Node_For_Itype here instead,
-- but in some cases it is not fine grained enough ???
if Present (Assoc_Ent) then
return Static_Accessibility_Level
(Assoc_Ent, Object_Decl_Level);
end if;
-- Otherwise take the context of the anonymous access type into
-- account.
-- Obtain the defining entity for the internally generated
-- anonymous access type.
Def_Ent := Defining_Entity_Or_Empty
(Associated_Node_For_Itype (Typ));
if Present (Def_Ent) then
-- When the defining entity is a subprogram then we know the
-- anonymous access type Typ has been generated to either
-- describe an anonymous access type formal or an anonymous
-- access result type.
-- Since we are only interested in the formal case, avoid
-- the anonymous access result type.
if Is_Subprogram (Def_Ent)
and then not (Ekind (Def_Ent) = E_Function
and then Etype (Def_Ent) = Typ)
then
-- When the type comes from an anonymous access
-- parameter, the level is that of the subprogram
-- declaration.
return Scope_Depth (Def_Ent);
-- When the type is an access discriminant, the level is
-- that of the type.
elsif Ekind (Def_Ent) = E_Discriminant then
return Scope_Depth (Scope (Def_Ent));
end if;
end if;
-- If the type is a nonlocal anonymous access type (such as for
-- an access parameter) we treat it as being declared at the
-- library level to ensure that names such as X.all'access don't
-- fail static accessibility checks.
elsif not Is_Local_Anonymous_Access (Typ) then
return Scope_Depth (Standard_Standard);
-- If this is a return object, the accessibility level is that of
-- the result subtype of the enclosing function. The test here is
-- little complicated, because we have to account for extended
-- return statements that have been rewritten as blocks, in which
-- case we have to find and the Is_Return_Object attribute of the
-- itype's associated object. It would be nice to find a way to
-- simplify this test, but it doesn't seem worthwhile to add a new
-- flag just for purposes of this test. ???
elsif Ekind (Scope (Btyp)) = E_Return_Statement
or else
(Is_Itype (Btyp)
and then Nkind (Associated_Node_For_Itype (Btyp)) =
N_Object_Declaration
and then Is_Return_Object
(Defining_Identifier
(Associated_Node_For_Itype (Btyp))))
then
declare
Scop : Entity_Id;
begin
Scop := Scope (Scope (Btyp));
while Present (Scop) loop
exit when Ekind (Scop) = E_Function;
Scop := Scope (Scop);
end loop;
-- Treat the return object's type as having the level of the
-- function's result subtype (as per RM05-6.5(5.3/2)).
return Type_Access_Level (Etype (Scop), Allow_Alt_Model);
end;
end if;
end if;
Btyp := Root_Type (Btyp);
-- The accessibility level of anonymous access types associated with
-- discriminants is that of the current instance of the type, and
-- that's deeper than the type itself (AARM 3.10.2 (12.3.21)).
-- AI-402: access discriminants have accessibility based on the
-- object rather than the type in Ada 2005, so the above paragraph
-- doesn't apply.
-- ??? Needs completion with rules from AI-416
if Ada_Version <= Ada_95
and then Ekind (Typ) = E_Anonymous_Access_Type
and then Present (Associated_Node_For_Itype (Typ))
and then Nkind (Associated_Node_For_Itype (Typ)) =
N_Discriminant_Specification
then
return Scope_Depth (Enclosing_Dynamic_Scope (Btyp)) + 1;
end if;
end if;
-- Return library level for a generic formal type. This is done because
-- RM(10.3.2) says that "The statically deeper relationship does not
-- apply to ... a descendant of a generic formal type". Rather than
-- checking at each point where a static accessibility check is
-- performed to see if we are dealing with a formal type, this rule is
-- implemented by having Type_Access_Level and Deepest_Type_Access_Level
-- return extreme values for a formal type; Deepest_Type_Access_Level
-- returns Int'Last. By calling the appropriate function from among the
-- two, we ensure that the static accessibility check will pass if we
-- happen to run into a formal type. More specifically, we should call
-- Deepest_Type_Access_Level instead of Type_Access_Level whenever the
-- call occurs as part of a static accessibility check and the error
-- case is the case where the type's level is too shallow (as opposed
-- to too deep).
if Is_Generic_Type (Root_Type (Btyp)) then
return Scope_Depth (Standard_Standard);
end if;
return Scope_Depth (Enclosing_Dynamic_Scope (Btyp));
end Type_Access_Level;
end Accessibility;
|