summaryrefslogtreecommitdiffstats
path: root/gcc/ada/checks.adb
diff options
context:
space:
mode:
authorcharlet <charlet@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-21 13:42:24 +0000
committercharlet <charlet@138bc75d-0d04-0410-961f-82ee72b054a4>2003-10-21 13:42:24 +0000
commit9dfe12ae5b94d03c997ea2903022a5d2d5c5f266 (patch)
treebdfc70477b60f1220cb05dd233a4570dd9c6bb5c /gcc/ada/checks.adb
parent1c662558a1113238a624245a45382d3df90ccf13 (diff)
downloadppe42-gcc-9dfe12ae5b94d03c997ea2903022a5d2d5c5f266.tar.gz
ppe42-gcc-9dfe12ae5b94d03c997ea2903022a5d2d5c5f266.zip
2003-10-21 Arnaud Charlet <charlet@act-europe.fr>
* 3psoccon.ads, 3veacodu.adb, 3vexpect.adb, 3vsoccon.ads, 3vsocthi.adb, 3vsocthi.ads, 3vtrasym.adb, 3zsoccon.ads, 3zsocthi.adb, 3zsocthi.ads, 50system.ads, 51system.ads, 55system.ads, 56osinte.adb, 56osinte.ads, 56taprop.adb, 56taspri.ads, 56tpopsp.adb, 57system.ads, 58system.ads, 59system.ads, 5aml-tgt.adb, 5bml-tgt.adb, 5csystem.ads, 5dsystem.ads, 5fosinte.adb, 5gml-tgt.adb, 5hml-tgt.adb, 5isystem.ads, 5lparame.adb, 5msystem.ads, 5psystem.ads, 5sml-tgt.adb, 5sosprim.adb, 5stpopsp.adb, 5tsystem.ads, 5usystem.ads, 5vml-tgt.adb, 5vsymbol.adb, 5vtraent.adb, 5vtraent.ads, 5wml-tgt.adb, 5xparame.ads, 5xsystem.ads, 5xvxwork.ads, 5yparame.ads, 5ytiitho.adb, 5zinit.adb, 5zml-tgt.adb, 5zparame.ads, 5ztaspri.ads, 5ztfsetr.adb, 5zthrini.adb, 5ztiitho.adb, 5ztpopsp.adb, 7stfsetr.adb, 7straces.adb, 7strafor.adb, 7strafor.ads, 7stratas.adb, a-excach.adb, a-exexda.adb, a-exexpr.adb, a-exextr.adb, a-exstat.adb, a-strsup.adb, a-strsup.ads, a-stwisu.adb, a-stwisu.ads, bld.adb, bld.ads, bld-io.adb, bld-io.ads, clean.adb, clean.ads, ctrl_c.c, erroutc.adb, erroutc.ads, errutil.adb, errutil.ads, err_vars.ads, final.c, g-arrspl.adb, g-arrspl.ads, g-boubuf.adb, g-boubuf.ads, g-boumai.ads, g-bubsor.adb, g-bubsor.ads, g-comver.adb, g-comver.ads, g-ctrl_c.ads, g-dynhta.adb, g-dynhta.ads, g-eacodu.adb, g-excact.adb, g-excact.ads, g-heasor.adb, g-heasor.ads, g-memdum.adb, g-memdum.ads, gnatclean.adb, gnatsym.adb, g-pehage.adb, g-pehage.ads, g-perhas.ads, gpr2make.adb, gpr2make.ads, gprcmd.adb, gprep.adb, gprep.ads, g-semaph.adb, g-semaph.ads, g-string.adb, g-string.ads, g-strspl.ads, g-wistsp.ads, i-vthrea.adb, i-vthrea.ads, i-vxwoio.adb, i-vxwoio.ads, Makefile.generic, Makefile.prolog, Makefile.rtl, prep.adb, prep.ads, prepcomp.adb, prepcomp.ads, prj-err.adb, prj-err.ads, s-boarop.ads, s-carsi8.adb, s-carsi8.ads, s-carun8.adb, s-carun8.ads, s-casi16.adb, s-casi16.ads, s-casi32.adb, s-casi32.ads, s-casi64.adb, s-casi64.ads, s-casuti.adb, s-casuti.ads, s-caun16.adb, s-caun16.ads, s-caun32.adb, s-caun32.ads, s-caun64.adb, s-caun64.ads, scng.adb, scng.ads, s-exnint.adb, s-exnllf.adb, s-exnlli.adb, s-expint.adb, s-explli.adb, s-geveop.adb, s-geveop.ads, s-hibaen.ads, s-htable.adb, s-htable.ads, sinput-c.adb, sinput-c.ads, s-memcop.ads, socket.c, s-purexc.ads, s-scaval.adb, s-stopoo.adb, s-strcom.adb, s-strcom.ads, s-strxdr.adb, s-rident.ads, s-thread.adb, s-thread.ads, s-tpae65.adb, s-tpae65.ads, s-tporft.adb, s-traent.adb, s-traent.ads, styleg.adb, styleg.ads, styleg-c.adb, styleg-c.ads, s-veboop.adb, s-veboop.ads, s-vector.ads, symbols.adb, symbols.ads, tb-alvms.c, tb-alvxw.c, tempdir.adb, tempdir.ads, vms_conv.ads, vms_conv.adb, vms_data.ads, vxaddr2line.adb: Files added. Merge with ACT tree. * 4dintnam.ads, 4mintnam.ads, 4uintnam.ads, 52system.ads, 5dosinte.ads, 5etpopse.adb, 5mosinte.ads, 5qosinte.adb, 5qosinte.ads, 5qstache.adb, 5qtaprop.adb, 5qtaspri.ads, 5stpopse.adb, 5uintman.adb, 5uosinte.ads, adafinal.c, g-enblsp.adb, io-aux.c, scn-nlit.adb, scn-slit.adb, s-exnflt.ads, s-exngen.adb, s-exngen.ads, s-exnlfl.ads, s-exnlin.ads, s-exnsfl.ads, s-exnsin.ads, s-exnssi.ads, s-expflt.ads, s-expgen.adb, s-expgen.ads, s-explfl.ads, s-explin.ads, s-expllf.ads, s-expsfl.ads, s-expsin.ads, s-expssi.ads, style.adb: Files removed. Merge with ACT tree. * 1ic.ads, 31soccon.ads, 31soliop.ads, 3asoccon.ads, 3bsoccon.ads, 3gsoccon.ads, 3hsoccon.ads, 3ssoccon.ads, 3ssoliop.ads, 3wsoccon.ads, 3wsocthi.adb, 3wsocthi.ads, 3wsoliop.ads, 41intnam.ads, 42intnam.ads, 4aintnam.ads, 4cintnam.ads, 4gintnam.ads, 4hexcpol.adb, 4hintnam.ads, 4lintnam.ads, 4nintnam.ads, 4ointnam.ads, 4onumaux.ads, 4pintnam.ads, 4sintnam.ads, 4vcaldel.adb, 4vcalend.adb, 4vintnam.ads, 4wexcpol.adb, 4wintnam.ads, 4zintnam.ads, 51osinte.adb, 51osinte.ads, 52osinte.adb, 52osinte.ads, 53osinte.ads, 54osinte.ads, 5aosinte.adb, 5aosinte.ads, 5asystem.ads, 5ataprop.adb, 5atasinf.ads, 5ataspri.ads, 5atpopsp.adb, 5avxwork.ads, 5bosinte.adb, 5bosinte.ads, 5bsystem.ads, 5cosinte.ads, 5esystem.ads, 5fintman.adb, 5fosinte.ads, 5fsystem.ads, 5ftaprop.adb, 5ftasinf.ads, 5ginterr.adb, 5gintman.adb, 5gmastop.adb, 5gosinte.ads, 5gproinf.ads, 5gsystem.ads, 5gtaprop.adb, 5gtasinf.ads, 5gtpgetc.adb, 5hosinte.adb, 5hosinte.ads, 5hsystem.ads, 5htaprop.adb, 5htaspri.ads, 5htraceb.adb, 5iosinte.adb, 5itaprop.adb, 5itaspri.ads, 5ksystem.ads, 5kvxwork.ads, 5lintman.adb, 5lml-tgt.adb, 5losinte.ads, 5lsystem.ads, 5mvxwork.ads, 5ninmaop.adb, 5nintman.adb, 5nosinte.ads, 5ntaprop.adb, 5ntaspri.ads, 5ointerr.adb, 5omastop.adb, 5oosinte.adb, 5oosinte.ads, 5oosprim.adb, 5oparame.adb, 5osystem.ads, 5otaprop.adb, 5otaspri.ads, 5posinte.ads, 5posprim.adb, 5pvxwork.ads, 5sintman.adb, 5sosinte.adb, 5sosinte.ads, 5ssystem.ads, 5staprop.adb, 5stasinf.ads, 5staspri.ads, 5svxwork.ads, 5tosinte.ads, 5vasthan.adb, 5vinmaop.adb, 5vinterr.adb, 5vintman.adb, 5vintman.ads, 5vmastop.adb, 5vosinte.adb, 5vosinte.ads, 5vosprim.adb, 5vsystem.ads, 5vtaprop.adb, 5vtaspri.ads, 5vtpopde.adb, 5vtpopde.ads, 5wgloloc.adb, 5wintman.adb, 5wmemory.adb, 5wosprim.adb, 5wsystem.ads, 5wtaprop.adb, 5wtaspri.ads, 5ysystem.ads, 5zinterr.adb, 5zintman.adb, 5zosinte.adb, 5zosinte.ads, 5zosprim.adb, 5zsystem.ads, 5ztaprop.adb, 6vcpp.adb, 6vcstrea.adb, 6vinterf.ads, 7sinmaop.adb, 7sintman.adb, 7sosinte.adb, 7sosprim.adb, 7staprop.adb, 7staspri.ads, 7stpopsp.adb, 7straceb.adb, 9drpc.adb, a-caldel.adb, a-caldel.ads, a-charac.ads, a-colien.ads, a-comlin.adb, adaint.c, adaint.h, ada-tree.def, a-diocst.adb, a-diocst.ads, a-direio.adb, a-except.adb, a-except.ads, a-excpol.adb, a-exctra.adb, a-exctra.ads, a-filico.adb, a-interr.adb, a-intsig.adb, a-intsig.ads, ali.adb, ali.ads, ali-util.adb, ali-util.ads, a-ngcefu.adb, a-ngcoty.adb, a-ngelfu.adb, a-nudira.adb, a-nudira.ads, a-nuflra.adb, a-nuflra.ads, a-reatim.adb, a-reatim.ads, a-retide.ads, a-sequio.adb, a-siocst.adb, a-siocst.ads, a-ssicst.adb, a-ssicst.ads, a-strbou.adb, a-strbou.ads, a-strfix.adb, a-strmap.adb, a-strsea.ads, a-strunb.adb, a-strunb.ads, a-ststio.adb, a-stunau.adb, a-stunau.ads, a-stwibo.adb, a-stwibo.ads, a-stwifi.adb, a-stwima.adb, a-stwiun.adb, a-stwiun.ads, a-tags.adb, a-tags.ads, a-tasatt.adb, a-taside.adb, a-teioed.adb, a-textio.adb, a-textio.ads, a-tienau.adb, a-tifiio.adb, a-tiflau.adb, a-tiflio.adb, a-tigeau.adb, a-tigeau.ads, a-tiinau.adb, a-timoau.adb, a-tiocst.adb, a-tiocst.ads, atree.adb, atree.ads, a-witeio.adb, a-witeio.ads, a-wtcstr.adb, a-wtcstr.ads, a-wtdeio.adb, a-wtedit.adb, a-wtenau.adb, a-wtflau.adb, a-wtinau.adb, a-wtmoau.adb, bcheck.adb, binde.adb, bindgen.adb, bindusg.adb, checks.adb, checks.ads, cio.c, comperr.adb, comperr.ads, csets.adb, cstand.adb, cstreams.c, debug_a.adb, debug_a.ads, debug.adb, decl.c, einfo.adb, einfo.ads, errout.adb, errout.ads, eval_fat.adb, eval_fat.ads, exp_aggr.adb, expander.adb, expander.ads, exp_attr.adb, exp_ch11.adb, exp_ch13.adb, exp_ch2.adb, exp_ch3.adb, exp_ch3.ads, exp_ch4.adb, exp_ch5.adb, exp_ch6.adb, exp_ch7.adb, exp_ch7.ads, exp_ch8.adb, exp_ch9.adb, exp_code.adb, exp_dbug.adb, exp_dbug.ads, exp_disp.adb, exp_dist.adb, expect.c, exp_fixd.adb, exp_imgv.adb, exp_intr.adb, exp_pakd.adb, exp_prag.adb, exp_strm.adb, exp_strm.ads, exp_tss.adb, exp_tss.ads, exp_util.adb, exp_util.ads, exp_vfpt.adb, fe.h, fmap.adb, fmap.ads, fname.adb, fname.ads, fname-uf.adb, fname-uf.ads, freeze.adb, freeze.ads, frontend.adb, g-awk.adb, g-awk.ads, g-busora.adb, g-busora.ads, g-busorg.adb, g-busorg.ads, g-casuti.adb, g-casuti.ads, g-catiio.adb, g-catiio.ads, g-cgi.adb, g-cgi.ads, g-cgicoo.adb, g-cgicoo.ads, g-cgideb.adb, g-cgideb.ads, g-comlin.adb, g-comlin.ads, g-crc32.adb, g-crc32.ads, g-debpoo.adb, g-debpoo.ads, g-debuti.adb, g-debuti.ads, g-diopit.adb, g-diopit.ads, g-dirope.adb, g-dirope.ads, g-dyntab.adb, g-dyntab.ads, g-except.ads, g-exctra.adb, g-exctra.ads, g-expect.adb, g-expect.ads, g-hesora.adb, g-hesora.ads, g-hesorg.adb, g-hesorg.ads, g-htable.adb, g-htable.ads, gigi.h, g-io.adb, g-io.ads, g-io_aux.adb, g-io_aux.ads, g-locfil.adb, g-locfil.ads, g-md5.adb, g-md5.ads, gmem.c, gnat1drv.adb, gnatbind.adb, gnatchop.adb, gnatcmd.adb, gnatfind.adb, gnatkr.adb, gnatlbr.adb, gnatlink.adb, gnatls.adb, gnatmake.adb, gnatmem.adb, gnatname.adb, gnatprep.adb, gnatprep.ads, gnatpsta.adb, gnatxref.adb, g-os_lib.adb, g-os_lib.ads, g-regexp.adb, g-regexp.ads, g-regist.adb, g-regist.ads, g-regpat.adb, g-regpat.ads, g-soccon.ads, g-socket.adb, g-socket.ads, g-socthi.adb, g-socthi.ads, g-soliop.ads, g-souinf.ads, g-speche.adb, g-speche.ads, g-spipat.adb, g-spipat.ads, g-spitbo.adb, g-spitbo.ads, g-sptabo.ads, g-sptain.ads, g-sptavs.ads, g-table.adb, g-table.ads, g-tasloc.adb, g-tasloc.ads, g-thread.adb, g-thread.ads, g-traceb.adb, g-traceb.ads, g-trasym.adb, g-trasym.ads, hostparm.ads, i-c.ads, i-cobol.adb, i-cpp.adb, i-cstrea.ads, i-cstrin.adb, i-cstrin.ads, impunit.adb, init.c, inline.adb, interfac.ads, i-pacdec.ads, itypes.adb, itypes.ads, i-vxwork.ads, lang.opt, lang-specs.h, layout.adb, lib.adb, lib.ads, lib-list.adb, lib-load.adb, lib-load.ads, lib-sort.adb, lib-util.adb, lib-writ.adb, lib-writ.ads, lib-xref.adb, lib-xref.ads, link.c, live.adb, make.adb, make.ads, Makefile.adalib, Makefile.in, Make-lang.in, makeusg.adb, mdll.adb, mdll-fil.adb, mdll-fil.ads, mdll-utl.adb, mdll-utl.ads, memroot.adb, memroot.ads, memtrack.adb, misc.c, mkdir.c, mlib.adb, mlib.ads, mlib-fil.adb, mlib-fil.ads, mlib-prj.adb, mlib-prj.ads, mlib-tgt.adb, mlib-tgt.ads, mlib-utl.adb, mlib-utl.ads, namet.adb, namet.ads, namet.h, nlists.ads, nlists.h, nmake.adt, opt.adb, opt.ads, osint.adb, osint.ads, osint-b.adb, osint-c.adb, par.adb, par-ch10.adb, par-ch11.adb, par-ch2.adb, par-ch3.adb, par-ch4.adb, par-ch5.adb, par-ch6.adb, par-ch9.adb, par-endh.adb, par-labl.adb, par-load.adb, par-prag.adb, par-sync.adb, par-tchk.adb, par-util.adb, prj.adb, prj.ads, prj-attr.adb, prj-attr.ads, prj-com.adb, prj-com.ads, prj-dect.adb, prj-dect.ads, prj-env.adb, prj-env.ads, prj-ext.adb, prj-ext.ads, prj-makr.adb, prj-makr.ads, prj-nmsc.adb, prj-nmsc.ads, prj-pars.adb, prj-pars.ads, prj-part.adb, prj-part.ads, prj-pp.adb, prj-pp.ads, prj-proc.adb, prj-proc.ads, prj-strt.adb, prj-strt.ads, prj-tree.adb, prj-tree.ads, prj-util.adb, prj-util.ads, raise.c, raise.h, repinfo.adb, repinfo.h, restrict.adb, restrict.ads, rident.ads, rtsfind.adb, rtsfind.ads, s-addima.ads, s-arit64.adb, s-assert.adb, s-assert.ads, s-atacco.adb, s-atacco.ads, s-auxdec.adb, s-auxdec.ads, s-bitops.adb, scans.ads, scn.adb, scn.ads, s-crc32.adb, s-crc32.ads, s-direio.adb, sem.adb, sem.ads, sem_aggr.adb, sem_attr.adb, sem_attr.ads, sem_case.adb, sem_case.ads, sem_cat.adb, sem_cat.ads, sem_ch10.adb, sem_ch11.adb, sem_ch12.adb, sem_ch12.ads, sem_ch13.adb, sem_ch13.ads, sem_ch3.adb, sem_ch3.ads, sem_ch4.adb, sem_ch5.adb, sem_ch5.ads, sem_ch6.adb, sem_ch6.ads, sem_ch7.adb, sem_ch7.ads, sem_ch8.adb, sem_ch8.ads, sem_ch9.adb, sem_disp.adb, sem_disp.ads, sem_dist.adb, sem_elab.adb, sem_eval.adb, sem_eval.ads, sem_intr.adb, sem_maps.adb, sem_mech.adb, sem_prag.adb, sem_prag.ads, sem_res.adb, sem_res.ads, sem_type.adb, sem_type.ads, sem_util.adb, sem_util.ads, sem_warn.adb, s-errrep.adb, s-errrep.ads, s-exctab.adb, s-exctab.ads, s-exnint.ads, s-exnllf.ads, s-exnlli.ads, s-expint.ads, s-explli.ads, s-expuns.ads, s-fatflt.ads, s-fatgen.adb, s-fatgen.ads, s-fatlfl.ads, s-fatllf.ads, s-fatsfl.ads, s-fileio.adb, s-fileio.ads, s-finimp.adb, s-finimp.ads, s-finroo.adb, s-finroo.ads, sfn_scan.adb, s-gloloc.adb, s-gloloc.ads, s-imgdec.adb, s-imgenu.adb, s-imgrea.adb, s-imgwch.adb, sinfo.adb, sinfo.ads, s-inmaop.ads, sinput.adb, sinput.ads, sinput-d.adb, sinput-l.adb, sinput-l.ads, sinput-p.adb, sinput-p.ads, s-interr.adb, s-interr.ads, s-intman.ads, s-maccod.ads, s-mastop.adb, s-mastop.ads, s-memory.adb, s-memory.ads, snames.adb, snames.ads, snames.h, s-osprim.ads, s-parame.ads, s-parint.ads, s-pooloc.adb, s-pooloc.ads, s-poosiz.adb, sprint.adb, s-proinf.ads, s-scaval.ads, s-secsta.adb, s-secsta.ads, s-sequio.adb, s-shasto.adb, s-shasto.ads, s-soflin.ads, s-stache.adb, s-stache.ads, s-stalib.adb, s-stalib.ads, s-stoele.ads, s-stopoo.ads, s-stratt.adb, s-stratt.ads, s-strops.adb, s-strops.ads, s-taasde.adb, s-taasde.ads, s-tadeca.adb, s-tadeca.ads, s-tadert.adb, s-tadert.ads, s-taenca.adb, s-taenca.ads, s-taprob.adb, s-taprob.ads, s-taprop.ads, s-tarest.adb, s-tarest.ads, s-tasdeb.adb, s-tasdeb.ads, s-tasinf.adb, s-tasinf.ads, s-tasini.adb, s-tasini.ads, s-taskin.adb, s-taskin.ads, s-tasque.adb, s-tasque.ads, s-tasren.adb, s-tasren.ads, s-tasres.ads, s-tassta.adb, s-tassta.ads, s-tasuti.adb, s-tasuti.ads, s-tataat.adb, s-tataat.ads, s-tpinop.adb, s-tpinop.ads, s-tpoben.adb, s-tpoben.ads, s-tpobop.adb, s-tpobop.ads, s-tposen.adb, s-tposen.ads, s-traceb.adb, s-traceb.ads, stringt.adb, stringt.ads, stringt.h, style.ads, stylesw.adb, stylesw.ads, s-unstyp.ads, s-vaflop.ads, s-valrea.adb, s-valuti.adb, s-vercon.adb, s-vmexta.adb, s-wchcnv.ads, s-wchcon.ads, s-widcha.adb, switch.adb, switch.ads, switch-b.adb, switch-c.adb, switch-m.adb, s-wwdcha.adb, s-wwdwch.adb, sysdep.c, system.ads, table.adb, table.ads, targparm.adb, targparm.ads, targtyps.c, tbuild.adb, tbuild.ads, tracebak.c, trans.c, tree_io.adb, treepr.adb, treeprs.adt, ttypes.ads, types.ads, types.h, uintp.adb, uintp.ads, uintp.h, uname.adb, urealp.adb, urealp.ads, urealp.h, usage.adb, utils2.c, utils.c, validsw.adb, validsw.ads, widechar.adb, xeinfo.adb, xnmake.adb, xref_lib.adb, xref_lib.ads, xr_tabls.adb, xr_tabls.ads, xtreeprs.adb, xsnames.adb, einfo.h, sinfo.h, treeprs.ads, nmake.ads, nmake.adb, gnatvsn.ads: Merge with ACT tree. * gnatvsn.adb: Rewritten in a simpler and more efficient way. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@72751 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ada/checks.adb')
-rw-r--r--gcc/ada/checks.adb1894
1 files changed, 1672 insertions, 222 deletions
diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb
index 597c439a6a4..04a4c048d75 100644
--- a/gcc/ada/checks.adb
+++ b/gcc/ada/checks.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2002 Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2003 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- --
@@ -32,18 +32,23 @@ with Exp_Ch2; use Exp_Ch2;
with Exp_Util; use Exp_Util;
with Elists; use Elists;
with Freeze; use Freeze;
+with Lib; use Lib;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
+with Output; use Output;
with Restrict; use Restrict;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Eval; use Sem_Eval;
+with Sem_Ch8; use Sem_Ch8;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sem_Warn; use Sem_Warn;
with Sinfo; use Sinfo;
+with Sinput; use Sinput;
with Snames; use Snames;
+with Sprint; use Sprint;
with Stand; use Stand;
with Targparm; use Targparm;
with Tbuild; use Tbuild;
@@ -71,9 +76,115 @@ package body Checks is
-- the ability to emit constraint error warning for static expressions
-- even when we are not generating code.
- ----------------------------
- -- Local Subprogram Specs --
- ----------------------------
+ -------------------------------------
+ -- Suppression of Redundant Checks --
+ -------------------------------------
+
+ -- This unit implements a limited circuit for removal of redundant
+ -- checks. The processing is based on a tracing of simple sequential
+ -- flow. For any sequence of statements, we save expressions that are
+ -- marked to be checked, and then if the same expression appears later
+ -- with the same check, then under certain circumstances, the second
+ -- check can be suppressed.
+
+ -- Basically, we can suppress the check if we know for certain that
+ -- the previous expression has been elaborated (together with its
+ -- check), and we know that the exception frame is the same, and that
+ -- nothing has happened to change the result of the exception.
+
+ -- Let us examine each of these three conditions in turn to describe
+ -- how we ensure that this condition is met.
+
+ -- First, we need to know for certain that the previous expression has
+ -- been executed. This is done principly by the mechanism of calling
+ -- Conditional_Statements_Begin at the start of any statement sequence
+ -- and Conditional_Statements_End at the end. The End call causes all
+ -- checks remembered since the Begin call to be discarded. This does
+ -- miss a few cases, notably the case of a nested BEGIN-END block with
+ -- no exception handlers. But the important thing is to be conservative.
+ -- The other protection is that all checks are discarded if a label
+ -- is encountered, since then the assumption of sequential execution
+ -- is violated, and we don't know enough about the flow.
+
+ -- Second, we need to know that the exception frame is the same. We
+ -- do this by killing all remembered checks when we enter a new frame.
+ -- Again, that's over-conservative, but generally the cases we can help
+ -- with are pretty local anyway (like the body of a loop for example).
+
+ -- Third, we must be sure to forget any checks which are no longer valid.
+ -- This is done by two mechanisms, first the Kill_Checks_Variable call is
+ -- used to note any changes to local variables. We only attempt to deal
+ -- with checks involving local variables, so we do not need to worry
+ -- about global variables. Second, a call to any non-global procedure
+ -- causes us to abandon all stored checks, since such a all may affect
+ -- the values of any local variables.
+
+ -- The following define the data structures used to deal with remembering
+ -- checks so that redundant checks can be eliminated as described above.
+
+ -- Right now, the only expressions that we deal with are of the form of
+ -- simple local objects (either declared locally, or IN parameters) or
+ -- such objects plus/minus a compile time known constant. We can do
+ -- more later on if it seems worthwhile, but this catches many simple
+ -- cases in practice.
+
+ -- The following record type reflects a single saved check. An entry
+ -- is made in the stack of saved checks if and only if the expression
+ -- has been elaborated with the indicated checks.
+
+ type Saved_Check is record
+ Killed : Boolean;
+ -- Set True if entry is killed by Kill_Checks
+
+ Entity : Entity_Id;
+ -- The entity involved in the expression that is checked
+
+ Offset : Uint;
+ -- A compile time value indicating the result of adding or
+ -- subtracting a compile time value. This value is to be
+ -- added to the value of the Entity. A value of zero is
+ -- used for the case of a simple entity reference.
+
+ Check_Type : Character;
+ -- This is set to 'R' for a range check (in which case Target_Type
+ -- is set to the target type for the range check) or to 'O' for an
+ -- overflow check (in which case Target_Type is set to Empty).
+
+ Target_Type : Entity_Id;
+ -- Used only if Do_Range_Check is set. Records the target type for
+ -- the check. We need this, because a check is a duplicate only if
+ -- it has a the same target type (or more accurately one with a
+ -- range that is smaller or equal to the stored target type of a
+ -- saved check).
+ end record;
+
+ -- The following table keeps track of saved checks. Rather than use an
+ -- extensible table. We just use a table of fixed size, and we discard
+ -- any saved checks that do not fit. That's very unlikely to happen and
+ -- this is only an optimization in any case.
+
+ Saved_Checks : array (Int range 1 .. 200) of Saved_Check;
+ -- Array of saved checks
+
+ Num_Saved_Checks : Nat := 0;
+ -- Number of saved checks
+
+ -- The following stack keeps track of statement ranges. It is treated
+ -- as a stack. When Conditional_Statements_Begin is called, an entry
+ -- is pushed onto this stack containing the value of Num_Saved_Checks
+ -- at the time of the call. Then when Conditional_Statements_End is
+ -- called, this value is popped off and used to reset Num_Saved_Checks.
+
+ -- Note: again, this is a fixed length stack with a size that should
+ -- always be fine. If the value of the stack pointer goes above the
+ -- limit, then we just forget all saved checks.
+
+ Saved_Checks_Stack : array (Int range 1 .. 100) of Nat;
+ Saved_Checks_TOS : Nat := 0;
+
+ -----------------------
+ -- Local Subprograms --
+ -----------------------
procedure Apply_Selected_Length_Checks
(Ck_Node : Node_Id;
@@ -95,6 +206,26 @@ package body Checks is
-- routine. The Do_Static flag indicates that only a static check is
-- to be done.
+ procedure Find_Check
+ (Expr : Node_Id;
+ Check_Type : Character;
+ Target_Type : Entity_Id;
+ Entry_OK : out Boolean;
+ Check_Num : out Nat;
+ Ent : out Entity_Id;
+ Ofs : out Uint);
+ -- This routine is used by Enable_Range_Check and Enable_Overflow_Check
+ -- to see if a check is of the form for optimization, and if so, to see
+ -- if it has already been performed. Expr is the expression to check,
+ -- and Check_Type is 'R' for a range check, 'O' for an overflow check.
+ -- Target_Type is the target type for a range check, and Empty for an
+ -- overflow check. If the entry is not of the form for optimization,
+ -- then Entry_OK is set to False, and the remaining out parameters
+ -- are undefined. If the entry is OK, then Ent/Ofs are set to the
+ -- entity and offset from the expression. Check_Num is the number of
+ -- a matching saved entry in Saved_Checks, or zero if no such entry
+ -- is located.
+
function Get_Discriminal (E : Entity_Id; Bound : Node_Id) return Node_Id;
-- If a discriminal is used in constraining a prival, Return reference
-- to the discriminal of the protected body (which renames the parameter
@@ -142,8 +273,11 @@ package body Checks is
function Access_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Access_Checks
- or else (Present (E) and then Suppress_Access_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Access_Check);
+ else
+ return Scope_Suppress (Access_Check);
+ end if;
end Access_Checks_Suppressed;
-------------------------------------
@@ -152,8 +286,11 @@ package body Checks is
function Accessibility_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Accessibility_Checks
- or else (Present (E) and then Suppress_Accessibility_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Accessibility_Check);
+ else
+ return Scope_Suppress (Accessibility_Check);
+ end if;
end Accessibility_Checks_Suppressed;
-------------------------
@@ -167,8 +304,9 @@ package body Checks is
Static_Sloc : Source_Ptr;
Flag_Node : Node_Id)
is
- Internal_Flag_Node : Node_Id := Flag_Node;
- Internal_Static_Sloc : Source_Ptr := Static_Sloc;
+ Internal_Flag_Node : constant Node_Id := Flag_Node;
+ Internal_Static_Sloc : constant Source_Ptr := Static_Sloc;
+
Checks_On : constant Boolean :=
(not Index_Checks_Suppressed (Suppress_Typ))
or else
@@ -219,17 +357,53 @@ package body Checks is
Check_Unset_Reference (P);
end if;
- if Is_Entity_Name (P)
- and then Access_Checks_Suppressed (Entity (P))
- then
+ -- Don't need access check if prefix is known to be non-null
+
+ if Known_Non_Null (P) then
return;
+ -- Don't need access checks if they are suppressed on the type
+
elsif Access_Checks_Suppressed (Etype (P)) then
return;
+ end if;
- else
- Set_Do_Access_Check (N, True);
+ -- Case where P is an entity name
+
+ if Is_Entity_Name (P) then
+ declare
+ Ent : constant Entity_Id := Entity (P);
+
+ begin
+ if Access_Checks_Suppressed (Ent) then
+ return;
+ end if;
+
+ -- Otherwise we are going to generate an access check, and
+ -- are we have done it, the entity will now be known non null
+ -- But we have to check for safe sequential semantics here!
+
+ if Safe_To_Capture_Value (N, Ent) then
+ Set_Is_Known_Non_Null (Ent);
+ end if;
+ end;
end if;
+
+ -- Access check is required
+
+ declare
+ Loc : constant Source_Ptr := Sloc (N);
+
+ begin
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Sloc (N),
+ Condition =>
+ Make_Op_Eq (Loc,
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (P),
+ Right_Opnd =>
+ Make_Null (Loc)),
+ Reason => CE_Access_Check_Failed));
+ end;
end Apply_Access_Check;
-------------------------------
@@ -290,7 +464,13 @@ package body Checks is
Loc : Source_Ptr;
begin
- if No (AC) or else Range_Checks_Suppressed (E) then
+ -- See if check needed. Note that we never need a check if the
+ -- maximum alignment is one, since the check will always succeed
+
+ if No (AC)
+ or else not Check_Address_Alignment (AC)
+ or else Maximum_Alignment = 1
+ then
return;
end if;
@@ -341,7 +521,7 @@ package body Checks is
Left_Opnd =>
Unchecked_Convert_To
(RTE (RE_Integer_Address),
- Duplicate_Subexpr (Expr)),
+ Duplicate_Subexpr_No_Checks (Expr)),
Right_Opnd =>
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (E, Loc),
@@ -353,6 +533,10 @@ package body Checks is
end if;
return;
+
+ exception
+ when RE_Not_Available =>
+ return;
end Apply_Alignment_Check;
-------------------------------------
@@ -376,11 +560,11 @@ package body Checks is
Ctyp : Entity_Id;
Opnd : Node_Id;
Cent : RE_Id;
- Lo : Uint;
- Hi : Uint;
- OK : Boolean;
begin
+ -- Skip this if overflow checks are done in back end, or the overflow
+ -- flag is not set anyway, or we are not doing code expansion.
+
if Backend_Overflow_Checks_On_Target
or not Do_Overflow_Check (N)
or not Expander_Active
@@ -388,36 +572,8 @@ package body Checks is
return;
end if;
- -- Nothing to do if the range of the result is known OK
-
- Determine_Range (N, OK, Lo, Hi);
-
- -- Note in the test below that we assume that if a bound of the
- -- range is equal to that of the type. That's not quite accurate
- -- but we do this for the following reasons:
-
- -- a) The way that Determine_Range works, it will typically report
- -- the bounds of the value are the bounds of the type, because
- -- it either can't tell anything more precise, or does not think
- -- it is worth the effort to be more precise.
-
- -- b) It is very unusual to have a situation in which this would
- -- generate an unnecessary overflow check (an example would be
- -- a subtype with a range 0 .. Integer'Last - 1 to which the
- -- literal value one is added.
-
- -- c) The alternative is a lot of special casing in this routine
- -- which would partially duplicate the Determine_Range processing.
-
- if OK
- and then Lo > Expr_Value (Type_Low_Bound (Typ))
- and then Hi < Expr_Value (Type_High_Bound (Typ))
- then
- return;
- end if;
-
- -- None of the special case optimizations worked, so there is nothing
- -- for it but to generate the full general case code:
+ -- Otherwise, we generate the full general code for front end overflow
+ -- detection, which works by doing arithmetic in a larger type:
-- x op y
@@ -503,13 +659,30 @@ package body Checks is
-- Now build the outer conversion
Opnd := OK_Convert_To (Typ, Opnod);
-
Analyze (Opnd);
Set_Etype (Opnd, Typ);
- Set_Analyzed (Opnd, True);
- Set_Do_Overflow_Check (Opnd, True);
- Rewrite (N, Opnd);
+ -- In the discrete type case, we directly generate the range check
+ -- for the outer operand. This range check will implement the required
+ -- overflow check.
+
+ if Is_Discrete_Type (Typ) then
+ Rewrite (N, Opnd);
+ Generate_Range_Check (Expression (N), Typ, CE_Overflow_Check_Failed);
+
+ -- For other types, we enable overflow checking on the conversion,
+ -- after setting the node as analyzed to prevent recursive attempts
+ -- to expand the conversion node.
+
+ else
+ Set_Analyzed (Opnd, True);
+ Enable_Overflow_Check (Opnd);
+ Rewrite (N, Opnd);
+ end if;
+
+ exception
+ when RE_Not_Available =>
+ return;
end Apply_Arithmetic_Overflow_Check;
----------------------------
@@ -605,7 +778,7 @@ package body Checks is
return;
end if;
- -- It is pointless to insert this check inside an _init_proc, because
+ -- It is pointless to insert this check inside an init proc, because
-- that's too late, we have already built the object to be the right
-- size, and if it's too large, too bad!
@@ -688,9 +861,7 @@ package body Checks is
Insert_Action (N,
Make_Raise_Storage_Error (Loc,
Reason => SE_Object_Too_Large));
- Warn_On_Instance := True;
Error_Msg_N ("?Storage_Error will be raised at run-time", N);
- Warn_On_Instance := False;
Uintp.Release (Umark);
return;
end if;
@@ -715,13 +886,12 @@ package body Checks is
Sizx :=
Make_Attribute_Reference (Loc,
- Prefix => New_Occurrence_Of (Ctyp, Loc),
+ Prefix => New_Occurrence_Of (Ctyp, Loc),
Attribute_Name => Name_Size);
Indx := First_Index (Typ);
for J in 1 .. Number_Dimensions (Typ) loop
-
if Sloc (Etype (Indx)) = Sloc (N) then
Ensure_Defined (Etype (Indx), N);
end if;
@@ -942,8 +1112,7 @@ package body Checks is
if Nkind (Original_Node (N)) /= N_Allocator
and then (No (Lhs)
or else not Is_Entity_Name (Lhs)
- or else (Ekind (Entity (Lhs)) /= E_In_Out_Parameter
- and then Ekind (Entity (Lhs)) /= E_Out_Parameter))
+ or else No (Param_Entity (Lhs)))
then
if (Etype (N) = Typ
or else (Do_Access and then Designated_Type (Typ) = S_Typ))
@@ -960,7 +1129,8 @@ package body Checks is
and then Is_Entity_Name (Expression (Original_Node (N)))
then
declare
- Alloc_Typ : Entity_Id := Entity (Expression (Original_Node (N)));
+ Alloc_Typ : constant Entity_Id :=
+ Entity (Expression (Original_Node (N)));
begin
if Alloc_Typ = T_Typ
@@ -979,7 +1149,7 @@ package body Checks is
-- all the constraints are constants. In this case, we can do the
-- check successfully at compile time.
- -- we skip this check for the case where the node is a rewritten`
+ -- We skip this check for the case where the node is a rewritten`
-- allocator, because it already carries the context subtype, and
-- extracting the discriminants from the aggregate is messy.
@@ -1079,7 +1249,6 @@ package body Checks is
Make_Raise_Constraint_Error (Loc,
Condition => Cond,
Reason => CE_Discriminant_Check_Failed));
-
end Apply_Discriminant_Check;
------------------------
@@ -1116,7 +1285,7 @@ package body Checks is
Make_Raise_Constraint_Error (Loc,
Condition =>
Make_Op_Eq (Loc,
- Left_Opnd => Duplicate_Subexpr (Right),
+ Left_Opnd => Duplicate_Subexpr_Move_Checks (Right),
Right_Opnd => Make_Integer_Literal (Loc, 0)),
Reason => CE_Divide_By_Zero));
end if;
@@ -1142,11 +1311,13 @@ package body Checks is
Make_And_Then (Loc,
Make_Op_Eq (Loc,
- Left_Opnd => Duplicate_Subexpr (Left),
+ Left_Opnd =>
+ Duplicate_Subexpr_Move_Checks (Left),
Right_Opnd => Make_Integer_Literal (Loc, LLB)),
Make_Op_Eq (Loc,
- Left_Opnd => Duplicate_Subexpr (Right),
+ Left_Opnd =>
+ Duplicate_Subexpr (Right),
Right_Opnd =>
Make_Integer_Literal (Loc, -1))),
Reason => CE_Overflow_Check_Failed));
@@ -1218,6 +1389,10 @@ package body Checks is
procedure Bad_Value;
-- Procedure called if value is determined to be out of range
+ ---------------
+ -- Bad_Value --
+ ---------------
+
procedure Bad_Value is
begin
Apply_Compile_Time_Constraint_Error
@@ -1226,6 +1401,8 @@ package body Checks is
Typ => Target_Typ);
end Bad_Value;
+ -- Start of processing for Apply_Scalar_Range_Check
+
begin
if Inside_A_Generic then
return;
@@ -1261,21 +1438,21 @@ package body Checks is
-- Check array type and its base type
if Index_Checks_Suppressed (Arr_Typ)
- or else Suppress_Index_Checks (Base_Type (Arr_Typ))
+ or else Index_Checks_Suppressed (Base_Type (Arr_Typ))
then
return;
-- Check array itself if it is an entity name
elsif Is_Entity_Name (Arr)
- and then Suppress_Index_Checks (Entity (Arr))
+ and then Index_Checks_Suppressed (Entity (Arr))
then
return;
-- Check expression itself if it is an entity name
elsif Is_Entity_Name (Expr)
- and then Suppress_Index_Checks (Entity (Expr))
+ and then Index_Checks_Suppressed (Entity (Expr))
then
return;
end if;
@@ -1286,14 +1463,14 @@ package body Checks is
-- Check target type and its base type
if Range_Checks_Suppressed (Target_Typ)
- or else Suppress_Range_Checks (Base_Type (Target_Typ))
+ or else Range_Checks_Suppressed (Base_Type (Target_Typ))
then
return;
-- Check expression itself if it is an entity name
elsif Is_Entity_Name (Expr)
- and then Suppress_Range_Checks (Entity (Expr))
+ and then Range_Checks_Suppressed (Entity (Expr))
then
return;
@@ -1302,13 +1479,30 @@ package body Checks is
elsif Nkind (Parnt) = N_Assignment_Statement
and then Is_Entity_Name (Name (Parnt))
- and then Suppress_Range_Checks (Entity (Name (Parnt)))
+ and then Range_Checks_Suppressed (Entity (Name (Parnt)))
then
return;
end if;
end if;
end if;
+ -- Do not set range checks if they are killed
+
+ if Nkind (Expr) = N_Unchecked_Type_Conversion
+ and then Kill_Range_Check (Expr)
+ then
+ return;
+ end if;
+
+ -- Do not set range checks for any values from System.Scalar_Values
+ -- since the whole idea of such values is to avoid checking them!
+
+ if Is_Entity_Name (Expr)
+ and then Is_RTU (Scope (Entity (Expr)), System_Scalar_Values)
+ then
+ return;
+ end if;
+
-- Now see if we need a check
if No (Source_Typ) then
@@ -1325,7 +1519,8 @@ package body Checks is
Is_Subscr_Ref and then not Is_Constrained (Arr_Typ);
-- Always do a range check if the source type includes infinities
- -- and the target type does not include infinities.
+ -- and the target type does not include infinities. We do not do
+ -- this if range checks are killed.
if Is_Floating_Point_Type (S_Typ)
and then Has_Infinities (S_Typ)
@@ -1360,23 +1555,44 @@ package body Checks is
if Compile_Time_Known_Value (Tlo)
and then Compile_Time_Known_Value (Thi)
then
- Determine_Range (Expr, OK, Lo, Hi);
+ declare
+ Lov : constant Uint := Expr_Value (Tlo);
+ Hiv : constant Uint := Expr_Value (Thi);
- if OK then
- declare
- Lov : constant Uint := Expr_Value (Tlo);
- Hiv : constant Uint := Expr_Value (Thi);
+ begin
+ -- If range is null, we for sure have a constraint error
+ -- (we don't even need to look at the value involved,
+ -- since all possible values will raise CE).
+
+ if Lov > Hiv then
+ Bad_Value;
+ return;
+ end if;
+
+ -- Otherwise determine range of value
+
+ Determine_Range (Expr, OK, Lo, Hi);
+
+ if OK then
+
+ -- If definitely in range, all OK
- begin
if Lo >= Lov and then Hi <= Hiv then
return;
+ -- If definitely not in range, warn
+
elsif Lov > Hi or else Hiv < Lo then
Bad_Value;
return;
+
+ -- Otherwise we don't know
+
+ else
+ null;
end if;
- end;
- end if;
+ end if;
+ end;
end if;
end;
end if;
@@ -1386,10 +1602,9 @@ package body Checks is
or else (Is_Fixed_Point_Type (S_Typ) and then not Fixed_Int);
-- Check if we can determine at compile time whether Expr is in the
- -- range of the target type. Note that if S_Typ is within the
- -- bounds of Target_Typ then this must be the case. This checks is
- -- only meaningful if this is not a conversion between integer and
- -- real types.
+ -- range of the target type. Note that if S_Typ is within the bounds
+ -- of Target_Typ then this must be the case. This check is meaningful
+ -- only if this is not a conversion between integer and real types.
if not Is_Unconstrained_Subscr_Ref
and then
@@ -1405,27 +1620,21 @@ package body Checks is
Bad_Value;
return;
- -- Do not set range checks if they are killed
+ -- In the floating-point case, we only do range checks if the
+ -- type is constrained. We definitely do NOT want range checks
+ -- for unconstrained types, since we want to have infinities
- elsif Nkind (Expr) = N_Unchecked_Type_Conversion
- and then Kill_Range_Check (Expr)
- then
- return;
+ elsif Is_Floating_Point_Type (S_Typ) then
+ if Is_Constrained (S_Typ) then
+ Enable_Range_Check (Expr);
+ end if;
- -- ??? We only need a runtime check if the target type is constrained
- -- (the predefined type Float is not for instance).
- -- so the following should really be
- --
- -- elsif Is_Constrained (Target_Typ) then
- --
- -- but it isn't because certain types do not have the Is_Constrained
- -- flag properly set (see 1503-003).
+ -- For all other cases we enable a range check unconditionally
else
Enable_Range_Check (Expr);
return;
end if;
-
end Apply_Scalar_Range_Check;
----------------------------------
@@ -1457,7 +1666,6 @@ package body Checks is
Selected_Length_Checks (Ck_Node, Target_Typ, Source_Typ, Empty);
for J in 1 .. 2 loop
-
R_Cno := R_Result (J);
exit when No (R_Cno);
@@ -1613,9 +1821,7 @@ package body Checks is
else
Install_Static_Check (R_Cno, Loc);
end if;
-
end loop;
-
end Apply_Selected_Range_Checks;
-------------------------------
@@ -1667,9 +1873,8 @@ package body Checks is
procedure Apply_Type_Conversion_Checks (N : Node_Id) is
Target_Type : constant Entity_Id := Etype (N);
Target_Base : constant Entity_Id := Base_Type (Target_Type);
-
- Expr : constant Node_Id := Expression (N);
- Expr_Type : constant Entity_Id := Etype (Expr);
+ Expr : constant Node_Id := Expression (N);
+ Expr_Type : constant Entity_Id := Etype (Expr);
begin
if Inside_A_Generic then
@@ -1682,14 +1887,10 @@ package body Checks is
return;
-- Scalar type conversions of the form Target_Type (Expr) require
- -- two checks:
- --
- -- - First there is an overflow check to insure that Expr is
- -- in the base type of Target_Typ (4.6 (28)),
- --
- -- - After we know Expr fits into the base type, we must perform a
- -- range check to ensure that Expr meets the constraints of the
- -- Target_Type.
+ -- a range check if we cannot be sure that Expr is in the base type
+ -- of Target_Typ and also that Expr is in the range of Target_Typ.
+ -- These are not quite the same condition from an implementation
+ -- point of view, but clearly the second includes the first.
elsif Is_Scalar_Type (Target_Type) then
declare
@@ -1699,8 +1900,6 @@ package body Checks is
-- then fixed point values must be read as integral values.
begin
- -- Overflow check.
-
if not Overflow_Checks_Suppressed (Target_Base)
and then not In_Subrange_Of (Expr_Type, Target_Base, Conv_OK)
then
@@ -1720,26 +1919,28 @@ package body Checks is
and then Is_Derived_Type (Target_Type)
and then not Is_Tagged_Type (Target_Type)
and then not Is_Constrained (Target_Type)
- and then Present (Girder_Constraint (Target_Type))
+ and then Present (Stored_Constraint (Target_Type))
then
- -- A unconstrained derived type may have inherited discriminants.
- -- Build an actual discriminant constraint list using the girder
+ -- An unconstrained derived type may have inherited discriminant
+ -- Build an actual discriminant constraint list using the stored
-- constraint, to verify that the expression of the parent type
-- satisfies the constraints imposed by the (unconstrained!)
-- derived type. This applies to value conversions, not to view
-- conversions of tagged types.
declare
- Loc : constant Source_Ptr := Sloc (N);
- Cond : Node_Id;
- Constraint : Elmt_Id;
- Discr_Value : Node_Id;
- Discr : Entity_Id;
- New_Constraints : Elist_Id := New_Elmt_List;
- Old_Constraints : Elist_Id := Discriminant_Constraint (Expr_Type);
+ Loc : constant Source_Ptr := Sloc (N);
+ Cond : Node_Id;
+ Constraint : Elmt_Id;
+ Discr_Value : Node_Id;
+ Discr : Entity_Id;
+
+ New_Constraints : constant Elist_Id := New_Elmt_List;
+ Old_Constraints : constant Elist_Id :=
+ Discriminant_Constraint (Expr_Type);
begin
- Constraint := First_Elmt (Girder_Constraint (Target_Type));
+ Constraint := First_Elmt (Stored_Constraint (Target_Type));
while Present (Constraint) loop
Discr_Value := Node (Constraint);
@@ -1755,13 +1956,14 @@ package body Checks is
-- Parent is constrained by new discriminant. Obtain
-- Value of original discriminant in expression. If
-- the new discriminant has been used to constrain more
- -- than one of the girder ones, this will provide the
- -- required consistency check.
+ -- than one of the stored discriminants, this will
+ -- provide the required consistency check.
Append_Elmt (
Make_Selected_Component (Loc,
Prefix =>
- Duplicate_Subexpr (Expr, Name_Req => True),
+ Duplicate_Subexpr_No_Checks
+ (Expr, Name_Req => True),
Selector_Name =>
Make_Identifier (Loc, Chars (Discr))),
New_Constraints);
@@ -1773,11 +1975,12 @@ package body Checks is
end if;
-- Derived type definition has an explicit value for
- -- this girder discriminant.
+ -- this stored discriminant.
else
Append_Elmt
- (Duplicate_Subexpr (Discr_Value), New_Constraints);
+ (Duplicate_Subexpr_No_Checks (Discr_Value),
+ New_Constraints);
end if;
Next_Elmt (Constraint);
@@ -1797,12 +2000,14 @@ package body Checks is
Reason => CE_Discriminant_Check_Failed));
end;
- -- should there be other checks here for array types ???
+ -- For arrays, conversions are applied during expansion, to take
+ -- into accounts changes of representation. The checks become range
+ -- checks on the base type or length checks on the subtype, depending
+ -- on whether the target type is unconstrained or constrained.
else
null;
end if;
-
end Apply_Type_Conversion_Checks;
----------------------------------------------
@@ -1832,6 +2037,18 @@ package body Checks is
elsif not Comes_From_Source (N) then
return;
+ -- If the prefix is a selected component that depends on a discriminant
+ -- the check may improperly expose a discriminant instead of using
+ -- the bounds of the object itself. Set the type of the attribute to
+ -- the base type of the context, so that a check will be imposed when
+ -- needed (e.g. if the node appears as an index).
+
+ elsif Nkind (Prefix (N)) = N_Selected_Component
+ and then Ekind (Typ) = E_Signed_Integer_Subtype
+ and then Depends_On_Discriminant (Scalar_Range (Typ))
+ then
+ Set_Etype (N, Base_Type (Typ));
+
-- Otherwise, replace the attribute node with a type conversion
-- node whose expression is the attribute, retyped to universal
-- integer, and whose subtype mark is the target type. The call
@@ -1866,14 +2083,14 @@ package body Checks is
Cond : Node_Id;
Disc : Elmt_Id;
Disc_Ent : Entity_Id;
+ Dref : Node_Id;
Dval : Node_Id;
begin
Cond := Empty;
Disc := First_Elmt (Discriminant_Constraint (T_Typ));
- -- For a fully private type, use the discriminants of the parent
- -- type.
+ -- For a fully private type, use the discriminants of the parent type
if Is_Private_Type (T_Typ)
and then No (Full_View (T_Typ))
@@ -1884,7 +2101,6 @@ package body Checks is
end if;
while Present (Disc) loop
-
Dval := Node (Disc);
if Nkind (Dval) = N_Identifier
@@ -1892,17 +2108,21 @@ package body Checks is
then
Dval := New_Occurrence_Of (Discriminal (Entity (Dval)), Loc);
else
- Dval := Duplicate_Subexpr (Dval);
+ Dval := Duplicate_Subexpr_No_Checks (Dval);
end if;
+ Dref :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ Duplicate_Subexpr_No_Checks (N, Name_Req => True),
+ Selector_Name =>
+ Make_Identifier (Loc, Chars (Disc_Ent)));
+
+ Set_Is_In_Discriminant_Check (Dref);
+
Evolve_Or_Else (Cond,
Make_Op_Ne (Loc,
- Left_Opnd =>
- Make_Selected_Component (Loc,
- Prefix =>
- Duplicate_Subexpr (N, Name_Req => True),
- Selector_Name =>
- Make_Identifier (Loc, Chars (Disc_Ent))),
+ Left_Opnd => Dref,
Right_Opnd => Dval));
Next_Elmt (Disc);
@@ -1949,6 +2169,63 @@ package body Checks is
end if;
end Check_Valid_Lvalue_Subscripts;
+ ----------------------------------
+ -- Conditional_Statements_Begin --
+ ----------------------------------
+
+ procedure Conditional_Statements_Begin is
+ begin
+ Saved_Checks_TOS := Saved_Checks_TOS + 1;
+
+ -- If stack overflows, kill all checks, that way we know to
+ -- simply reset the number of saved checks to zero on return.
+ -- This should never occur in practice.
+
+ if Saved_Checks_TOS > Saved_Checks_Stack'Last then
+ Kill_All_Checks;
+
+ -- In the normal case, we just make a new stack entry saving
+ -- the current number of saved checks for a later restore.
+
+ else
+ Saved_Checks_Stack (Saved_Checks_TOS) := Num_Saved_Checks;
+
+ if Debug_Flag_CC then
+ w ("Conditional_Statements_Begin: Num_Saved_Checks = ",
+ Num_Saved_Checks);
+ end if;
+ end if;
+ end Conditional_Statements_Begin;
+
+ --------------------------------
+ -- Conditional_Statements_End --
+ --------------------------------
+
+ procedure Conditional_Statements_End is
+ begin
+ pragma Assert (Saved_Checks_TOS > 0);
+
+ -- If the saved checks stack overflowed, then we killed all
+ -- checks, so setting the number of saved checks back to
+ -- zero is correct. This should never occur in practice.
+
+ if Saved_Checks_TOS > Saved_Checks_Stack'Last then
+ Num_Saved_Checks := 0;
+
+ -- In the normal case, restore the number of saved checks
+ -- from the top stack entry.
+
+ else
+ Num_Saved_Checks := Saved_Checks_Stack (Saved_Checks_TOS);
+ if Debug_Flag_CC then
+ w ("Conditional_Statements_End: Num_Saved_Checks = ",
+ Num_Saved_Checks);
+ end if;
+ end if;
+
+ Saved_Checks_TOS := Saved_Checks_TOS - 1;
+ end Conditional_Statements_End;
+
---------------------
-- Determine_Range --
---------------------
@@ -2175,12 +2452,14 @@ package body Checks is
when N_Op_Mod =>
if OK_Operands then
- if Lo_Right = Hi_Right then
+ if Lo_Right = Hi_Right
+ and then Lo_Right /= 0
+ then
if Lo_Right > 0 then
Lor := Uint_0;
Hir := Lo_Right - 1;
- elsif Lo_Right < 0 then
+ else -- Lo_Right < 0
Lor := Lo_Right + 1;
Hir := Uint_0;
end if;
@@ -2195,7 +2474,9 @@ package body Checks is
when N_Op_Rem =>
if OK_Operands then
- if Lo_Right = Hi_Right then
+ if Lo_Right = Hi_Right
+ and then Lo_Right /= 0
+ then
declare
Dval : constant Uint := (abs Lo_Right) - 1;
@@ -2386,7 +2667,6 @@ package body Checks is
Hi := No_Uint;
return;
end if;
-
end Determine_Range;
------------------------------------
@@ -2395,8 +2675,15 @@ package body Checks is
function Discriminant_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Discriminant_Checks
- or else (Present (E) and then Suppress_Discriminant_Checks (E));
+ if Present (E) then
+ if Is_Unchecked_Union (E) then
+ return True;
+ elsif Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Discriminant_Check);
+ end if;
+ end if;
+
+ return Scope_Suppress (Discriminant_Check);
end Discriminant_Checks_Suppressed;
--------------------------------
@@ -2405,8 +2692,11 @@ package body Checks is
function Division_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Division_Checks
- or else (Present (E) and then Suppress_Division_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Division_Check);
+ else
+ return Scope_Suppress (Division_Check);
+ end if;
end Division_Checks_Suppressed;
-----------------------------------
@@ -2415,23 +2705,354 @@ package body Checks is
function Elaboration_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Elaboration_Checks
- or else (Present (E) and then Suppress_Elaboration_Checks (E));
+ if Present (E) then
+ if Kill_Elaboration_Checks (E) then
+ return True;
+ elsif Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Elaboration_Check);
+ end if;
+ end if;
+
+ return Scope_Suppress (Elaboration_Check);
end Elaboration_Checks_Suppressed;
+ ---------------------------
+ -- Enable_Overflow_Check --
+ ---------------------------
+
+ procedure Enable_Overflow_Check (N : Node_Id) is
+ Typ : constant Entity_Id := Base_Type (Etype (N));
+ Chk : Nat;
+ OK : Boolean;
+ Ent : Entity_Id;
+ Ofs : Uint;
+ Lo : Uint;
+ Hi : Uint;
+
+ begin
+ if Debug_Flag_CC then
+ w ("Enable_Overflow_Check for node ", Int (N));
+ Write_Str (" Source location = ");
+ wl (Sloc (N));
+ pg (N);
+ end if;
+
+ -- Nothing to do if the range of the result is known OK. We skip
+ -- this for conversions, since the caller already did the check,
+ -- and in any case the condition for deleting the check for a
+ -- type conversion is different in any case.
+
+ if Nkind (N) /= N_Type_Conversion then
+ Determine_Range (N, OK, Lo, Hi);
+
+ -- Note in the test below that we assume that if a bound of the
+ -- range is equal to that of the type. That's not quite accurate
+ -- but we do this for the following reasons:
+
+ -- a) The way that Determine_Range works, it will typically report
+ -- the bounds of the value as being equal to the bounds of the
+ -- type, because it either can't tell anything more precise, or
+ -- does not think it is worth the effort to be more precise.
+
+ -- b) It is very unusual to have a situation in which this would
+ -- generate an unnecessary overflow check (an example would be
+ -- a subtype with a range 0 .. Integer'Last - 1 to which the
+ -- literal value one is added.
+
+ -- c) The alternative is a lot of special casing in this routine
+ -- which would partially duplicate Determine_Range processing.
+
+ if OK
+ and then Lo > Expr_Value (Type_Low_Bound (Typ))
+ and then Hi < Expr_Value (Type_High_Bound (Typ))
+ then
+ if Debug_Flag_CC then
+ w ("No overflow check required");
+ end if;
+
+ return;
+ end if;
+ end if;
+
+ -- If not in optimizing mode, set flag and we are done. We are also
+ -- done (and just set the flag) if the type is not a discrete type,
+ -- since it is not worth the effort to eliminate checks for other
+ -- than discrete types. In addition, we take this same path if we
+ -- have stored the maximum number of checks possible already (a
+ -- very unlikely situation, but we do not want to blow up!)
+
+ if Optimization_Level = 0
+ or else not Is_Discrete_Type (Etype (N))
+ or else Num_Saved_Checks = Saved_Checks'Last
+ then
+ Set_Do_Overflow_Check (N, True);
+
+ if Debug_Flag_CC then
+ w ("Optimization off");
+ end if;
+
+ return;
+ end if;
+
+ -- Otherwise evaluate and check the expression
+
+ Find_Check
+ (Expr => N,
+ Check_Type => 'O',
+ Target_Type => Empty,
+ Entry_OK => OK,
+ Check_Num => Chk,
+ Ent => Ent,
+ Ofs => Ofs);
+
+ if Debug_Flag_CC then
+ w ("Called Find_Check");
+ w (" OK = ", OK);
+
+ if OK then
+ w (" Check_Num = ", Chk);
+ w (" Ent = ", Int (Ent));
+ Write_Str (" Ofs = ");
+ pid (Ofs);
+ end if;
+ end if;
+
+ -- If check is not of form to optimize, then set flag and we are done
+
+ if not OK then
+ Set_Do_Overflow_Check (N, True);
+ return;
+ end if;
+
+ -- If check is already performed, then return without setting flag
+
+ if Chk /= 0 then
+ if Debug_Flag_CC then
+ w ("Check suppressed!");
+ end if;
+
+ return;
+ end if;
+
+ -- Here we will make a new entry for the new check
+
+ Set_Do_Overflow_Check (N, True);
+ Num_Saved_Checks := Num_Saved_Checks + 1;
+ Saved_Checks (Num_Saved_Checks) :=
+ (Killed => False,
+ Entity => Ent,
+ Offset => Ofs,
+ Check_Type => 'O',
+ Target_Type => Empty);
+
+ if Debug_Flag_CC then
+ w ("Make new entry, check number = ", Num_Saved_Checks);
+ w (" Entity = ", Int (Ent));
+ Write_Str (" Offset = ");
+ pid (Ofs);
+ w (" Check_Type = O");
+ w (" Target_Type = Empty");
+ end if;
+
+ -- If we get an exception, then something went wrong, probably because
+ -- of an error in the structure of the tree due to an incorrect program.
+ -- Or it may be a bug in the optimization circuit. In either case the
+ -- safest thing is simply to set the check flag unconditionally.
+
+ exception
+ when others =>
+ Set_Do_Overflow_Check (N, True);
+
+ if Debug_Flag_CC then
+ w (" exception occurred, overflow flag set");
+ end if;
+
+ return;
+ end Enable_Overflow_Check;
+
------------------------
-- Enable_Range_Check --
------------------------
procedure Enable_Range_Check (N : Node_Id) is
+ Chk : Nat;
+ OK : Boolean;
+ Ent : Entity_Id;
+ Ofs : Uint;
+ Ttyp : Entity_Id;
+ P : Node_Id;
+
begin
+ -- Return if unchecked type conversion with range check killed.
+ -- In this case we never set the flag (that's what Kill_Range_Check
+ -- is all about!)
+
if Nkind (N) = N_Unchecked_Type_Conversion
and then Kill_Range_Check (N)
then
return;
+ end if;
+
+ -- Debug trace output
+
+ if Debug_Flag_CC then
+ w ("Enable_Range_Check for node ", Int (N));
+ Write_Str (" Source location = ");
+ wl (Sloc (N));
+ pg (N);
+ end if;
+
+ -- If not in optimizing mode, set flag and we are done. We are also
+ -- done (and just set the flag) if the type is not a discrete type,
+ -- since it is not worth the effort to eliminate checks for other
+ -- than discrete types. In addition, we take this same path if we
+ -- have stored the maximum number of checks possible already (a
+ -- very unlikely situation, but we do not want to blow up!)
+
+ if Optimization_Level = 0
+ or else No (Etype (N))
+ or else not Is_Discrete_Type (Etype (N))
+ or else Num_Saved_Checks = Saved_Checks'Last
+ then
+ Set_Do_Range_Check (N, True);
+
+ if Debug_Flag_CC then
+ w ("Optimization off");
+ end if;
+
+ return;
+ end if;
+
+ -- Otherwise find out the target type
+
+ P := Parent (N);
+
+ -- For assignment, use left side subtype
+
+ if Nkind (P) = N_Assignment_Statement
+ and then Expression (P) = N
+ then
+ Ttyp := Etype (Name (P));
+
+ -- For indexed component, use subscript subtype
+
+ elsif Nkind (P) = N_Indexed_Component then
+ declare
+ Atyp : Entity_Id;
+ Indx : Node_Id;
+ Subs : Node_Id;
+
+ begin
+ Atyp := Etype (Prefix (P));
+
+ if Is_Access_Type (Atyp) then
+ Atyp := Designated_Type (Atyp);
+ end if;
+
+ Indx := First_Index (Atyp);
+ Subs := First (Expressions (P));
+ loop
+ if Subs = N then
+ Ttyp := Etype (Indx);
+ exit;
+ end if;
+
+ Next_Index (Indx);
+ Next (Subs);
+ end loop;
+ end;
+
+ -- For now, ignore all other cases, they are not so interesting
+
else
+ if Debug_Flag_CC then
+ w (" target type not found, flag set");
+ end if;
+
+ Set_Do_Range_Check (N, True);
+ return;
+ end if;
+
+ -- Evaluate and check the expression
+
+ Find_Check
+ (Expr => N,
+ Check_Type => 'R',
+ Target_Type => Ttyp,
+ Entry_OK => OK,
+ Check_Num => Chk,
+ Ent => Ent,
+ Ofs => Ofs);
+
+ if Debug_Flag_CC then
+ w ("Called Find_Check");
+ w ("Target_Typ = ", Int (Ttyp));
+ w (" OK = ", OK);
+
+ if OK then
+ w (" Check_Num = ", Chk);
+ w (" Ent = ", Int (Ent));
+ Write_Str (" Ofs = ");
+ pid (Ofs);
+ end if;
+ end if;
+
+ -- If check is not of form to optimize, then set flag and we are done
+
+ if not OK then
+ if Debug_Flag_CC then
+ w (" expression not of optimizable type, flag set");
+ end if;
+
Set_Do_Range_Check (N, True);
+ return;
+ end if;
+
+ -- If check is already performed, then return without setting flag
+
+ if Chk /= 0 then
+ if Debug_Flag_CC then
+ w ("Check suppressed!");
+ end if;
+
+ return;
+ end if;
+
+ -- Here we will make a new entry for the new check
+
+ Set_Do_Range_Check (N, True);
+ Num_Saved_Checks := Num_Saved_Checks + 1;
+ Saved_Checks (Num_Saved_Checks) :=
+ (Killed => False,
+ Entity => Ent,
+ Offset => Ofs,
+ Check_Type => 'R',
+ Target_Type => Ttyp);
+
+ if Debug_Flag_CC then
+ w ("Make new entry, check number = ", Num_Saved_Checks);
+ w (" Entity = ", Int (Ent));
+ Write_Str (" Offset = ");
+ pid (Ofs);
+ w (" Check_Type = R");
+ w (" Target_Type = ", Int (Ttyp));
+ pg (Ttyp);
end if;
+
+ -- If we get an exception, then something went wrong, probably because
+ -- of an error in the structure of the tree due to an incorrect program.
+ -- Or it may be a bug in the optimization circuit. In either case the
+ -- safest thing is simply to set the check flag unconditionally.
+
+ exception
+ when others =>
+ Set_Do_Range_Check (N, True);
+
+ if Debug_Flag_CC then
+ w (" exception occurred, range flag set");
+ end if;
+
+ return;
end Enable_Range_Check;
------------------
@@ -2447,14 +3068,24 @@ package body Checks is
if not Validity_Checks_On then
return;
+ -- Ignore call if range checks suppressed on entity in question
+
+ elsif Is_Entity_Name (Expr)
+ and then Range_Checks_Suppressed (Entity (Expr))
+ then
+ return;
+
-- No check required if expression is from the expander, we assume
-- the expander will generate whatever checks are needed. Note that
-- this is not just an optimization, it avoids infinite recursions!
-- Unchecked conversions must be checked, unless they are initialized
- -- scalar values, as in a component assignment in an init_proc.
+ -- scalar values, as in a component assignment in an init proc.
+
+ -- In addition, we force a check if Force_Validity_Checks is set
elsif not Comes_From_Source (Expr)
+ and then not Force_Validity_Checks
and then (Nkind (Expr) /= N_Unchecked_Type_Conversion
or else Kill_Range_Check (Expr))
then
@@ -2515,11 +3146,19 @@ package body Checks is
end if;
-- Only need to worry if we are argument of a procedure
- -- call since functions don't have out parameters.
+ -- call since functions don't have out parameters. If this
+ -- is an indirect or dispatching call, get signature from
+ -- the subprogram type.
if Nkind (P) = N_Procedure_Call_Statement then
L := Parameter_Associations (P);
- E := Entity (Name (P));
+
+ if Is_Entity_Name (Name (P)) then
+ E := Entity (Name (P));
+ else
+ pragma Assert (Nkind (Name (P)) = N_Explicit_Dereference);
+ E := Etype (Name (P));
+ end if;
-- Only need to worry if there are indeed actuals, and
-- if this could be a procedure call, otherwise we cannot
@@ -2647,6 +3286,683 @@ package body Checks is
end if;
end Expr_Known_Valid;
+ ----------------
+ -- Find_Check --
+ ----------------
+
+ procedure Find_Check
+ (Expr : Node_Id;
+ Check_Type : Character;
+ Target_Type : Entity_Id;
+ Entry_OK : out Boolean;
+ Check_Num : out Nat;
+ Ent : out Entity_Id;
+ Ofs : out Uint)
+ is
+ function Within_Range_Of
+ (Target_Type : Entity_Id;
+ Check_Type : Entity_Id)
+ return Boolean;
+ -- Given a requirement for checking a range against Target_Type, and
+ -- and a range Check_Type against which a check has already been made,
+ -- determines if the check against check type is sufficient to ensure
+ -- that no check against Target_Type is required.
+
+ ---------------------
+ -- Within_Range_Of --
+ ---------------------
+
+ function Within_Range_Of
+ (Target_Type : Entity_Id;
+ Check_Type : Entity_Id)
+ return Boolean
+ is
+ begin
+ if Target_Type = Check_Type then
+ return True;
+
+ else
+ declare
+ Tlo : constant Node_Id := Type_Low_Bound (Target_Type);
+ Thi : constant Node_Id := Type_High_Bound (Target_Type);
+ Clo : constant Node_Id := Type_Low_Bound (Check_Type);
+ Chi : constant Node_Id := Type_High_Bound (Check_Type);
+
+ begin
+ if (Tlo = Clo
+ or else (Compile_Time_Known_Value (Tlo)
+ and then
+ Compile_Time_Known_Value (Clo)
+ and then
+ Expr_Value (Clo) >= Expr_Value (Tlo)))
+ and then
+ (Thi = Chi
+ or else (Compile_Time_Known_Value (Thi)
+ and then
+ Compile_Time_Known_Value (Chi)
+ and then
+ Expr_Value (Chi) <= Expr_Value (Clo)))
+ then
+ return True;
+ else
+ return False;
+ end if;
+ end;
+ end if;
+ end Within_Range_Of;
+
+ -- Start of processing for Find_Check
+
+ begin
+ -- Establish default, to avoid warnings from GCC.
+
+ Check_Num := 0;
+
+ -- Case of expression is simple entity reference
+
+ if Is_Entity_Name (Expr) then
+ Ent := Entity (Expr);
+ Ofs := Uint_0;
+
+ -- Case of expression is entity + known constant
+
+ elsif Nkind (Expr) = N_Op_Add
+ and then Compile_Time_Known_Value (Right_Opnd (Expr))
+ and then Is_Entity_Name (Left_Opnd (Expr))
+ then
+ Ent := Entity (Left_Opnd (Expr));
+ Ofs := Expr_Value (Right_Opnd (Expr));
+
+ -- Case of expression is entity - known constant
+
+ elsif Nkind (Expr) = N_Op_Subtract
+ and then Compile_Time_Known_Value (Right_Opnd (Expr))
+ and then Is_Entity_Name (Left_Opnd (Expr))
+ then
+ Ent := Entity (Left_Opnd (Expr));
+ Ofs := UI_Negate (Expr_Value (Right_Opnd (Expr)));
+
+ -- Any other expression is not of the right form
+
+ else
+ Ent := Empty;
+ Ofs := Uint_0;
+ Entry_OK := False;
+ return;
+ end if;
+
+ -- Come here with expression of appropriate form, check if
+ -- entity is an appropriate one for our purposes.
+
+ if (Ekind (Ent) = E_Variable
+ or else
+ Ekind (Ent) = E_Constant
+ or else
+ Ekind (Ent) = E_Loop_Parameter
+ or else
+ Ekind (Ent) = E_In_Parameter)
+ and then not Is_Library_Level_Entity (Ent)
+ then
+ Entry_OK := True;
+ else
+ Entry_OK := False;
+ return;
+ end if;
+
+ -- See if there is matching check already
+
+ for J in reverse 1 .. Num_Saved_Checks loop
+ declare
+ SC : Saved_Check renames Saved_Checks (J);
+
+ begin
+ if SC.Killed = False
+ and then SC.Entity = Ent
+ and then SC.Offset = Ofs
+ and then SC.Check_Type = Check_Type
+ and then Within_Range_Of (Target_Type, SC.Target_Type)
+ then
+ Check_Num := J;
+ return;
+ end if;
+ end;
+ end loop;
+
+ -- If we fall through entry was not found
+
+ Check_Num := 0;
+ return;
+ end Find_Check;
+
+ ---------------------------------
+ -- Generate_Discriminant_Check --
+ ---------------------------------
+
+ -- Note: the code for this procedure is derived from the
+ -- emit_discriminant_check routine a-trans.c v1.659.
+
+ procedure Generate_Discriminant_Check (N : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Pref : constant Node_Id := Prefix (N);
+ Sel : constant Node_Id := Selector_Name (N);
+
+ Orig_Comp : constant Entity_Id :=
+ Original_Record_Component (Entity (Sel));
+ -- The original component to be checked
+
+ Discr_Fct : constant Entity_Id :=
+ Discriminant_Checking_Func (Orig_Comp);
+ -- The discriminant checking function
+
+ Discr : Entity_Id;
+ -- One discriminant to be checked in the type
+
+ Real_Discr : Entity_Id;
+ -- Actual discriminant in the call
+
+ Pref_Type : Entity_Id;
+ -- Type of relevant prefix (ignoring private/access stuff)
+
+ Args : List_Id;
+ -- List of arguments for function call
+
+ Formal : Entity_Id;
+ -- Keep track of the formal corresponding to the actual we build
+ -- for each discriminant, in order to be able to perform the
+ -- necessary type conversions.
+
+ Scomp : Node_Id;
+ -- Selected component reference for checking function argument
+
+ begin
+ Pref_Type := Etype (Pref);
+
+ -- Force evaluation of the prefix, so that it does not get evaluated
+ -- twice (once for the check, once for the actual reference). Such a
+ -- double evaluation is always a potential source of inefficiency,
+ -- and is functionally incorrect in the volatile case, or when the
+ -- prefix may have side-effects. An entity or a component of an
+ -- entity requires no evaluation.
+
+ if Is_Entity_Name (Pref) then
+ if Treat_As_Volatile (Entity (Pref)) then
+ Force_Evaluation (Pref, Name_Req => True);
+ end if;
+
+ elsif Treat_As_Volatile (Etype (Pref)) then
+ Force_Evaluation (Pref, Name_Req => True);
+
+ elsif Nkind (Pref) = N_Selected_Component
+ and then Is_Entity_Name (Prefix (Pref))
+ then
+ null;
+
+ else
+ Force_Evaluation (Pref, Name_Req => True);
+ end if;
+
+ -- For a tagged type, use the scope of the original component to
+ -- obtain the type, because ???
+
+ if Is_Tagged_Type (Scope (Orig_Comp)) then
+ Pref_Type := Scope (Orig_Comp);
+
+ -- For an untagged derived type, use the discriminants of the
+ -- parent which have been renamed in the derivation, possibly
+ -- by a one-to-many discriminant constraint.
+ -- For non-tagged type, initially get the Etype of the prefix
+
+ else
+ if Is_Derived_Type (Pref_Type)
+ and then Number_Discriminants (Pref_Type) /=
+ Number_Discriminants (Etype (Base_Type (Pref_Type)))
+ then
+ Pref_Type := Etype (Base_Type (Pref_Type));
+ end if;
+ end if;
+
+ -- We definitely should have a checking function, This routine should
+ -- not be called if no discriminant checking function is present.
+
+ pragma Assert (Present (Discr_Fct));
+
+ -- Create the list of the actual parameters for the call. This list
+ -- is the list of the discriminant fields of the record expression to
+ -- be discriminant checked.
+
+ Args := New_List;
+ Formal := First_Formal (Discr_Fct);
+ Discr := First_Discriminant (Pref_Type);
+ while Present (Discr) loop
+
+ -- If we have a corresponding discriminant field, and a parent
+ -- subtype is present, then we want to use the corresponding
+ -- discriminant since this is the one with the useful value.
+
+ if Present (Corresponding_Discriminant (Discr))
+ and then Ekind (Pref_Type) = E_Record_Type
+ and then Present (Parent_Subtype (Pref_Type))
+ then
+ Real_Discr := Corresponding_Discriminant (Discr);
+ else
+ Real_Discr := Discr;
+ end if;
+
+ -- Construct the reference to the discriminant
+
+ Scomp :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ Unchecked_Convert_To (Pref_Type,
+ Duplicate_Subexpr (Pref)),
+ Selector_Name => New_Occurrence_Of (Real_Discr, Loc));
+
+ -- Manually analyze and resolve this selected component. We really
+ -- want it just as it appears above, and do not want the expander
+ -- playing discriminal games etc with this reference. Then we
+ -- append the argument to the list we are gathering.
+
+ Set_Etype (Scomp, Etype (Real_Discr));
+ Set_Analyzed (Scomp, True);
+ Append_To (Args, Convert_To (Etype (Formal), Scomp));
+
+ Next_Formal_With_Extras (Formal);
+ Next_Discriminant (Discr);
+ end loop;
+
+ -- Now build and insert the call
+
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Function_Call (Loc,
+ Name => New_Occurrence_Of (Discr_Fct, Loc),
+ Parameter_Associations => Args),
+ Reason => CE_Discriminant_Check_Failed));
+ end Generate_Discriminant_Check;
+
+ ----------------------------
+ -- Generate_Index_Checks --
+ ----------------------------
+
+ procedure Generate_Index_Checks (N : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ A : constant Node_Id := Prefix (N);
+ Sub : Node_Id;
+ Ind : Nat;
+ Num : List_Id;
+
+ begin
+ Sub := First (Expressions (N));
+ Ind := 1;
+ while Present (Sub) loop
+ if Do_Range_Check (Sub) then
+ Set_Do_Range_Check (Sub, False);
+
+ -- Force evaluation except for the case of a simple name of
+ -- a non-volatile entity.
+
+ if not Is_Entity_Name (Sub)
+ or else Treat_As_Volatile (Entity (Sub))
+ then
+ Force_Evaluation (Sub);
+ end if;
+
+ -- Generate a raise of constraint error with the appropriate
+ -- reason and a condition of the form:
+
+ -- Base_Type(Sub) not in array'range (subscript)
+
+ -- Note that the reason we generate the conversion to the
+ -- base type here is that we definitely want the range check
+ -- to take place, even if it looks like the subtype is OK.
+ -- Optimization considerations that allow us to omit the
+ -- check have already been taken into account in the setting
+ -- of the Do_Range_Check flag earlier on.
+
+ if Ind = 1 then
+ Num := No_List;
+ else
+ Num := New_List (Make_Integer_Literal (Loc, Ind));
+ end if;
+
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Not_In (Loc,
+ Left_Opnd =>
+ Convert_To (Base_Type (Etype (Sub)),
+ Duplicate_Subexpr_Move_Checks (Sub)),
+ Right_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Prefix => Duplicate_Subexpr_Move_Checks (A),
+ Attribute_Name => Name_Range,
+ Expressions => Num)),
+ Reason => CE_Index_Check_Failed));
+ end if;
+
+ Ind := Ind + 1;
+ Next (Sub);
+ end loop;
+ end Generate_Index_Checks;
+
+ --------------------------
+ -- Generate_Range_Check --
+ --------------------------
+
+ procedure Generate_Range_Check
+ (N : Node_Id;
+ Target_Type : Entity_Id;
+ Reason : RT_Exception_Code)
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+ Source_Type : constant Entity_Id := Etype (N);
+ Source_Base_Type : constant Entity_Id := Base_Type (Source_Type);
+ Target_Base_Type : constant Entity_Id := Base_Type (Target_Type);
+
+ begin
+ -- First special case, if the source type is already within the
+ -- range of the target type, then no check is needed (probably we
+ -- should have stopped Do_Range_Check from being set in the first
+ -- place, but better late than later in preventing junk code!
+
+ -- We do NOT apply this if the source node is a literal, since in
+ -- this case the literal has already been labeled as having the
+ -- subtype of the target.
+
+ if In_Subrange_Of (Source_Type, Target_Type)
+ and then not
+ (Nkind (N) = N_Integer_Literal
+ or else
+ Nkind (N) = N_Real_Literal
+ or else
+ Nkind (N) = N_Character_Literal
+ or else
+ (Is_Entity_Name (N)
+ and then Ekind (Entity (N)) = E_Enumeration_Literal))
+ then
+ return;
+ end if;
+
+ -- We need a check, so force evaluation of the node, so that it does
+ -- not get evaluated twice (once for the check, once for the actual
+ -- reference). Such a double evaluation is always a potential source
+ -- of inefficiency, and is functionally incorrect in the volatile case.
+
+ if not Is_Entity_Name (N)
+ or else Treat_As_Volatile (Entity (N))
+ then
+ Force_Evaluation (N);
+ end if;
+
+ -- The easiest case is when Source_Base_Type and Target_Base_Type
+ -- are the same since in this case we can simply do a direct
+ -- check of the value of N against the bounds of Target_Type.
+
+ -- [constraint_error when N not in Target_Type]
+
+ -- Note: this is by far the most common case, for example all cases of
+ -- checks on the RHS of assignments are in this category, but not all
+ -- cases are like this. Notably conversions can involve two types.
+
+ if Source_Base_Type = Target_Base_Type then
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Not_In (Loc,
+ Left_Opnd => Duplicate_Subexpr (N),
+ Right_Opnd => New_Occurrence_Of (Target_Type, Loc)),
+ Reason => Reason));
+
+ -- Next test for the case where the target type is within the bounds
+ -- of the base type of the source type, since in this case we can
+ -- simply convert these bounds to the base type of T to do the test.
+
+ -- [constraint_error when N not in
+ -- Source_Base_Type (Target_Type'First)
+ -- ..
+ -- Source_Base_Type(Target_Type'Last))]
+
+ -- The conversions will always work and need no check.
+
+ elsif In_Subrange_Of (Target_Type, Source_Base_Type) then
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Not_In (Loc,
+ Left_Opnd => Duplicate_Subexpr (N),
+
+ Right_Opnd =>
+ Make_Range (Loc,
+ Low_Bound =>
+ Convert_To (Source_Base_Type,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_First)),
+
+ High_Bound =>
+ Convert_To (Source_Base_Type,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_Last)))),
+ Reason => Reason));
+
+ -- Note that at this stage we now that the Target_Base_Type is
+ -- not in the range of the Source_Base_Type (since even the
+ -- Target_Type itself is not in this range). It could still be
+ -- the case that the Source_Type is in range of the target base
+ -- type, since we have not checked that case.
+
+ -- If that is the case, we can freely convert the source to the
+ -- target, and then test the target result against the bounds.
+
+ elsif In_Subrange_Of (Source_Type, Target_Base_Type) then
+
+ -- We make a temporary to hold the value of the converted
+ -- value (converted to the base type), and then we will
+ -- do the test against this temporary.
+
+ -- Tnn : constant Target_Base_Type := Target_Base_Type (N);
+ -- [constraint_error when Tnn not in Target_Type]
+
+ -- Then the conversion itself is replaced by an occurrence of Tnn
+
+ declare
+ Tnn : constant Entity_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_Internal_Name ('T'));
+
+ begin
+ Insert_Actions (N, New_List (
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Tnn,
+ Object_Definition =>
+ New_Occurrence_Of (Target_Base_Type, Loc),
+ Constant_Present => True,
+ Expression =>
+ Make_Type_Conversion (Loc,
+ Subtype_Mark => New_Occurrence_Of (Target_Base_Type, Loc),
+ Expression => Duplicate_Subexpr (N))),
+
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Not_In (Loc,
+ Left_Opnd => New_Occurrence_Of (Tnn, Loc),
+ Right_Opnd => New_Occurrence_Of (Target_Type, Loc)),
+
+ Reason => Reason)));
+
+ Rewrite (N, New_Occurrence_Of (Tnn, Loc));
+ end;
+
+ -- At this stage, we know that we have two scalar types, which are
+ -- directly convertible, and where neither scalar type has a base
+ -- range that is in the range of the other scalar type.
+
+ -- The only way this can happen is with a signed and unsigned type.
+ -- So test for these two cases:
+
+ else
+ -- Case of the source is unsigned and the target is signed
+
+ if Is_Unsigned_Type (Source_Base_Type)
+ and then not Is_Unsigned_Type (Target_Base_Type)
+ then
+ -- If the source is unsigned and the target is signed, then we
+ -- know that the source is not shorter than the target (otherwise
+ -- the source base type would be in the target base type range).
+
+ -- In other words, the unsigned type is either the same size
+ -- as the target, or it is larger. It cannot be smaller.
+
+ pragma Assert
+ (Esize (Source_Base_Type) >= Esize (Target_Base_Type));
+
+ -- We only need to check the low bound if the low bound of the
+ -- target type is non-negative. If the low bound of the target
+ -- type is negative, then we know that we will fit fine.
+
+ -- If the high bound of the target type is negative, then we
+ -- know we have a constraint error, since we can't possibly
+ -- have a negative source.
+
+ -- With these two checks out of the way, we can do the check
+ -- using the source type safely
+
+ -- This is definitely the most annoying case!
+
+ -- [constraint_error
+ -- when (Target_Type'First >= 0
+ -- and then
+ -- N < Source_Base_Type (Target_Type'First))
+ -- or else Target_Type'Last < 0
+ -- or else N > Source_Base_Type (Target_Type'Last)];
+
+ -- We turn off all checks since we know that the conversions
+ -- will work fine, given the guards for negative values.
+
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Or_Else (Loc,
+ Make_Or_Else (Loc,
+ Left_Opnd =>
+ Make_And_Then (Loc,
+ Left_Opnd => Make_Op_Ge (Loc,
+ Left_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_First),
+ Right_Opnd => Make_Integer_Literal (Loc, Uint_0)),
+
+ Right_Opnd =>
+ Make_Op_Lt (Loc,
+ Left_Opnd => Duplicate_Subexpr (N),
+ Right_Opnd =>
+ Convert_To (Source_Base_Type,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_First)))),
+
+ Right_Opnd =>
+ Make_Op_Lt (Loc,
+ Left_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_Last),
+ Right_Opnd => Make_Integer_Literal (Loc, Uint_0))),
+
+ Right_Opnd =>
+ Make_Op_Gt (Loc,
+ Left_Opnd => Duplicate_Subexpr (N),
+ Right_Opnd =>
+ Convert_To (Source_Base_Type,
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Target_Type, Loc),
+ Attribute_Name => Name_Last)))),
+
+ Reason => Reason),
+ Suppress => All_Checks);
+
+ -- Only remaining possibility is that the source is signed and
+ -- the target is unsigned
+
+ else
+ pragma Assert (not Is_Unsigned_Type (Source_Base_Type)
+ and then Is_Unsigned_Type (Target_Base_Type));
+
+ -- If the source is signed and the target is unsigned, then
+ -- we know that the target is not shorter than the source
+ -- (otherwise the target base type would be in the source
+ -- base type range).
+
+ -- In other words, the unsigned type is either the same size
+ -- as the target, or it is larger. It cannot be smaller.
+
+ -- Clearly we have an error if the source value is negative
+ -- since no unsigned type can have negative values. If the
+ -- source type is non-negative, then the check can be done
+ -- using the target type.
+
+ -- Tnn : constant Target_Base_Type (N) := Target_Type;
+
+ -- [constraint_error
+ -- when N < 0 or else Tnn not in Target_Type];
+
+ -- We turn off all checks for the conversion of N to the
+ -- target base type, since we generate the explicit check
+ -- to ensure that the value is non-negative
+
+ declare
+ Tnn : constant Entity_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_Internal_Name ('T'));
+
+ begin
+ Insert_Actions (N, New_List (
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Tnn,
+ Object_Definition =>
+ New_Occurrence_Of (Target_Base_Type, Loc),
+ Constant_Present => True,
+ Expression =>
+ Make_Type_Conversion (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of (Target_Base_Type, Loc),
+ Expression => Duplicate_Subexpr (N))),
+
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Or_Else (Loc,
+ Left_Opnd =>
+ Make_Op_Lt (Loc,
+ Left_Opnd => Duplicate_Subexpr (N),
+ Right_Opnd => Make_Integer_Literal (Loc, Uint_0)),
+
+ Right_Opnd =>
+ Make_Not_In (Loc,
+ Left_Opnd => New_Occurrence_Of (Tnn, Loc),
+ Right_Opnd =>
+ New_Occurrence_Of (Target_Type, Loc))),
+
+ Reason => Reason)),
+ Suppress => All_Checks);
+
+ -- Set the Etype explicitly, because Insert_Actions may
+ -- have placed the declaration in the freeze list for an
+ -- enclosing construct, and thus it is not analyzed yet.
+
+ Set_Etype (Tnn, Target_Base_Type);
+ Rewrite (N, New_Occurrence_Of (Tnn, Loc));
+ end;
+ end if;
+ end if;
+ end Generate_Range_Check;
+
---------------------
-- Get_Discriminal --
---------------------
@@ -2704,7 +4020,7 @@ package body Checks is
Make_And_Then (Loc,
Left_Opnd =>
Make_Op_Ne (Loc,
- Left_Opnd => Duplicate_Subexpr (Ck_Node),
+ Left_Opnd => Duplicate_Subexpr_No_Checks (Ck_Node),
Right_Opnd => Make_Null (Loc)),
Right_Opnd => Cond);
end if;
@@ -2716,8 +4032,11 @@ package body Checks is
function Index_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Index_Checks
- or else (Present (E) and then Suppress_Index_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Index_Check);
+ else
+ return Scope_Suppress (Index_Check);
+ end if;
end Index_Checks_Suppressed;
----------------
@@ -2842,7 +4161,7 @@ package body Checks is
Right_Opnd =>
Make_Attribute_Reference (Loc,
Prefix =>
- Duplicate_Subexpr (Exp, Name_Req => True),
+ Duplicate_Subexpr_No_Checks (Exp, Name_Req => True),
Attribute_Name => Name_Valid)),
Reason => CE_Invalid_Data),
Suppress => All_Checks);
@@ -2867,14 +4186,59 @@ package body Checks is
Set_Is_Static_Expression (R_Cno, Stat);
end Install_Static_Check;
+ ---------------------
+ -- Kill_All_Checks --
+ ---------------------
+
+ procedure Kill_All_Checks is
+ begin
+ if Debug_Flag_CC then
+ w ("Kill_All_Checks");
+ end if;
+
+ -- We reset the number of saved checks to zero, and also modify
+ -- all stack entries for statement ranges to indicate that the
+ -- number of checks at each level is now zero.
+
+ Num_Saved_Checks := 0;
+
+ for J in 1 .. Saved_Checks_TOS loop
+ Saved_Checks_Stack (J) := 0;
+ end loop;
+ end Kill_All_Checks;
+
+ -----------------
+ -- Kill_Checks --
+ -----------------
+
+ procedure Kill_Checks (V : Entity_Id) is
+ begin
+ if Debug_Flag_CC then
+ w ("Kill_Checks for entity", Int (V));
+ end if;
+
+ for J in 1 .. Num_Saved_Checks loop
+ if Saved_Checks (J).Entity = V then
+ if Debug_Flag_CC then
+ w (" Checks killed for saved check ", J);
+ end if;
+
+ Saved_Checks (J).Killed := True;
+ end if;
+ end loop;
+ end Kill_Checks;
+
------------------------------
-- Length_Checks_Suppressed --
------------------------------
function Length_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Length_Checks
- or else (Present (E) and then Suppress_Length_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Length_Check);
+ else
+ return Scope_Suppress (Length_Check);
+ end if;
end Length_Checks_Suppressed;
--------------------------------
@@ -2883,8 +4247,11 @@ package body Checks is
function Overflow_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Overflow_Checks
- or else (Present (E) and then Suppress_Overflow_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Overflow_Check);
+ else
+ return Scope_Suppress (Overflow_Check);
+ end if;
end Overflow_Checks_Suppressed;
-----------------
@@ -2909,12 +4276,21 @@ package body Checks is
function Range_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- -- Note: for now we always suppress range checks on Vax float types,
- -- since Gigi does not know how to generate these checks.
+ if Present (E) then
+
+ -- Note: for now we always suppress range checks on Vax float types,
+ -- since Gigi does not know how to generate these checks.
+
+ if Vax_Float (E) then
+ return True;
+ elsif Kill_Range_Checks (E) then
+ return True;
+ elsif Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Range_Check);
+ end if;
+ end if;
- return Scope_Suppress.Range_Checks
- or else (Present (E) and then Suppress_Range_Checks (E))
- or else Vax_Float (E);
+ return Scope_Suppress (Range_Check);
end Range_Checks_Suppressed;
-------------------
@@ -2923,6 +4299,7 @@ package body Checks is
procedure Remove_Checks (Expr : Node_Id) is
Discard : Traverse_Result;
+ pragma Warnings (Off, Discard);
function Process (N : Node_Id) return Traverse_Result;
-- Process a single node during the traversal
@@ -2948,18 +4325,11 @@ package body Checks is
return Skip;
when N_Attribute_Reference =>
- Set_Do_Access_Check (N, False);
Set_Do_Overflow_Check (N, False);
- when N_Explicit_Dereference =>
- Set_Do_Access_Check (N, False);
-
when N_Function_Call =>
Set_Do_Tag_Check (N, False);
- when N_Indexed_Component =>
- Set_Do_Access_Check (N, False);
-
when N_Op =>
Set_Do_Overflow_Check (N, False);
@@ -2991,16 +4361,12 @@ package body Checks is
return Skip;
when N_Selected_Component =>
- Set_Do_Access_Check (N, False);
Set_Do_Discriminant_Check (N, False);
- when N_Slice =>
- Set_Do_Access_Check (N, False);
-
when N_Type_Conversion =>
- Set_Do_Length_Check (N, False);
+ Set_Do_Length_Check (N, False);
+ Set_Do_Tag_Check (N, False);
Set_Do_Overflow_Check (N, False);
- Set_Do_Tag_Check (N, False);
when others =>
null;
@@ -3046,7 +4412,7 @@ package body Checks is
function Same_Bounds (L : Node_Id; R : Node_Id) return Boolean;
-- True for equal literals and for nodes that denote the same constant
-- entity, even if its value is not a static constant. This includes the
- -- case of a discriminal reference within an init_proc. Removes some
+ -- case of a discriminal reference within an init proc. Removes some
-- obviously superfluous checks.
function Length_E_Cond
@@ -3090,9 +4456,9 @@ package body Checks is
------------------
function Get_E_Length (E : Entity_Id; Indx : Nat) return Node_Id is
+ Pt : constant Entity_Id := Scope (Scope (E));
N : Node_Id;
E1 : Entity_Id := E;
- Pt : Entity_Id := Scope (Scope (E));
begin
if Ekind (Scope (E)) = E_Record_Type
@@ -3155,11 +4521,11 @@ package body Checks is
if Do_Expand then
if not Is_Entity_Name (Lo) then
- Lo := Duplicate_Subexpr (Lo);
+ Lo := Duplicate_Subexpr_No_Checks (Lo);
end if;
if not Is_Entity_Name (Hi) then
- Lo := Duplicate_Subexpr (Hi);
+ Lo := Duplicate_Subexpr_No_Checks (Hi);
end if;
N :=
@@ -3215,7 +4581,7 @@ package body Checks is
Make_Attribute_Reference (Loc,
Attribute_Name => Name_Length,
Prefix =>
- Duplicate_Subexpr (N, Name_Req => True),
+ Duplicate_Subexpr_No_Checks (N, Name_Req => True),
Expressions => New_List (
Make_Integer_Literal (Loc, Indx)));
@@ -3354,7 +4720,9 @@ package body Checks is
-- T_Typ'Length = string-literal-length
- if Nkind (Expr_Actual) = N_String_Literal then
+ if Nkind (Expr_Actual) = N_String_Literal
+ and then Ekind (Etype (Expr_Actual)) = E_String_Literal_Subtype
+ then
Cond :=
Make_Op_Ne (Loc,
Left_Opnd => Get_E_Length (T_Typ, 1),
@@ -3374,19 +4742,35 @@ package body Checks is
elsif Is_Constrained (Exptyp) then
declare
- L_Index : Node_Id;
- R_Index : Node_Id;
- Ndims : Nat := Number_Dimensions (T_Typ);
-
- L_Low : Node_Id;
- L_High : Node_Id;
- R_Low : Node_Id;
- R_High : Node_Id;
-
+ Ndims : constant Nat := Number_Dimensions (T_Typ);
+
+ L_Index : Node_Id;
+ R_Index : Node_Id;
+ L_Low : Node_Id;
+ L_High : Node_Id;
+ R_Low : Node_Id;
+ R_High : Node_Id;
L_Length : Uint;
R_Length : Uint;
+ Ref_Node : Node_Id;
begin
+
+ -- At the library level, we need to ensure that the
+ -- type of the object is elaborated before the check
+ -- itself is emitted.
+
+ if Is_Itype (Exptyp)
+ and then
+ Ekind (Cunit_Entity (Current_Sem_Unit)) = E_Package
+ and then
+ not In_Package_Body (Cunit_Entity (Current_Sem_Unit))
+ then
+ Ref_Node := Make_Itype_Reference (Sloc (Ck_Node));
+ Set_Itype (Ref_Node, Exptyp);
+ Insert_Action (Ck_Node, Ref_Node);
+ end if;
+
L_Index := First_Index (T_Typ);
R_Index := First_Index (Exptyp);
@@ -3470,7 +4854,7 @@ package body Checks is
else
declare
- Ndims : Nat := Number_Dimensions (T_Typ);
+ Ndims : constant Nat := Number_Dimensions (T_Typ);
begin
-- Build the condition for the explicit dereference case
@@ -3554,7 +4938,7 @@ package body Checks is
function Get_N_First (N : Node_Id; Indx : Nat) return Node_Id;
function Get_N_Last (N : Node_Id; Indx : Nat) return Node_Id;
-- Returns expression to compute:
- -- N'First or N'Last using Duplicate_Subexpr
+ -- N'First or N'Last using Duplicate_Subexpr_No_Checks
function Range_E_Cond
(Exptyp : Entity_Id;
@@ -3615,7 +4999,8 @@ package body Checks is
Left_Opnd =>
Make_Op_Lt (Loc,
Left_Opnd =>
- Convert_To (Base_Type (Typ), Duplicate_Subexpr (Expr)),
+ Convert_To (Base_Type (Typ),
+ Duplicate_Subexpr_No_Checks (Expr)),
Right_Opnd =>
Convert_To (Base_Type (Typ),
Get_E_First_Or_Last (Typ, 0, Name_First))),
@@ -3623,7 +5008,8 @@ package body Checks is
Right_Opnd =>
Make_Op_Gt (Loc,
Left_Opnd =>
- Convert_To (Base_Type (Typ), Duplicate_Subexpr (Expr)),
+ Convert_To (Base_Type (Typ),
+ Duplicate_Subexpr_No_Checks (Expr)),
Right_Opnd =>
Convert_To
(Base_Type (Typ),
@@ -3660,7 +5046,7 @@ package body Checks is
Make_Op_Lt (Loc,
Left_Opnd =>
Convert_To
- (Base_Type (Typ), Duplicate_Subexpr (LB)),
+ (Base_Type (Typ), Duplicate_Subexpr_No_Checks (LB)),
Right_Opnd =>
Convert_To
@@ -3694,7 +5080,7 @@ package body Checks is
Make_Op_Gt (Loc,
Left_Opnd =>
Convert_To
- (Base_Type (Typ), Duplicate_Subexpr (HB)),
+ (Base_Type (Typ), Duplicate_Subexpr_No_Checks (HB)),
Right_Opnd =>
Convert_To
@@ -3753,7 +5139,50 @@ package body Checks is
if Nkind (Bound) = N_Identifier
and then Ekind (Entity (Bound)) = E_Discriminant
then
- return New_Occurrence_Of (Discriminal (Entity (Bound)), Loc);
+ -- If this is a task discriminant, and we are the body, we must
+ -- retrieve the corresponding body discriminal. This is another
+ -- consequence of the early creation of discriminals, and the
+ -- need to generate constraint checks before their declarations
+ -- are made visible.
+
+ if Is_Concurrent_Record_Type (Scope (Entity (Bound))) then
+ declare
+ Tsk : constant Entity_Id :=
+ Corresponding_Concurrent_Type
+ (Scope (Entity (Bound)));
+ Disc : Entity_Id;
+
+ begin
+ if In_Open_Scopes (Tsk)
+ and then Has_Completion (Tsk)
+ then
+ -- Find discriminant of original task, and use its
+ -- current discriminal, which is the renaming within
+ -- the task body.
+
+ Disc := First_Discriminant (Tsk);
+ while Present (Disc) loop
+ if Chars (Disc) = Chars (Entity (Bound)) then
+ Set_Scope (Discriminal (Disc), Tsk);
+ return New_Occurrence_Of (Discriminal (Disc), Loc);
+ end if;
+
+ Next_Discriminant (Disc);
+ end loop;
+
+ -- That loop should always succeed in finding a matching
+ -- entry and returning. Fatal error if not.
+
+ raise Program_Error;
+
+ else
+ return
+ New_Occurrence_Of (Discriminal (Entity (Bound)), Loc);
+ end if;
+ end;
+ else
+ return New_Occurrence_Of (Discriminal (Entity (Bound)), Loc);
+ end if;
elsif Nkind (Bound) = N_Identifier
and then Ekind (Entity (Bound)) = E_In_Parameter
@@ -3765,7 +5194,7 @@ package body Checks is
return Make_Integer_Literal (Loc, Intval (Bound));
else
- return Duplicate_Subexpr (Bound);
+ return Duplicate_Subexpr_No_Checks (Bound);
end if;
end Get_E_First_Or_Last;
@@ -3779,7 +5208,7 @@ package body Checks is
Make_Attribute_Reference (Loc,
Attribute_Name => Name_First,
Prefix =>
- Duplicate_Subexpr (N, Name_Req => True),
+ Duplicate_Subexpr_No_Checks (N, Name_Req => True),
Expressions => New_List (
Make_Integer_Literal (Loc, Indx)));
@@ -3795,7 +5224,7 @@ package body Checks is
Make_Attribute_Reference (Loc,
Attribute_Name => Name_Last,
Prefix =>
- Duplicate_Subexpr (N, Name_Req => True),
+ Duplicate_Subexpr_No_Checks (N, Name_Req => True),
Expressions => New_List (
Make_Integer_Literal (Loc, Indx)));
@@ -4030,7 +5459,7 @@ package body Checks is
-- the record declaration, it is a use of the discriminant
-- in a constraint of a component, and nothing can be
-- checked here. The check will be emitted within the
- -- init_proc. Before then, the discriminal has no real
+ -- init proc. Before then, the discriminal has no real
-- meaning.
if Nkind (LB) = N_Identifier
@@ -4062,8 +5491,8 @@ package body Checks is
Make_And_Then (Loc,
Left_Opnd =>
Make_Op_Ge (Loc,
- Left_Opnd => Duplicate_Subexpr (HB),
- Right_Opnd => Duplicate_Subexpr (LB)),
+ Left_Opnd => Duplicate_Subexpr_No_Checks (HB),
+ Right_Opnd => Duplicate_Subexpr_No_Checks (LB)),
Right_Opnd => Cond);
end;
@@ -4180,14 +5609,14 @@ package body Checks is
elsif Is_Constrained (Exptyp) then
declare
+ Ndims : constant Nat := Number_Dimensions (T_Typ);
+
L_Index : Node_Id;
R_Index : Node_Id;
- Ndims : Nat := Number_Dimensions (T_Typ);
-
- L_Low : Node_Id;
- L_High : Node_Id;
- R_Low : Node_Id;
- R_High : Node_Id;
+ L_Low : Node_Id;
+ L_High : Node_Id;
+ R_Low : Node_Id;
+ R_High : Node_Id;
begin
L_Index := First_Index (T_Typ);
@@ -4243,7 +5672,7 @@ package body Checks is
else
declare
- Ndims : Nat := Number_Dimensions (T_Typ);
+ Ndims : constant Nat := Number_Dimensions (T_Typ);
begin
-- Build the condition for the explicit dereference case
@@ -4282,6 +5711,17 @@ package body Checks is
then
null;
+ -- If null range, no check needed.
+ elsif
+ Compile_Time_Known_Value (High_Bound (Opnd_Index))
+ and then
+ Compile_Time_Known_Value (Low_Bound (Opnd_Index))
+ and then
+ Expr_Value (High_Bound (Opnd_Index)) <
+ Expr_Value (Low_Bound (Opnd_Index))
+ then
+ null;
+
elsif Is_Out_Of_Range
(Low_Bound (Opnd_Index), Etype (Targ_Index))
or else
@@ -4330,8 +5770,11 @@ package body Checks is
function Storage_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Storage_Checks
- or else (Present (E) and then Suppress_Storage_Checks (E));
+ if Present (E) and then Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Storage_Check);
+ else
+ return Scope_Suppress (Storage_Check);
+ end if;
end Storage_Checks_Suppressed;
---------------------------
@@ -4340,8 +5783,15 @@ package body Checks is
function Tag_Checks_Suppressed (E : Entity_Id) return Boolean is
begin
- return Scope_Suppress.Tag_Checks
- or else (Present (E) and then Suppress_Tag_Checks (E));
+ if Present (E) then
+ if Kill_Tag_Checks (E) then
+ return True;
+ elsif Checks_May_Be_Suppressed (E) then
+ return Is_Check_Suppressed (E, Tag_Check);
+ end if;
+ end if;
+
+ return Scope_Suppress (Tag_Check);
end Tag_Checks_Suppressed;
end Checks;
OpenPOWER on IntegriCloud