aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-ssa-sprintf.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/gimple-ssa-sprintf.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/gimple-ssa-sprintf.c')
-rw-r--r--gcc/gimple-ssa-sprintf.c4728
1 files changed, 0 insertions, 4728 deletions
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
deleted file mode 100644
index 1f756b7..0000000
--- a/gcc/gimple-ssa-sprintf.c
+++ /dev/null
@@ -1,4728 +0,0 @@
-/* Copyright (C) 2016-2022 Free Software Foundation, Inc.
- Contributed by Martin Sebor <msebor@redhat.com>.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT 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
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-/* This file implements the printf-return-value pass. The pass does
- two things: 1) it analyzes calls to formatted output functions like
- sprintf looking for possible buffer overflows and calls to bounded
- functions like snprintf for early truncation (and under the control
- of the -Wformat-length option issues warnings), and 2) under the
- control of the -fprintf-return-value option it folds the return
- value of safe calls into constants, making it possible to eliminate
- code that depends on the value of those constants.
-
- For all functions (bounded or not) the pass uses the size of the
- destination object. That means that it will diagnose calls to
- snprintf not on the basis of the size specified by the function's
- second argument but rather on the basis of the size the first
- argument points to (if possible). For bound-checking built-ins
- like __builtin___snprintf_chk the pass uses the size typically
- determined by __builtin_object_size and passed to the built-in
- by the Glibc inline wrapper.
-
- The pass handles all forms standard sprintf format directives,
- including character, integer, floating point, pointer, and strings,
- with the standard C flags, widths, and precisions. For integers
- and strings it computes the length of output itself. For floating
- point it uses MPFR to format known constants with up and down
- rounding and uses the resulting range of output lengths. For
- strings it uses the length of string literals and the sizes of
- character arrays that a character pointer may point to as a bound
- on the longest string. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "tree.h"
-#include "gimple.h"
-#include "tree-pass.h"
-#include "ssa.h"
-#include "gimple-fold.h"
-#include "gimple-pretty-print.h"
-#include "diagnostic-core.h"
-#include "fold-const.h"
-#include "gimple-iterator.h"
-#include "tree-ssa.h"
-#include "tree-object-size.h"
-#include "tree-cfg.h"
-#include "tree-ssa-propagate.h"
-#include "calls.h"
-#include "cfgloop.h"
-#include "tree-scalar-evolution.h"
-#include "tree-ssa-loop.h"
-#include "intl.h"
-#include "langhooks.h"
-
-#include "attribs.h"
-#include "builtins.h"
-#include "pointer-query.h"
-#include "stor-layout.h"
-
-#include "realmpfr.h"
-#include "target.h"
-
-#include "cpplib.h"
-#include "input.h"
-#include "toplev.h"
-#include "substring-locations.h"
-#include "diagnostic.h"
-#include "domwalk.h"
-#include "alloc-pool.h"
-#include "vr-values.h"
-#include "tree-ssa-strlen.h"
-#include "tree-dfa.h"
-
-/* The likely worst case value of MB_LEN_MAX for the target, large enough
- for UTF-8. Ideally, this would be obtained by a target hook if it were
- to be used for optimization but it's good enough as is for warnings. */
-#define target_mb_len_max() 6
-
-/* The maximum number of bytes a single non-string directive can result
- in. This is the result of printf("%.*Lf", INT_MAX, -LDBL_MAX) for
- LDBL_MAX_10_EXP of 4932. */
-#define IEEE_MAX_10_EXP 4932
-#define target_dir_max() (target_int_max () + IEEE_MAX_10_EXP + 2)
-
-namespace {
-
-/* Set to the warning level for the current function which is equal
- either to warn_format_trunc for bounded functions or to
- warn_format_overflow otherwise. */
-
-static int warn_level;
-
-/* The minimum, maximum, likely, and unlikely maximum number of bytes
- of output either a formatting function or an individual directive
- can result in. */
-
-struct result_range
-{
- /* The absolute minimum number of bytes. The result of a successful
- conversion is guaranteed to be no less than this. (An erroneous
- conversion can be indicated by MIN > HOST_WIDE_INT_MAX.) */
- unsigned HOST_WIDE_INT min;
- /* The likely maximum result that is used in diagnostics. In most
- cases MAX is the same as the worst case UNLIKELY result. */
- unsigned HOST_WIDE_INT max;
- /* The likely result used to trigger diagnostics. For conversions
- that result in a range of bytes [MIN, MAX], LIKELY is somewhere
- in that range. */
- unsigned HOST_WIDE_INT likely;
- /* In rare cases (e.g., for multibyte characters) UNLIKELY gives
- the worst cases maximum result of a directive. In most cases
- UNLIKELY == MAX. UNLIKELY is used to control the return value
- optimization but not in diagnostics. */
- unsigned HOST_WIDE_INT unlikely;
-};
-
-/* Return the value of INT_MIN for the target. */
-
-static inline HOST_WIDE_INT
-target_int_min ()
-{
- return tree_to_shwi (TYPE_MIN_VALUE (integer_type_node));
-}
-
-/* Return the value of INT_MAX for the target. */
-
-static inline unsigned HOST_WIDE_INT
-target_int_max ()
-{
- return tree_to_uhwi (TYPE_MAX_VALUE (integer_type_node));
-}
-
-/* Return the value of SIZE_MAX for the target. */
-
-static inline unsigned HOST_WIDE_INT
-target_size_max ()
-{
- return tree_to_uhwi (TYPE_MAX_VALUE (size_type_node));
-}
-
-/* A straightforward mapping from the execution character set to the host
- character set indexed by execution character. */
-
-static char target_to_host_charmap[256];
-
-/* Initialize a mapping from the execution character set to the host
- character set. */
-
-static bool
-init_target_to_host_charmap ()
-{
- /* If the percent sign is non-zero the mapping has already been
- initialized. */
- if (target_to_host_charmap['%'])
- return true;
-
- /* Initialize the target_percent character (done elsewhere). */
- if (!init_target_chars ())
- return false;
-
- /* The subset of the source character set used by printf conversion
- specifications (strictly speaking, not all letters are used but
- they are included here for the sake of simplicity). The dollar
- sign must be included even though it's not in the basic source
- character set. */
- const char srcset[] = " 0123456789!\"#%&'()*+,-./:;<=>?[\\]^_{|}~$"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
- /* Set the mapping for all characters to some ordinary value (i,e.,
- not none used in printf conversion specifications) and overwrite
- those that are used by conversion specifications with their
- corresponding values. */
- memset (target_to_host_charmap + 1, '?', sizeof target_to_host_charmap - 1);
-
- /* Are the two sets of characters the same? */
- bool all_same_p = true;
-
- for (const char *pc = srcset; *pc; ++pc)
- {
- /* Slice off the high end bits in case target characters are
- signed. All values are expected to be non-nul, otherwise
- there's a problem. */
- if (unsigned char tc = lang_hooks.to_target_charset (*pc))
- {
- target_to_host_charmap[tc] = *pc;
- if (tc != *pc)
- all_same_p = false;
- }
- else
- return false;
-
- }
-
- /* Set the first element to a non-zero value if the mapping
- is 1-to-1, otherwise leave it clear (NUL is assumed to be
- the same in both character sets). */
- target_to_host_charmap[0] = all_same_p;
-
- return true;
-}
-
-/* Return the host source character corresponding to the character
- CH in the execution character set if one exists, or some innocuous
- (non-special, non-nul) source character otherwise. */
-
-static inline unsigned char
-target_to_host (unsigned char ch)
-{
- return target_to_host_charmap[ch];
-}
-
-/* Convert an initial substring of the string TARGSTR consisting of
- characters in the execution character set into a string in the
- source character set on the host and store up to HOSTSZ characters
- in the buffer pointed to by HOSTR. Return HOSTR. */
-
-static const char*
-target_to_host (char *hostr, size_t hostsz, const char *targstr)
-{
- /* Make sure the buffer is reasonably big. */
- gcc_assert (hostsz > 4);
-
- /* The interesting subset of source and execution characters are
- the same so no conversion is necessary. However, truncate
- overlong strings just like the translated strings are. */
- if (target_to_host_charmap['\0'] == 1)
- {
- size_t len = strlen (targstr);
- if (len >= hostsz)
- {
- memcpy (hostr, targstr, hostsz - 4);
- strcpy (hostr + hostsz - 4, "...");
- }
- else
- memcpy (hostr, targstr, len + 1);
- return hostr;
- }
-
- /* Convert the initial substring of TARGSTR to the corresponding
- characters in the host set, appending "..." if TARGSTR is too
- long to fit. Using the static buffer assumes the function is
- not called in between sequence points (which it isn't). */
- for (char *ph = hostr; ; ++targstr)
- {
- *ph++ = target_to_host (*targstr);
- if (!*targstr)
- break;
-
- if (size_t (ph - hostr) == hostsz)
- {
- strcpy (ph - 4, "...");
- break;
- }
- }
-
- return hostr;
-}
-
-/* Convert the sequence of decimal digits in the execution character
- starting at *PS to a HOST_WIDE_INT, analogously to strtol. Return
- the result and set *PS to one past the last converted character.
- On range error set ERANGE to the digit that caused it. */
-
-static inline HOST_WIDE_INT
-target_strtowi (const char **ps, const char **erange)
-{
- unsigned HOST_WIDE_INT val = 0;
- for ( ; ; ++*ps)
- {
- unsigned char c = target_to_host (**ps);
- if (ISDIGIT (c))
- {
- c -= '0';
-
- /* Check for overflow. */
- if (val > ((unsigned HOST_WIDE_INT) HOST_WIDE_INT_MAX - c) / 10LU)
- {
- val = HOST_WIDE_INT_MAX;
- *erange = *ps;
-
- /* Skip the remaining digits. */
- do
- c = target_to_host (*++*ps);
- while (ISDIGIT (c));
- break;
- }
- else
- val = val * 10 + c;
- }
- else
- break;
- }
-
- return val;
-}
-
-/* Given FORMAT, set *PLOC to the source location of the format string
- and return the format string if it is known or null otherwise. */
-
-static const char*
-get_format_string (tree format, location_t *ploc)
-{
- *ploc = EXPR_LOC_OR_LOC (format, input_location);
-
- return c_getstr (format);
-}
-
-/* For convenience and brevity, shorter named entrypoints of
- format_string_diagnostic_t::emit_warning_va and
- format_string_diagnostic_t::emit_warning_n_va.
- These have to be functions with the attribute so that exgettext
- works properly. */
-
-static bool
-ATTRIBUTE_GCC_DIAG (5, 6)
-fmtwarn (const substring_loc &fmt_loc, location_t param_loc,
- const char *corrected_substring, opt_code opt,
- const char *gmsgid, ...)
-{
- format_string_diagnostic_t diag (fmt_loc, NULL, param_loc, NULL,
- corrected_substring);
- va_list ap;
- va_start (ap, gmsgid);
- bool warned = diag.emit_warning_va (opt, gmsgid, &ap);
- va_end (ap);
-
- return warned;
-}
-
-static bool
-ATTRIBUTE_GCC_DIAG (6, 8) ATTRIBUTE_GCC_DIAG (7, 8)
-fmtwarn_n (const substring_loc &fmt_loc, location_t param_loc,
- const char *corrected_substring, opt_code opt,
- unsigned HOST_WIDE_INT n,
- const char *singular_gmsgid, const char *plural_gmsgid, ...)
-{
- format_string_diagnostic_t diag (fmt_loc, NULL, param_loc, NULL,
- corrected_substring);
- va_list ap;
- va_start (ap, plural_gmsgid);
- bool warned = diag.emit_warning_n_va (opt, n, singular_gmsgid, plural_gmsgid,
- &ap);
- va_end (ap);
-
- return warned;
-}
-
-/* Format length modifiers. */
-
-enum format_lengths
-{
- FMT_LEN_none,
- FMT_LEN_hh, // char argument
- FMT_LEN_h, // short
- FMT_LEN_l, // long
- FMT_LEN_ll, // long long
- FMT_LEN_L, // long double (and GNU long long)
- FMT_LEN_z, // size_t
- FMT_LEN_t, // ptrdiff_t
- FMT_LEN_j // intmax_t
-};
-
-
-/* Description of the result of conversion either of a single directive
- or the whole format string. */
-
-class fmtresult
-{
-public:
- /* Construct a FMTRESULT object with all counters initialized
- to MIN. KNOWNRANGE is set when MIN is valid. */
- fmtresult (unsigned HOST_WIDE_INT min = HOST_WIDE_INT_MAX)
- : argmin (), argmax (), dst_offset (HOST_WIDE_INT_MIN), nonstr (),
- knownrange (min < HOST_WIDE_INT_MAX),
- mayfail (), nullp ()
- {
- range.min = min;
- range.max = min;
- range.likely = min;
- range.unlikely = min;
- }
-
- /* Construct a FMTRESULT object with MIN, MAX, and LIKELY counters.
- KNOWNRANGE is set when both MIN and MAX are valid. */
- fmtresult (unsigned HOST_WIDE_INT min, unsigned HOST_WIDE_INT max,
- unsigned HOST_WIDE_INT likely = HOST_WIDE_INT_MAX)
- : argmin (), argmax (), dst_offset (HOST_WIDE_INT_MIN), nonstr (),
- knownrange (min < HOST_WIDE_INT_MAX && max < HOST_WIDE_INT_MAX),
- mayfail (), nullp ()
- {
- range.min = min;
- range.max = max;
- range.likely = max < likely ? min : likely;
- range.unlikely = max;
- }
-
- /* Adjust result upward to reflect the RANGE of values the specified
- width or precision is known to be in. */
- fmtresult& adjust_for_width_or_precision (const HOST_WIDE_INT[2],
- tree = NULL_TREE,
- unsigned = 0, unsigned = 0);
-
- /* Return the maximum number of decimal digits a value of TYPE
- formats as on output. */
- static unsigned type_max_digits (tree, int);
-
- /* The range a directive's argument is in. */
- tree argmin, argmax;
-
- /* The starting offset into the destination of the formatted function
- call of the %s argument that points into (aliases with) the same
- destination array. */
- HOST_WIDE_INT dst_offset;
-
- /* The minimum and maximum number of bytes that a directive
- results in on output for an argument in the range above. */
- result_range range;
-
- /* Non-nul when the argument of a string directive is not a nul
- terminated string. */
- tree nonstr;
-
- /* True when the range above is obtained from a known value of
- a directive's argument or its bounds and not the result of
- heuristics that depend on warning levels. */
- bool knownrange;
-
- /* True for a directive that may fail (such as wide character
- directives). */
- bool mayfail;
-
- /* True when the argument is a null pointer. */
- bool nullp;
-};
-
-/* Adjust result upward to reflect the range ADJUST of values the
- specified width or precision is known to be in. When non-null,
- TYPE denotes the type of the directive whose result is being
- adjusted, BASE gives the base of the directive (octal, decimal,
- or hex), and ADJ denotes the additional adjustment to the LIKELY
- counter that may need to be added when ADJUST is a range. */
-
-fmtresult&
-fmtresult::adjust_for_width_or_precision (const HOST_WIDE_INT adjust[2],
- tree type /* = NULL_TREE */,
- unsigned base /* = 0 */,
- unsigned adj /* = 0 */)
-{
- bool minadjusted = false;
-
- /* Adjust the minimum and likely counters. */
- if (adjust[0] >= 0)
- {
- if (range.min < (unsigned HOST_WIDE_INT)adjust[0])
- {
- range.min = adjust[0];
- minadjusted = true;
- }
-
- /* Adjust the likely counter. */
- if (range.likely < range.min)
- range.likely = range.min;
- }
- else if (adjust[0] == target_int_min ()
- && (unsigned HOST_WIDE_INT)adjust[1] == target_int_max ())
- knownrange = false;
-
- /* Adjust the maximum counter. */
- if (adjust[1] > 0)
- {
- if (range.max < (unsigned HOST_WIDE_INT)adjust[1])
- {
- range.max = adjust[1];
-
- /* Set KNOWNRANGE if both the minimum and maximum have been
- adjusted. Otherwise leave it at what it was before. */
- knownrange = minadjusted;
- }
- }
-
- if (warn_level > 1 && type)
- {
- /* For large non-constant width or precision whose range spans
- the maximum number of digits produced by the directive for
- any argument, set the likely number of bytes to be at most
- the number digits plus other adjustment determined by the
- caller (one for sign or two for the hexadecimal "0x"
- prefix). */
- unsigned dirdigs = type_max_digits (type, base);
- if (adjust[0] < dirdigs && dirdigs < adjust[1]
- && range.likely < dirdigs)
- range.likely = dirdigs + adj;
- }
- else if (range.likely < (range.min ? range.min : 1))
- {
- /* Conservatively, set LIKELY to at least MIN but no less than
- 1 unless MAX is zero. */
- range.likely = (range.min
- ? range.min
- : range.max && (range.max < HOST_WIDE_INT_MAX
- || warn_level > 1) ? 1 : 0);
- }
-
- /* Finally adjust the unlikely counter to be at least as large as
- the maximum. */
- if (range.unlikely < range.max)
- range.unlikely = range.max;
-
- return *this;
-}
-
-/* Return the maximum number of digits a value of TYPE formats in
- BASE on output, not counting base prefix . */
-
-unsigned
-fmtresult::type_max_digits (tree type, int base)
-{
- unsigned prec = TYPE_PRECISION (type);
- switch (base)
- {
- case 8:
- return (prec + 2) / 3;
- case 10:
- /* Decimal approximation: yields 3, 5, 10, and 20 for precision
- of 8, 16, 32, and 64 bits. */
- return prec * 301 / 1000 + 1;
- case 16:
- return prec / 4;
- }
-
- gcc_unreachable ();
-}
-
-static bool
-get_int_range (tree, gimple *, HOST_WIDE_INT *, HOST_WIDE_INT *,
- bool, HOST_WIDE_INT, range_query *);
-
-struct call_info;
-
-/* Description of a format directive. A directive is either a plain
- string or a conversion specification that starts with '%'. */
-
-struct directive
-{
- directive (const call_info *inf, unsigned dno)
- : info (inf), dirno (dno), argno (), beg (), len (), flags (),
- width (), prec (), modifier (), specifier (), arg (), fmtfunc ()
- { }
-
- /* Reference to the info structure describing the call that this
- directive is a part of. */
- const call_info *info;
-
- /* The 1-based directive number (for debugging). */
- unsigned dirno;
-
- /* The zero-based argument number of the directive's argument ARG in
- the function's argument list. */
- unsigned argno;
-
- /* The first character of the directive and its length. */
- const char *beg;
- size_t len;
-
- /* A bitmap of flags, one for each character. */
- unsigned flags[256 / sizeof (int)];
-
- /* The range of values of the specified width, or -1 if not specified. */
- HOST_WIDE_INT width[2];
- /* The range of values of the specified precision, or -1 if not
- specified. */
- HOST_WIDE_INT prec[2];
-
- /* Length modifier. */
- format_lengths modifier;
-
- /* Format specifier character. */
- char specifier;
-
- /* The argument of the directive or null when the directive doesn't
- take one or when none is available (such as for vararg functions). */
- tree arg;
-
- /* Format conversion function that given a directive and an argument
- returns the formatting result. */
- fmtresult (*fmtfunc) (const directive &, tree, range_query *);
-
- /* Return True when the format flag CHR has been used. */
- bool get_flag (char chr) const
- {
- unsigned char c = chr & 0xff;
- return (flags[c / (CHAR_BIT * sizeof *flags)]
- & (1U << (c % (CHAR_BIT * sizeof *flags))));
- }
-
- /* Make a record of the format flag CHR having been used. */
- void set_flag (char chr)
- {
- unsigned char c = chr & 0xff;
- flags[c / (CHAR_BIT * sizeof *flags)]
- |= (1U << (c % (CHAR_BIT * sizeof *flags)));
- }
-
- /* Reset the format flag CHR. */
- void clear_flag (char chr)
- {
- unsigned char c = chr & 0xff;
- flags[c / (CHAR_BIT * sizeof *flags)]
- &= ~(1U << (c % (CHAR_BIT * sizeof *flags)));
- }
-
- /* Set both bounds of the width range to VAL. */
- void set_width (HOST_WIDE_INT val)
- {
- width[0] = width[1] = val;
- }
-
- /* Set the width range according to ARG, with both bounds being
- no less than 0. For a constant ARG set both bounds to its value
- or 0, whichever is greater. For a non-constant ARG in some range
- set width to its range adjusting each bound to -1 if it's less.
- For an indeterminate ARG set width to [0, INT_MAX]. */
- void set_width (tree arg, range_query *);
-
- /* Set both bounds of the precision range to VAL. */
- void set_precision (HOST_WIDE_INT val)
- {
- prec[0] = prec[1] = val;
- }
-
- /* Set the precision range according to ARG, with both bounds being
- no less than -1. For a constant ARG set both bounds to its value
- or -1 whichever is greater. For a non-constant ARG in some range
- set precision to its range adjusting each bound to -1 if it's less.
- For an indeterminate ARG set precision to [-1, INT_MAX]. */
- void set_precision (tree arg, range_query *query);
-
- /* Return true if both width and precision are known to be
- either constant or in some range, false otherwise. */
- bool known_width_and_precision () const
- {
- return ((width[1] < 0
- || (unsigned HOST_WIDE_INT)width[1] <= target_int_max ())
- && (prec[1] < 0
- || (unsigned HOST_WIDE_INT)prec[1] < target_int_max ()));
- }
-};
-
-/* The result of a call to a formatted function. */
-
-struct format_result
-{
- format_result ()
- : range (), aliases (), alias_count (), knownrange (), posunder4k (),
- floating (), warned () { /* No-op. */ }
-
- ~format_result ()
- {
- XDELETEVEC (aliases);
- }
-
- /* Range of characters written by the formatted function.
- Setting the minimum to HOST_WIDE_INT_MAX disables all
- length tracking for the remainder of the format string. */
- result_range range;
-
- struct alias_info
- {
- directive dir; /* The directive that aliases the destination. */
- HOST_WIDE_INT offset; /* The offset at which it aliases it. */
- result_range range; /* The raw result of the directive. */
- };
-
- /* An array of directives whose pointer argument aliases a part
- of the destination object of the formatted function. */
- alias_info *aliases;
- unsigned alias_count;
-
- /* True when the range above is obtained from known values of
- directive arguments, or bounds on the amount of output such
- as width and precision, and not the result of heuristics that
- depend on warning levels. It's used to issue stricter diagnostics
- in cases where strings of unknown lengths are bounded by the arrays
- they are determined to refer to. KNOWNRANGE must not be used for
- the return value optimization. */
- bool knownrange;
-
- /* True if no individual directive could fail or result in more than
- 4095 bytes of output (the total NUMBER_CHARS_{MIN,MAX} might be
- greater). Implementations are not required to handle directives
- that produce more than 4K bytes (leading to undefined behavior)
- and so when one is found it disables the return value optimization.
- Similarly, directives that can fail (such as wide character
- directives) disable the optimization. */
- bool posunder4k;
-
- /* True when a floating point directive has been seen in the format
- string. */
- bool floating;
-
- /* True when an intermediate result has caused a warning. Used to
- avoid issuing duplicate warnings while finishing the processing
- of a call. WARNED also disables the return value optimization. */
- bool warned;
-
- /* Preincrement the number of output characters by 1. */
- format_result& operator++ ()
- {
- return *this += 1;
- }
-
- /* Postincrement the number of output characters by 1. */
- format_result operator++ (int)
- {
- format_result prev (*this);
- *this += 1;
- return prev;
- }
-
- /* Increment the number of output characters by N. */
- format_result& operator+= (unsigned HOST_WIDE_INT);
-
- /* Add a directive to the sequence of those with potentially aliasing
- arguments. */
- void append_alias (const directive &, HOST_WIDE_INT, const result_range &);
-
-private:
- /* Not copyable or assignable. */
- format_result (format_result&);
- void operator= (format_result&);
-};
-
-format_result&
-format_result::operator+= (unsigned HOST_WIDE_INT n)
-{
- gcc_assert (n < HOST_WIDE_INT_MAX);
-
- if (range.min < HOST_WIDE_INT_MAX)
- range.min += n;
-
- if (range.max < HOST_WIDE_INT_MAX)
- range.max += n;
-
- if (range.likely < HOST_WIDE_INT_MAX)
- range.likely += n;
-
- if (range.unlikely < HOST_WIDE_INT_MAX)
- range.unlikely += n;
-
- return *this;
-}
-
-void
-format_result::append_alias (const directive &d, HOST_WIDE_INT off,
- const result_range &resrng)
-{
- unsigned cnt = alias_count + 1;
- alias_info *ar = XNEWVEC (alias_info, cnt);
-
- for (unsigned i = 0; i != alias_count; ++i)
- ar[i] = aliases[i];
-
- ar[alias_count].dir = d;
- ar[alias_count].offset = off;
- ar[alias_count].range = resrng;
-
- XDELETEVEC (aliases);
-
- alias_count = cnt;
- aliases = ar;
-}
-
-/* Return the logarithm of X in BASE. */
-
-static int
-ilog (unsigned HOST_WIDE_INT x, int base)
-{
- int res = 0;
- do
- {
- ++res;
- x /= base;
- } while (x);
- return res;
-}
-
-/* Return the number of bytes resulting from converting into a string
- the INTEGER_CST tree node X in BASE with a minimum of PREC digits.
- PLUS indicates whether 1 for a plus sign should be added for positive
- numbers, and PREFIX whether the length of an octal ('O') or hexadecimal
- ('0x') prefix should be added for nonzero numbers. Return -1 if X cannot
- be represented. */
-
-static HOST_WIDE_INT
-tree_digits (tree x, int base, HOST_WIDE_INT prec, bool plus, bool prefix)
-{
- unsigned HOST_WIDE_INT absval;
-
- HOST_WIDE_INT res;
-
- if (TYPE_UNSIGNED (TREE_TYPE (x)))
- {
- if (tree_fits_uhwi_p (x))
- {
- absval = tree_to_uhwi (x);
- res = plus;
- }
- else
- return -1;
- }
- else
- {
- if (tree_fits_shwi_p (x))
- {
- HOST_WIDE_INT i = tree_to_shwi (x);
- if (HOST_WIDE_INT_MIN == i)
- {
- /* Avoid undefined behavior due to negating a minimum. */
- absval = HOST_WIDE_INT_MAX;
- res = 1;
- }
- else if (i < 0)
- {
- absval = -i;
- res = 1;
- }
- else
- {
- absval = i;
- res = plus;
- }
- }
- else
- return -1;
- }
-
- int ndigs = ilog (absval, base);
-
- res += prec < ndigs ? ndigs : prec;
-
- /* Adjust a non-zero value for the base prefix, either hexadecimal,
- or, unless precision has resulted in a leading zero, also octal. */
- if (prefix && absval && (base == 16 || prec <= ndigs))
- {
- if (base == 8)
- res += 1;
- else if (base == 16)
- res += 2;
- }
-
- return res;
-}
-
-/* Description of a call to a formatted function. */
-
-struct call_info
-{
- /* Function call statement. */
- gimple *callstmt;
-
- /* Function called. */
- tree func;
-
- /* Called built-in function code. */
- built_in_function fncode;
-
- /* The "origin" of the destination pointer argument, which is either
- the DECL of the destination buffer being written into or a pointer
- that points to it, plus some offset. */
- tree dst_origin;
-
- /* For a destination pointing to a struct array member, the offset of
- the member. */
- HOST_WIDE_INT dst_field;
-
- /* The offset into the destination buffer. */
- HOST_WIDE_INT dst_offset;
-
- /* Format argument and format string extracted from it. */
- tree format;
- const char *fmtstr;
-
- /* The location of the format argument. */
- location_t fmtloc;
-
- /* The destination object size for __builtin___xxx_chk functions
- typically determined by __builtin_object_size, or -1 if unknown. */
- unsigned HOST_WIDE_INT objsize;
-
- /* Number of the first variable argument. */
- unsigned HOST_WIDE_INT argidx;
-
- /* True for functions like snprintf that specify the size of
- the destination, false for others like sprintf that don't. */
- bool bounded;
-
- /* True for bounded functions like snprintf that specify a zero-size
- buffer as a request to compute the size of output without actually
- writing any. NOWRITE is cleared in response to the %n directive
- which has side-effects similar to writing output. */
- bool nowrite;
-
- /* Return true if the called function's return value is used. */
- bool retval_used () const
- {
- return gimple_get_lhs (callstmt);
- }
-
- /* Return the warning option corresponding to the called function. */
- opt_code warnopt () const
- {
- return bounded ? OPT_Wformat_truncation_ : OPT_Wformat_overflow_;
- }
-
- /* Return true for calls to file formatted functions. */
- bool is_file_func () const
- {
- return (fncode == BUILT_IN_FPRINTF
- || fncode == BUILT_IN_FPRINTF_CHK
- || fncode == BUILT_IN_FPRINTF_UNLOCKED
- || fncode == BUILT_IN_VFPRINTF
- || fncode == BUILT_IN_VFPRINTF_CHK);
- }
-
- /* Return true for calls to string formatted functions. */
- bool is_string_func () const
- {
- return (fncode == BUILT_IN_SPRINTF
- || fncode == BUILT_IN_SPRINTF_CHK
- || fncode == BUILT_IN_SNPRINTF
- || fncode == BUILT_IN_SNPRINTF_CHK
- || fncode == BUILT_IN_VSPRINTF
- || fncode == BUILT_IN_VSPRINTF_CHK
- || fncode == BUILT_IN_VSNPRINTF
- || fncode == BUILT_IN_VSNPRINTF_CHK);
- }
-};
-
-void
-directive::set_width (tree arg, range_query *query)
-{
- get_int_range (arg, info->callstmt, width, width + 1, true, 0, query);
-}
-
-void
-directive::set_precision (tree arg, range_query *query)
-{
- get_int_range (arg, info->callstmt, prec, prec + 1, false, -1, query);
-}
-
-/* Return the result of formatting a no-op directive (such as '%n'). */
-
-static fmtresult
-format_none (const directive &, tree, range_query *)
-{
- fmtresult res (0);
- return res;
-}
-
-/* Return the result of formatting the '%%' directive. */
-
-static fmtresult
-format_percent (const directive &, tree, range_query *)
-{
- fmtresult res (1);
- return res;
-}
-
-
-/* Compute intmax_type_node and uintmax_type_node similarly to how
- tree.c builds size_type_node. */
-
-static void
-build_intmax_type_nodes (tree *pintmax, tree *puintmax)
-{
- if (strcmp (UINTMAX_TYPE, "unsigned int") == 0)
- {
- *pintmax = integer_type_node;
- *puintmax = unsigned_type_node;
- }
- else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0)
- {
- *pintmax = long_integer_type_node;
- *puintmax = long_unsigned_type_node;
- }
- else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0)
- {
- *pintmax = long_long_integer_type_node;
- *puintmax = long_long_unsigned_type_node;
- }
- else
- {
- for (int i = 0; i < NUM_INT_N_ENTS; i++)
- if (int_n_enabled_p[i])
- {
- char name[50], altname[50];
- sprintf (name, "__int%d unsigned", int_n_data[i].bitsize);
- sprintf (altname, "__int%d__ unsigned", int_n_data[i].bitsize);
-
- if (strcmp (name, UINTMAX_TYPE) == 0
- || strcmp (altname, UINTMAX_TYPE) == 0)
- {
- *pintmax = int_n_trees[i].signed_type;
- *puintmax = int_n_trees[i].unsigned_type;
- return;
- }
- }
- gcc_unreachable ();
- }
-}
-
-/* Determine the range [*PMIN, *PMAX] that the expression ARG is
- in and that is representable in type int.
- Return true when the range is a subrange of that of int.
- When ARG is null it is as if it had the full range of int.
- When ABSOLUTE is true the range reflects the absolute value of
- the argument. When ABSOLUTE is false, negative bounds of
- the determined range are replaced with NEGBOUND. */
-
-static bool
-get_int_range (tree arg, gimple *stmt,
- HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
- bool absolute, HOST_WIDE_INT negbound,
- range_query *query)
-{
- /* The type of the result. */
- const_tree type = integer_type_node;
-
- bool knownrange = false;
-
- if (!arg)
- {
- *pmin = tree_to_shwi (TYPE_MIN_VALUE (type));
- *pmax = tree_to_shwi (TYPE_MAX_VALUE (type));
- }
- else if (TREE_CODE (arg) == INTEGER_CST
- && TYPE_PRECISION (TREE_TYPE (arg)) <= TYPE_PRECISION (type))
- {
- /* For a constant argument return its value adjusted as specified
- by NEGATIVE and NEGBOUND and return true to indicate that the
- result is known. */
- *pmin = tree_fits_shwi_p (arg) ? tree_to_shwi (arg) : tree_to_uhwi (arg);
- *pmax = *pmin;
- knownrange = true;
- }
- else
- {
- /* True if the argument's range cannot be determined. */
- bool unknown = true;
-
- tree argtype = TREE_TYPE (arg);
-
- /* Ignore invalid arguments with greater precision that that
- of the expected type (e.g., in sprintf("%*i", 12LL, i)).
- They will have been detected and diagnosed by -Wformat and
- so it's not important to complicate this code to try to deal
- with them again. */
- if (TREE_CODE (arg) == SSA_NAME
- && INTEGRAL_TYPE_P (argtype)
- && TYPE_PRECISION (argtype) <= TYPE_PRECISION (type))
- {
- /* Try to determine the range of values of the integer argument. */
- value_range vr;
- query->range_of_expr (vr, arg, stmt);
-
- if (!vr.undefined_p () && !vr.varying_p ())
- {
- HOST_WIDE_INT type_min
- = (TYPE_UNSIGNED (argtype)
- ? tree_to_uhwi (TYPE_MIN_VALUE (argtype))
- : tree_to_shwi (TYPE_MIN_VALUE (argtype)));
-
- HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
-
- tree type = TREE_TYPE (arg);
- tree tmin = wide_int_to_tree (type, vr.lower_bound ());
- tree tmax = wide_int_to_tree (type, vr.upper_bound ());
- *pmin = TREE_INT_CST_LOW (tmin);
- *pmax = TREE_INT_CST_LOW (tmax);
-
- if (*pmin < *pmax)
- {
- /* Return true if the adjusted range is a subrange of
- the full range of the argument's type. *PMAX may
- be less than *PMIN when the argument is unsigned
- and its upper bound is in excess of TYPE_MAX. In
- that (invalid) case disregard the range and use that
- of the expected type instead. */
- knownrange = type_min < *pmin || *pmax < type_max;
-
- unknown = false;
- }
- }
- }
-
- /* Handle an argument with an unknown range as if none had been
- provided. */
- if (unknown)
- return get_int_range (NULL_TREE, NULL, pmin, pmax, absolute,
- negbound, query);
- }
-
- /* Adjust each bound as specified by ABSOLUTE and NEGBOUND. */
- if (absolute)
- {
- if (*pmin < 0)
- {
- if (*pmin == *pmax)
- *pmin = *pmax = -*pmin;
- else
- {
- /* Make sure signed overlow is avoided. */
- gcc_assert (*pmin != HOST_WIDE_INT_MIN);
-
- HOST_WIDE_INT tmp = -*pmin;
- *pmin = 0;
- if (*pmax < tmp)
- *pmax = tmp;
- }
- }
- }
- else if (*pmin < negbound)
- *pmin = negbound;
-
- return knownrange;
-}
-
-/* With the range [*ARGMIN, *ARGMAX] of an integer directive's actual
- argument, due to the conversion from either *ARGMIN or *ARGMAX to
- the type of the directive's formal argument it's possible for both
- to result in the same number of bytes or a range of bytes that's
- less than the number of bytes that would result from formatting
- some other value in the range [*ARGMIN, *ARGMAX]. This can be
- determined by checking for the actual argument being in the range
- of the type of the directive. If it isn't it must be assumed to
- take on the full range of the directive's type.
- Return true when the range has been adjusted to the full range
- of DIRTYPE, and false otherwise. */
-
-static bool
-adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax)
-{
- tree argtype = TREE_TYPE (*argmin);
- unsigned argprec = TYPE_PRECISION (argtype);
- unsigned dirprec = TYPE_PRECISION (dirtype);
-
- /* If the actual argument and the directive's argument have the same
- precision and sign there can be no overflow and so there is nothing
- to adjust. */
- if (argprec == dirprec && TYPE_SIGN (argtype) == TYPE_SIGN (dirtype))
- return false;
-
- /* The logic below was inspired/lifted from the CONVERT_EXPR_CODE_P
- branch in the extract_range_from_unary_expr function in tree-vrp.c. */
-
- if (TREE_CODE (*argmin) == INTEGER_CST
- && TREE_CODE (*argmax) == INTEGER_CST
- && (dirprec >= argprec
- || integer_zerop (int_const_binop (RSHIFT_EXPR,
- int_const_binop (MINUS_EXPR,
- *argmax,
- *argmin),
- size_int (dirprec)))))
- {
- *argmin = force_fit_type (dirtype, wi::to_widest (*argmin), 0, false);
- *argmax = force_fit_type (dirtype, wi::to_widest (*argmax), 0, false);
-
- /* If *ARGMIN is still less than *ARGMAX the conversion above
- is safe. Otherwise, it has overflowed and would be unsafe. */
- if (tree_int_cst_le (*argmin, *argmax))
- return false;
- }
-
- *argmin = TYPE_MIN_VALUE (dirtype);
- *argmax = TYPE_MAX_VALUE (dirtype);
- return true;
-}
-
-/* Return a range representing the minimum and maximum number of bytes
- that the format directive DIR will output for any argument given
- the WIDTH and PRECISION (extracted from DIR). This function is
- used when the directive argument or its value isn't known. */
-
-static fmtresult
-format_integer (const directive &dir, tree arg, range_query *query)
-{
- tree intmax_type_node;
- tree uintmax_type_node;
-
- /* Base to format the number in. */
- int base;
-
- /* True when a conversion is preceded by a prefix indicating the base
- of the argument (octal or hexadecimal). */
- bool maybebase = dir.get_flag ('#');
-
- /* True when a signed conversion is preceded by a sign or space. */
- bool maybesign = false;
-
- /* True for signed conversions (i.e., 'd' and 'i'). */
- bool sign = false;
-
- switch (dir.specifier)
- {
- case 'd':
- case 'i':
- /* Space and '+' are only meaningful for signed conversions. */
- maybesign = dir.get_flag (' ') | dir.get_flag ('+');
- sign = true;
- base = 10;
- break;
- case 'u':
- base = 10;
- break;
- case 'o':
- base = 8;
- break;
- case 'X':
- case 'x':
- base = 16;
- break;
- default:
- gcc_unreachable ();
- }
-
- /* The type of the "formal" argument expected by the directive. */
- tree dirtype = NULL_TREE;
-
- /* Determine the expected type of the argument from the length
- modifier. */
- switch (dir.modifier)
- {
- case FMT_LEN_none:
- if (dir.specifier == 'p')
- dirtype = ptr_type_node;
- else
- dirtype = sign ? integer_type_node : unsigned_type_node;
- break;
-
- case FMT_LEN_h:
- dirtype = sign ? short_integer_type_node : short_unsigned_type_node;
- break;
-
- case FMT_LEN_hh:
- dirtype = sign ? signed_char_type_node : unsigned_char_type_node;
- break;
-
- case FMT_LEN_l:
- dirtype = sign ? long_integer_type_node : long_unsigned_type_node;
- break;
-
- case FMT_LEN_L:
- case FMT_LEN_ll:
- dirtype = (sign
- ? long_long_integer_type_node
- : long_long_unsigned_type_node);
- break;
-
- case FMT_LEN_z:
- dirtype = signed_or_unsigned_type_for (!sign, size_type_node);
- break;
-
- case FMT_LEN_t:
- dirtype = signed_or_unsigned_type_for (!sign, ptrdiff_type_node);
- break;
-
- case FMT_LEN_j:
- build_intmax_type_nodes (&intmax_type_node, &uintmax_type_node);
- dirtype = sign ? intmax_type_node : uintmax_type_node;
- break;
-
- default:
- return fmtresult ();
- }
-
- /* The type of the argument to the directive, either deduced from
- the actual non-constant argument if one is known, or from
- the directive itself when none has been provided because it's
- a va_list. */
- tree argtype = NULL_TREE;
-
- if (!arg)
- {
- /* When the argument has not been provided, use the type of
- the directive's argument as an approximation. This will
- result in false positives for directives like %i with
- arguments with smaller precision (such as short or char). */
- argtype = dirtype;
- }
- else if (TREE_CODE (arg) == INTEGER_CST)
- {
- /* When a constant argument has been provided use its value
- rather than type to determine the length of the output. */
- fmtresult res;
-
- if ((dir.prec[0] <= 0 && dir.prec[1] >= 0) && integer_zerop (arg))
- {
- /* As a special case, a precision of zero with a zero argument
- results in zero bytes except in base 8 when the '#' flag is
- specified, and for signed conversions in base 8 and 10 when
- either the space or '+' flag has been specified and it results
- in just one byte (with width having the normal effect). This
- must extend to the case of a specified precision with
- an unknown value because it can be zero. */
- res.range.min = ((base == 8 && dir.get_flag ('#')) || maybesign);
- if (res.range.min == 0 && dir.prec[0] != dir.prec[1])
- {
- res.range.max = 1;
- res.range.likely = 1;
- }
- else
- {
- res.range.max = res.range.min;
- res.range.likely = res.range.min;
- }
- }
- else
- {
- /* Convert the argument to the type of the directive. */
- arg = fold_convert (dirtype, arg);
-
- res.range.min = tree_digits (arg, base, dir.prec[0],
- maybesign, maybebase);
- if (dir.prec[0] == dir.prec[1])
- res.range.max = res.range.min;
- else
- res.range.max = tree_digits (arg, base, dir.prec[1],
- maybesign, maybebase);
- res.range.likely = res.range.min;
- res.knownrange = true;
- }
-
- res.range.unlikely = res.range.max;
-
- /* Bump up the counters if WIDTH is greater than LEN. */
- res.adjust_for_width_or_precision (dir.width, dirtype, base,
- (sign | maybebase) + (base == 16));
- /* Bump up the counters again if PRECision is greater still. */
- res.adjust_for_width_or_precision (dir.prec, dirtype, base,
- (sign | maybebase) + (base == 16));
-
- return res;
- }
- else if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
- || TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE)
- /* Determine the type of the provided non-constant argument. */
- argtype = TREE_TYPE (arg);
- else
- /* Don't bother with invalid arguments since they likely would
- have already been diagnosed, and disable any further checking
- of the format string by returning [-1, -1]. */
- return fmtresult ();
-
- fmtresult res;
-
- /* Using either the range the non-constant argument is in, or its
- type (either "formal" or actual), create a range of values that
- constrain the length of output given the warning level. */
- tree argmin = NULL_TREE;
- tree argmax = NULL_TREE;
-
- if (arg
- && TREE_CODE (arg) == SSA_NAME
- && INTEGRAL_TYPE_P (argtype))
- {
- /* Try to determine the range of values of the integer argument
- (range information is not available for pointers). */
- value_range vr;
- query->range_of_expr (vr, arg, dir.info->callstmt);
-
- if (!vr.varying_p () && !vr.undefined_p ())
- {
- argmin = wide_int_to_tree (TREE_TYPE (arg), vr.lower_bound ());
- argmax = wide_int_to_tree (TREE_TYPE (arg), vr.upper_bound ());
-
- /* Set KNOWNRANGE if the argument is in a known subrange
- of the directive's type and neither width nor precision
- is unknown. (KNOWNRANGE may be reset below). */
- res.knownrange
- = ((!tree_int_cst_equal (TYPE_MIN_VALUE (dirtype), argmin)
- || !tree_int_cst_equal (TYPE_MAX_VALUE (dirtype), argmax))
- && dir.known_width_and_precision ());
-
- res.argmin = argmin;
- res.argmax = argmax;
- }
- else
- {
- /* The argument here may be the result of promoting the actual
- argument to int. Try to determine the type of the actual
- argument before promotion and narrow down its range that
- way. */
- gimple *def = SSA_NAME_DEF_STMT (arg);
- if (is_gimple_assign (def))
- {
- tree_code code = gimple_assign_rhs_code (def);
- if (code == INTEGER_CST)
- {
- arg = gimple_assign_rhs1 (def);
- return format_integer (dir, arg, query);
- }
-
- if (code == NOP_EXPR)
- {
- tree type = TREE_TYPE (gimple_assign_rhs1 (def));
- if (INTEGRAL_TYPE_P (type)
- || TREE_CODE (type) == POINTER_TYPE)
- argtype = type;
- }
- }
- }
- }
-
- if (!argmin)
- {
- if (TREE_CODE (argtype) == POINTER_TYPE)
- {
- argmin = build_int_cst (pointer_sized_int_node, 0);
- argmax = build_all_ones_cst (pointer_sized_int_node);
- }
- else
- {
- argmin = TYPE_MIN_VALUE (argtype);
- argmax = TYPE_MAX_VALUE (argtype);
- }
- }
-
- /* Clear KNOWNRANGE if the range has been adjusted to the maximum
- of the directive. If it has been cleared then since ARGMIN and/or
- ARGMAX have been adjusted also adjust the corresponding ARGMIN and
- ARGMAX in the result to include in diagnostics. */
- if (adjust_range_for_overflow (dirtype, &argmin, &argmax))
- {
- res.knownrange = false;
- res.argmin = argmin;
- res.argmax = argmax;
- }
-
- /* Recursively compute the minimum and maximum from the known range. */
- if (TYPE_UNSIGNED (dirtype) || tree_int_cst_sgn (argmin) >= 0)
- {
- /* For unsigned conversions/directives or signed when
- the minimum is positive, use the minimum and maximum to compute
- the shortest and longest output, respectively. */
- res.range.min = format_integer (dir, argmin, query).range.min;
- res.range.max = format_integer (dir, argmax, query).range.max;
- }
- else if (tree_int_cst_sgn (argmax) < 0)
- {
- /* For signed conversions/directives if maximum is negative,
- use the minimum as the longest output and maximum as the
- shortest output. */
- res.range.min = format_integer (dir, argmax, query).range.min;
- res.range.max = format_integer (dir, argmin, query).range.max;
- }
- else
- {
- /* Otherwise, 0 is inside of the range and minimum negative. Use 0
- as the shortest output and for the longest output compute the
- length of the output of both minimum and maximum and pick the
- longer. */
- unsigned HOST_WIDE_INT max1
- = format_integer (dir, argmin, query).range.max;
- unsigned HOST_WIDE_INT max2
- = format_integer (dir, argmax, query).range.max;
- res.range.min
- = format_integer (dir, integer_zero_node, query).range.min;
- res.range.max = MAX (max1, max2);
- }
-
- /* If the range is known, use the maximum as the likely length. */
- if (res.knownrange)
- res.range.likely = res.range.max;
- else
- {
- /* Otherwise, use the minimum. Except for the case where for %#x or
- %#o the minimum is just for a single value in the range (0) and
- for all other values it is something longer, like 0x1 or 01.
- Use the length for value 1 in that case instead as the likely
- length. */
- res.range.likely = res.range.min;
- if (maybebase
- && base != 10
- && (tree_int_cst_sgn (argmin) < 0 || tree_int_cst_sgn (argmax) > 0))
- {
- if (res.range.min == 1)
- res.range.likely += base == 8 ? 1 : 2;
- else if (res.range.min == 2
- && base == 16
- && (dir.width[0] == 2 || dir.prec[0] == 2))
- ++res.range.likely;
- }
- }
-
- res.range.unlikely = res.range.max;
- res.adjust_for_width_or_precision (dir.width, dirtype, base,
- (sign | maybebase) + (base == 16));
- res.adjust_for_width_or_precision (dir.prec, dirtype, base,
- (sign | maybebase) + (base == 16));
-
- return res;
-}
-
-/* Return the number of bytes that a format directive consisting of FLAGS,
- PRECision, format SPECification, and MPFR rounding specifier RNDSPEC,
- would result for argument X under ideal conditions (i.e., if PREC
- weren't excessive). MPFR 3.1 allocates large amounts of memory for
- values of PREC with large magnitude and can fail (see MPFR bug #21056).
- This function works around those problems. */
-
-static unsigned HOST_WIDE_INT
-get_mpfr_format_length (mpfr_ptr x, const char *flags, HOST_WIDE_INT prec,
- char spec, char rndspec)
-{
- char fmtstr[40];
-
- HOST_WIDE_INT len = strlen (flags);
-
- fmtstr[0] = '%';
- memcpy (fmtstr + 1, flags, len);
- memcpy (fmtstr + 1 + len, ".*R", 3);
- fmtstr[len + 4] = rndspec;
- fmtstr[len + 5] = spec;
- fmtstr[len + 6] = '\0';
-
- spec = TOUPPER (spec);
- if (spec == 'E' || spec == 'F')
- {
- /* For %e, specify the precision explicitly since mpfr_sprintf
- does its own thing just to be different (see MPFR bug 21088). */
- if (prec < 0)
- prec = 6;
- }
- else
- {
- /* Avoid passing negative precisions with larger magnitude to MPFR
- to avoid exposing its bugs. (A negative precision is supposed
- to be ignored.) */
- if (prec < 0)
- prec = -1;
- }
-
- HOST_WIDE_INT p = prec;
-
- if (spec == 'G' && !strchr (flags, '#'))
- {
- /* For G/g without the pound flag, precision gives the maximum number
- of significant digits which is bounded by LDBL_MAX_10_EXP, or, for
- a 128 bit IEEE extended precision, 4932. Using twice as much here
- should be more than sufficient for any real format. */
- if ((IEEE_MAX_10_EXP * 2) < prec)
- prec = IEEE_MAX_10_EXP * 2;
- p = prec;
- }
- else
- {
- /* Cap precision arbitrarily at 1KB and add the difference
- (if any) to the MPFR result. */
- if (prec > 1024)
- p = 1024;
- }
-
- len = mpfr_snprintf (NULL, 0, fmtstr, (int)p, x);
-
- /* Handle the unlikely (impossible?) error by returning more than
- the maximum dictated by the function's return type. */
- if (len < 0)
- return target_dir_max () + 1;
-
- /* Adjust the return value by the difference. */
- if (p < prec)
- len += prec - p;
-
- return len;
-}
-
-/* Return the number of bytes to format using the format specifier
- SPEC and the precision PREC the largest value in the real floating
- TYPE. */
-
-static unsigned HOST_WIDE_INT
-format_floating_max (tree type, char spec, HOST_WIDE_INT prec)
-{
- machine_mode mode = TYPE_MODE (type);
-
- /* IBM Extended mode. */
- if (MODE_COMPOSITE_P (mode))
- mode = DFmode;
-
- /* Get the real type format description for the target. */
- const real_format *rfmt = REAL_MODE_FORMAT (mode);
- REAL_VALUE_TYPE rv;
-
- real_maxval (&rv, 0, mode);
-
- /* Convert the GCC real value representation with the precision
- of the real type to the mpfr_t format with the GCC default
- round-to-nearest mode. */
- mpfr_t x;
- mpfr_init2 (x, rfmt->p);
- mpfr_from_real (x, &rv, MPFR_RNDN);
-
- /* Return a value one greater to account for the leading minus sign. */
- unsigned HOST_WIDE_INT r
- = 1 + get_mpfr_format_length (x, "", prec, spec, 'D');
- mpfr_clear (x);
- return r;
-}
-
-/* Return a range representing the minimum and maximum number of bytes
- that the directive DIR will output for any argument. PREC gives
- the adjusted precision range to account for negative precisions
- meaning the default 6. This function is used when the directive
- argument or its value isn't known. */
-
-static fmtresult
-format_floating (const directive &dir, const HOST_WIDE_INT prec[2])
-{
- tree type;
-
- switch (dir.modifier)
- {
- case FMT_LEN_l:
- case FMT_LEN_none:
- type = double_type_node;
- break;
-
- case FMT_LEN_L:
- type = long_double_type_node;
- break;
-
- case FMT_LEN_ll:
- type = long_double_type_node;
- break;
-
- default:
- return fmtresult ();
- }
-
- /* The minimum and maximum number of bytes produced by the directive. */
- fmtresult res;
-
- /* The minimum output as determined by flags. It's always at least 1.
- When plus or space are set the output is preceded by either a sign
- or a space. */
- unsigned flagmin = (1 /* for the first digit */
- + (dir.get_flag ('+') | dir.get_flag (' ')));
-
- /* The minimum is 3 for "inf" and "nan" for all specifiers, plus 1
- for the plus sign/space with the '+' and ' ' flags, respectively,
- unless reduced below. */
- res.range.min = 2 + flagmin;
-
- /* When the pound flag is set the decimal point is included in output
- regardless of precision. Whether or not a decimal point is included
- otherwise depends on the specification and precision. */
- bool radix = dir.get_flag ('#');
-
- switch (dir.specifier)
- {
- case 'A':
- case 'a':
- {
- HOST_WIDE_INT minprec = 6 + !radix /* decimal point */;
- if (dir.prec[0] <= 0)
- minprec = 0;
- else if (dir.prec[0] > 0)
- minprec = dir.prec[0] + !radix /* decimal point */;
-
- res.range.likely = (2 /* 0x */
- + flagmin
- + radix
- + minprec
- + 3 /* p+0 */);
-
- res.range.max = format_floating_max (type, 'a', prec[1]);
-
- /* The unlikely maximum accounts for the longest multibyte
- decimal point character. */
- res.range.unlikely = res.range.max;
- if (dir.prec[1] > 0)
- res.range.unlikely += target_mb_len_max () - 1;
-
- break;
- }
-
- case 'E':
- case 'e':
- {
- /* Minimum output attributable to precision and, when it's
- non-zero, decimal point. */
- HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
-
- /* The likely minimum output is "[-+]1.234567e+00" regardless
- of the value of the actual argument. */
- res.range.likely = (flagmin
- + radix
- + minprec
- + 2 /* e+ */ + 2);
-
- res.range.max = format_floating_max (type, 'e', prec[1]);
-
- /* The unlikely maximum accounts for the longest multibyte
- decimal point character. */
- if (dir.prec[0] != dir.prec[1]
- || dir.prec[0] == -1 || dir.prec[0] > 0)
- res.range.unlikely = res.range.max + target_mb_len_max () -1;
- else
- res.range.unlikely = res.range.max;
- break;
- }
-
- case 'F':
- case 'f':
- {
- /* Minimum output attributable to precision and, when it's non-zero,
- decimal point. */
- HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0;
-
- /* For finite numbers (i.e., not infinity or NaN) the lower bound
- when precision isn't specified is 8 bytes ("1.23456" since
- precision is taken to be 6). When precision is zero, the lower
- bound is 1 byte (e.g., "1"). Otherwise, when precision is greater
- than zero, then the lower bound is 2 plus precision (plus flags).
- But in all cases, the lower bound is no greater than 3. */
- unsigned HOST_WIDE_INT min = flagmin + radix + minprec;
- if (min < res.range.min)
- res.range.min = min;
-
- /* Compute the upper bound for -TYPE_MAX. */
- res.range.max = format_floating_max (type, 'f', prec[1]);
-
- /* The minimum output with unknown precision is a single byte
- (e.g., "0") but the more likely output is 3 bytes ("0.0"). */
- if (dir.prec[0] < 0 && dir.prec[1] > 0)
- res.range.likely = 3;
- else
- res.range.likely = min;
-
- /* The unlikely maximum accounts for the longest multibyte
- decimal point character. */
- if (dir.prec[0] != dir.prec[1]
- || dir.prec[0] == -1 || dir.prec[0] > 0)
- res.range.unlikely = res.range.max + target_mb_len_max () - 1;
- break;
- }
-
- case 'G':
- case 'g':
- {
- /* The %g output depends on precision and the exponent of
- the argument. Since the value of the argument isn't known
- the lower bound on the range of bytes (not counting flags
- or width) is 1 plus radix (i.e., either "0" or "0." for
- "%g" and "%#g", respectively, with a zero argument). */
- unsigned HOST_WIDE_INT min = flagmin + radix;
- if (min < res.range.min)
- res.range.min = min;
-
- char spec = 'g';
- HOST_WIDE_INT maxprec = dir.prec[1];
- if (radix && maxprec)
- {
- /* When the pound flag (radix) is set, trailing zeros aren't
- trimmed and so the longest output is the same as for %e,
- except with precision minus 1 (as specified in C11). */
- spec = 'e';
- if (maxprec > 0)
- --maxprec;
- else if (maxprec < 0)
- maxprec = 5;
- }
- else
- maxprec = prec[1];
-
- res.range.max = format_floating_max (type, spec, maxprec);
-
- /* The likely output is either the maximum computed above
- minus 1 (assuming the maximum is positive) when precision
- is known (or unspecified), or the same minimum as for %e
- (which is computed for a non-negative argument). Unlike
- for the other specifiers above the likely output isn't
- the minimum because for %g that's 1 which is unlikely. */
- if (dir.prec[1] < 0
- || (unsigned HOST_WIDE_INT)dir.prec[1] < target_int_max ())
- res.range.likely = res.range.max - 1;
- else
- {
- HOST_WIDE_INT minprec = 6 + !radix /* decimal point */;
- res.range.likely = (flagmin
- + radix
- + minprec
- + 2 /* e+ */ + 2);
- }
-
- /* The unlikely maximum accounts for the longest multibyte
- decimal point character. */
- res.range.unlikely = res.range.max + target_mb_len_max () - 1;
- break;
- }
-
- default:
- return fmtresult ();
- }
-
- /* Bump up the byte counters if WIDTH is greater. */
- res.adjust_for_width_or_precision (dir.width);
- return res;
-}
-
-/* Return a range representing the minimum and maximum number of bytes
- that the directive DIR will write on output for the floating argument
- ARG. */
-
-static fmtresult
-format_floating (const directive &dir, tree arg, range_query *)
-{
- HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
- tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll
- ? long_double_type_node : double_type_node);
-
- /* For an indeterminate precision the lower bound must be assumed
- to be zero. */
- if (TOUPPER (dir.specifier) == 'A')
- {
- /* Get the number of fractional decimal digits needed to represent
- the argument without a loss of accuracy. */
- unsigned fmtprec
- = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
-
- /* The precision of the IEEE 754 double format is 53.
- The precision of all other GCC binary double formats
- is 56 or less. */
- unsigned maxprec = fmtprec <= 56 ? 13 : 15;
-
- /* For %a, leave the minimum precision unspecified to let
- MFPR trim trailing zeros (as it and many other systems
- including Glibc happen to do) and set the maximum
- precision to reflect what it would be with trailing zeros
- present (as Solaris and derived systems do). */
- if (dir.prec[1] < 0)
- {
- /* Both bounds are negative implies that precision has
- not been specified. */
- prec[0] = maxprec;
- prec[1] = -1;
- }
- else if (dir.prec[0] < 0)
- {
- /* With a negative lower bound and a non-negative upper
- bound set the minimum precision to zero and the maximum
- to the greater of the maximum precision (i.e., with
- trailing zeros present) and the specified upper bound. */
- prec[0] = 0;
- prec[1] = dir.prec[1] < maxprec ? maxprec : dir.prec[1];
- }
- }
- else if (dir.prec[0] < 0)
- {
- if (dir.prec[1] < 0)
- {
- /* A precision in a strictly negative range is ignored and
- the default of 6 is used instead. */
- prec[0] = prec[1] = 6;
- }
- else
- {
- /* For a precision in a partly negative range, the lower bound
- must be assumed to be zero and the new upper bound is the
- greater of 6 (the default precision used when the specified
- precision is negative) and the upper bound of the specified
- range. */
- prec[0] = 0;
- prec[1] = dir.prec[1] < 6 ? 6 : dir.prec[1];
- }
- }
-
- if (!arg
- || TREE_CODE (arg) != REAL_CST
- || !useless_type_conversion_p (type, TREE_TYPE (arg)))
- return format_floating (dir, prec);
-
- /* The minimum and maximum number of bytes produced by the directive. */
- fmtresult res;
-
- /* Get the real type format description for the target. */
- const REAL_VALUE_TYPE *rvp = TREE_REAL_CST_PTR (arg);
- const real_format *rfmt = REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)));
-
- if (!real_isfinite (rvp))
- {
- /* The format for Infinity and NaN is "[-]inf"/"[-]infinity"
- and "[-]nan" with the choice being implementation-defined
- but not locale dependent. */
- bool sign = dir.get_flag ('+') || real_isneg (rvp);
- res.range.min = 3 + sign;
-
- res.range.likely = res.range.min;
- res.range.max = res.range.min;
- /* The unlikely maximum is "[-/+]infinity" or "[-/+][qs]nan".
- For NaN, the C/POSIX standards specify two formats:
- "[-/+]nan"
- and
- "[-/+]nan(n-char-sequence)"
- No known printf implementation outputs the latter format but AIX
- outputs QNaN and SNaN for quiet and signalling NaN, respectively,
- so the unlikely maximum reflects that. */
- res.range.unlikely = sign + (real_isinf (rvp) ? 8 : 4);
-
- /* The range for infinity and NaN is known unless either width
- or precision is unknown. Width has the same effect regardless
- of whether the argument is finite. Precision is either ignored
- (e.g., Glibc) or can have an effect on the short vs long format
- such as inf/infinity (e.g., Solaris). */
- res.knownrange = dir.known_width_and_precision ();
-
- /* Adjust the range for width but ignore precision. */
- res.adjust_for_width_or_precision (dir.width);
-
- return res;
- }
-
- char fmtstr [40];
- char *pfmt = fmtstr;
-
- /* Append flags. */
- for (const char *pf = "-+ #0"; *pf; ++pf)
- if (dir.get_flag (*pf))
- *pfmt++ = *pf;
-
- *pfmt = '\0';
-
- {
- /* Set up an array to easily iterate over. */
- unsigned HOST_WIDE_INT* const minmax[] = {
- &res.range.min, &res.range.max
- };
-
- for (int i = 0; i != sizeof minmax / sizeof *minmax; ++i)
- {
- /* Convert the GCC real value representation with the precision
- of the real type to the mpfr_t format rounding down in the
- first iteration that computes the minimum and up in the second
- that computes the maximum. This order is arbitrary because
- rounding in either direction can result in longer output. */
- mpfr_t mpfrval;
- mpfr_init2 (mpfrval, rfmt->p);
- mpfr_from_real (mpfrval, rvp, i ? MPFR_RNDU : MPFR_RNDD);
-
- /* Use the MPFR rounding specifier to round down in the first
- iteration and then up. In most but not all cases this will
- result in the same number of bytes. */
- char rndspec = "DU"[i];
-
- /* Format it and store the result in the corresponding member
- of the result struct. */
- *minmax[i] = get_mpfr_format_length (mpfrval, fmtstr, prec[i],
- dir.specifier, rndspec);
- mpfr_clear (mpfrval);
- }
- }
-
- /* Make sure the minimum is less than the maximum (MPFR rounding
- in the call to mpfr_snprintf can result in the reverse. */
- if (res.range.max < res.range.min)
- {
- unsigned HOST_WIDE_INT tmp = res.range.min;
- res.range.min = res.range.max;
- res.range.max = tmp;
- }
-
- /* The range is known unless either width or precision is unknown. */
- res.knownrange = dir.known_width_and_precision ();
-
- /* For the same floating point constant, unless width or precision
- is unknown, use the longer output as the likely maximum since
- with round to nearest either is equally likely. Otherwise, when
- precision is unknown, use the greater of the minimum and 3 as
- the likely output (for "0.0" since zero precision is unlikely). */
- if (res.knownrange)
- res.range.likely = res.range.max;
- else if (res.range.min < 3
- && dir.prec[0] < 0
- && (unsigned HOST_WIDE_INT)dir.prec[1] == target_int_max ())
- res.range.likely = 3;
- else
- res.range.likely = res.range.min;
-
- res.range.unlikely = res.range.max;
-
- if (res.range.max > 2 && (prec[0] != 0 || prec[1] != 0))
- {
- /* Unless the precision is zero output longer than 2 bytes may
- include the decimal point which must be a single character
- up to MB_LEN_MAX in length. This is overly conservative
- since in some conversions some constants result in no decimal
- point (e.g., in %g). */
- res.range.unlikely += target_mb_len_max () - 1;
- }
-
- res.adjust_for_width_or_precision (dir.width);
- return res;
-}
-
-/* Return a FMTRESULT struct set to the lengths of the shortest and longest
- strings referenced by the expression STR, or (-1, -1) when not known.
- Used by the format_string function below. */
-
-static fmtresult
-get_string_length (tree str, gimple *stmt, unsigned HOST_WIDE_INT max_size,
- unsigned eltsize, range_query *query)
-{
- if (!str)
- return fmtresult ();
-
- /* Try to determine the dynamic string length first.
- Set MAXBOUND to an arbitrary non-null non-integer node as a request
- to have it set to the length of the longest string in a PHI. */
- c_strlen_data lendata = { };
- lendata.maxbound = str;
- if (eltsize == 1)
- get_range_strlen_dynamic (str, stmt, &lendata, query);
- else
- {
- /* Determine the length of the shortest and longest string referenced
- by STR. Strings of unknown lengths are bounded by the sizes of
- arrays that subexpressions of STR may refer to. Pointers that
- aren't known to point any such arrays result in LENDATA.MAXLEN
- set to SIZE_MAX. */
- get_range_strlen (str, &lendata, eltsize);
- }
-
- /* If LENDATA.MAXBOUND is not equal to .MINLEN it corresponds to the bound
- of the largest array STR refers to, if known, or it's set to SIZE_MAX
- otherwise. */
-
- /* Return the default result when nothing is known about the string. */
- if ((lendata.maxbound && !tree_fits_uhwi_p (lendata.maxbound))
- || !tree_fits_uhwi_p (lendata.maxlen))
- {
- fmtresult res;
- res.nonstr = lendata.decl;
- return res;
- }
-
- unsigned HOST_WIDE_INT lenmax = tree_to_uhwi (max_object_size ()) - 2;
- if (integer_zerop (lendata.minlen)
- && (!lendata.maxbound || lenmax <= tree_to_uhwi (lendata.maxbound))
- && lenmax <= tree_to_uhwi (lendata.maxlen))
- {
- if (max_size > 0 && max_size < HOST_WIDE_INT_MAX)
- {
- /* Adjust the conservative unknown/unbounded result if MAX_SIZE
- is valid. Set UNLIKELY to maximum in case MAX_SIZE refers
- to a subobject.
- TODO: This is overly conservative. Set UNLIKELY to the size
- of the outermost enclosing declared object. */
- fmtresult res (0, max_size - 1);
- res.nonstr = lendata.decl;
- res.range.likely = res.range.max;
- res.range.unlikely = HOST_WIDE_INT_MAX;
- return res;
- }
-
- fmtresult res;
- res.nonstr = lendata.decl;
- return res;
- }
-
- HOST_WIDE_INT min
- = (tree_fits_uhwi_p (lendata.minlen)
- ? tree_to_uhwi (lendata.minlen)
- : 0);
-
- HOST_WIDE_INT max
- = (lendata.maxbound && tree_fits_uhwi_p (lendata.maxbound)
- ? tree_to_uhwi (lendata.maxbound)
- : HOST_WIDE_INT_M1U);
-
- const bool unbounded = integer_all_onesp (lendata.maxlen);
-
- /* Set the max/likely counters to unbounded when a minimum is known
- but the maximum length isn't bounded. This implies that STR is
- a conditional expression involving a string of known length and
- an expression of unknown/unbounded length. */
- if (min
- && (unsigned HOST_WIDE_INT)min < HOST_WIDE_INT_M1U
- && unbounded)
- max = HOST_WIDE_INT_M1U;
-
- /* get_range_strlen() returns the target value of SIZE_MAX for
- strings of unknown length. Bump it up to HOST_WIDE_INT_M1U
- which may be bigger. */
- if ((unsigned HOST_WIDE_INT)min == target_size_max ())
- min = HOST_WIDE_INT_M1U;
- if ((unsigned HOST_WIDE_INT)max == target_size_max ())
- max = HOST_WIDE_INT_M1U;
-
- fmtresult res (min, max);
- res.nonstr = lendata.decl;
-
- /* Set RES.KNOWNRANGE to true if and only if all strings referenced
- by STR are known to be bounded (though not necessarily by their
- actual length but perhaps by their maximum possible length). */
- if (res.range.max < target_int_max ())
- {
- res.knownrange = true;
- /* When the length of the longest string is known and not
- excessive use it as the likely length of the string(s). */
- res.range.likely = res.range.max;
- }
- else
- {
- /* When the upper bound is unknown (it can be zero or excessive)
- set the likely length to the greater of 1. If MAXBOUND is
- known, also reset the length of the lower bound to zero. */
- res.range.likely = res.range.min ? res.range.min : warn_level > 1;
- if (lendata.maxbound && !integer_all_onesp (lendata.maxbound))
- res.range.min = 0;
- }
-
- res.range.unlikely = unbounded ? HOST_WIDE_INT_MAX : res.range.max;
-
- return res;
-}
-
-/* Return the minimum and maximum number of characters formatted
- by the '%c' format directives and its wide character form for
- the argument ARG. ARG can be null (for functions such as
- vsprinf). */
-
-static fmtresult
-format_character (const directive &dir, tree arg, range_query *query)
-{
- fmtresult res;
-
- res.knownrange = true;
-
- if (dir.specifier == 'C'
- || dir.modifier == FMT_LEN_l)
- {
- /* A wide character can result in as few as zero bytes. */
- res.range.min = 0;
-
- HOST_WIDE_INT min, max;
- if (get_int_range (arg, dir.info->callstmt, &min, &max, false, 0, query))
- {
- if (min == 0 && max == 0)
- {
- /* The NUL wide character results in no bytes. */
- res.range.max = 0;
- res.range.likely = 0;
- res.range.unlikely = 0;
- }
- else if (min >= 0 && min < 128)
- {
- /* Be conservative if the target execution character set
- is not a 1-to-1 mapping to the source character set or
- if the source set is not ASCII. */
- bool one_2_one_ascii
- = (target_to_host_charmap[0] == 1 && target_to_host ('a') == 97);
-
- /* A wide character in the ASCII range most likely results
- in a single byte, and only unlikely in up to MB_LEN_MAX. */
- res.range.max = one_2_one_ascii ? 1 : target_mb_len_max ();;
- res.range.likely = 1;
- res.range.unlikely = target_mb_len_max ();
- res.mayfail = !one_2_one_ascii;
- }
- else
- {
- /* A wide character outside the ASCII range likely results
- in up to two bytes, and only unlikely in up to MB_LEN_MAX. */
- res.range.max = target_mb_len_max ();
- res.range.likely = 2;
- res.range.unlikely = res.range.max;
- /* Converting such a character may fail. */
- res.mayfail = true;
- }
- }
- else
- {
- /* An unknown wide character is treated the same as a wide
- character outside the ASCII range. */
- res.range.max = target_mb_len_max ();
- res.range.likely = 2;
- res.range.unlikely = res.range.max;
- res.mayfail = true;
- }
- }
- else
- {
- /* A plain '%c' directive. Its output is exactly 1. */
- res.range.min = res.range.max = 1;
- res.range.likely = res.range.unlikely = 1;
- res.knownrange = true;
- }
-
- /* Bump up the byte counters if WIDTH is greater. */
- return res.adjust_for_width_or_precision (dir.width);
-}
-
-/* If TYPE is an array or struct or union, increment *FLDOFF by the starting
- offset of the member that *OFF point into and set *FLDSIZE to its size
- in bytes and decrement *OFF by the same. Otherwise do nothing. */
-
-static void
-set_aggregate_size_and_offset (tree type, HOST_WIDE_INT *fldoff,
- HOST_WIDE_INT *fldsize, HOST_WIDE_INT *off)
-{
- /* The byte offset of the most basic struct member the byte
- offset *OFF corresponds to, or for a (multidimensional)
- array member, the byte offset of the array element. */
- if (TREE_CODE (type) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
- {
- HOST_WIDE_INT index = 0, arrsize = 0;
- if (array_elt_at_offset (type, *off, &index, &arrsize))
- {
- *fldoff += index;
- *off -= index;
- *fldsize = arrsize;
- }
- }
- else if (RECORD_OR_UNION_TYPE_P (type))
- {
- HOST_WIDE_INT index = 0;
- tree sub = field_at_offset (type, NULL_TREE, *off, &index);
- if (sub)
- {
- tree subsize = DECL_SIZE_UNIT (sub);
- if (*fldsize < HOST_WIDE_INT_MAX
- && subsize
- && tree_fits_uhwi_p (subsize))
- *fldsize = tree_to_uhwi (subsize);
- else
- *fldsize = HOST_WIDE_INT_MAX;
- *fldoff += index;
- *off -= index;
- }
- }
-}
-
-/* For an expression X of pointer type, recursively try to find the same
- origin (object or pointer) as Y it references and return such a Y.
- When X refers to an array element or struct member, set *FLDOFF to
- the offset of the element or member from the beginning of the "most
- derived" object and *FLDSIZE to its size. When nonnull, set *OFF to
- the overall offset from the beginning of the object so that
- *FLDOFF <= *OFF. */
-
-static tree
-get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize,
- HOST_WIDE_INT *off)
-{
- if (!x)
- return NULL_TREE;
-
- HOST_WIDE_INT sizebuf = -1;
- if (!fldsize)
- fldsize = &sizebuf;
-
- if (DECL_P (x))
- {
- /* Set the size if it hasn't been set yet. */
- if (tree size = DECL_SIZE_UNIT (x))
- if (*fldsize < 0 && tree_fits_shwi_p (size))
- *fldsize = tree_to_shwi (size);
- return x;
- }
-
- switch (TREE_CODE (x))
- {
- case ADDR_EXPR:
- x = TREE_OPERAND (x, 0);
- return get_origin_and_offset_r (x, fldoff, fldsize, off);
-
- case ARRAY_REF:
- {
- tree offset = TREE_OPERAND (x, 1);
- HOST_WIDE_INT idx = (tree_fits_uhwi_p (offset)
- ? tree_to_uhwi (offset) : HOST_WIDE_INT_MAX);
-
- tree eltype = TREE_TYPE (x);
- if (TREE_CODE (eltype) == INTEGER_TYPE)
- {
- if (off)
- *off = idx;
- }
- else if (idx < HOST_WIDE_INT_MAX)
- *fldoff += idx * int_size_in_bytes (eltype);
- else
- *fldoff = idx;
-
- x = TREE_OPERAND (x, 0);
- return get_origin_and_offset_r (x, fldoff, fldsize, nullptr);
- }
-
- case MEM_REF:
- if (off)
- {
- tree offset = TREE_OPERAND (x, 1);
- *off = (tree_fits_uhwi_p (offset)
- ? tree_to_uhwi (offset) : HOST_WIDE_INT_MAX);
- }
-
- x = TREE_OPERAND (x, 0);
-
- if (off)
- {
- tree xtype
- = (TREE_CODE (x) == ADDR_EXPR
- ? TREE_TYPE (TREE_OPERAND (x, 0)) : TREE_TYPE (TREE_TYPE (x)));
-
- set_aggregate_size_and_offset (xtype, fldoff, fldsize, off);
- }
-
- return get_origin_and_offset_r (x, fldoff, fldsize, nullptr);
-
- case COMPONENT_REF:
- {
- tree fld = TREE_OPERAND (x, 1);
- *fldoff += int_byte_position (fld);
-
- get_origin_and_offset_r (fld, fldoff, fldsize, off);
- x = TREE_OPERAND (x, 0);
- return get_origin_and_offset_r (x, fldoff, nullptr, off);
- }
-
- case SSA_NAME:
- {
- gimple *def = SSA_NAME_DEF_STMT (x);
- if (is_gimple_assign (def))
- {
- tree_code code = gimple_assign_rhs_code (def);
- if (code == ADDR_EXPR)
- {
- x = gimple_assign_rhs1 (def);
- return get_origin_and_offset_r (x, fldoff, fldsize, off);
- }
-
- if (code == POINTER_PLUS_EXPR)
- {
- tree offset = gimple_assign_rhs2 (def);
- if (off && tree_fits_uhwi_p (offset))
- *off = tree_to_uhwi (offset);
-
- x = gimple_assign_rhs1 (def);
- x = get_origin_and_offset_r (x, fldoff, fldsize, off);
- if (off && !tree_fits_uhwi_p (offset))
- *off = HOST_WIDE_INT_MAX;
- if (off)
- {
- tree xtype = TREE_TYPE (x);
- set_aggregate_size_and_offset (xtype, fldoff, fldsize, off);
- }
- return x;
- }
- else if (code == VAR_DECL)
- {
- x = gimple_assign_rhs1 (def);
- return get_origin_and_offset_r (x, fldoff, fldsize, off);
- }
- }
- else if (gimple_nop_p (def) && SSA_NAME_VAR (x))
- x = SSA_NAME_VAR (x);
-
- tree xtype = TREE_TYPE (x);
- if (POINTER_TYPE_P (xtype))
- xtype = TREE_TYPE (xtype);
-
- if (off)
- set_aggregate_size_and_offset (xtype, fldoff, fldsize, off);
- }
-
- default:
- break;
- }
-
- return x;
-}
-
-/* Nonrecursive version of the above. */
-
-static tree
-get_origin_and_offset (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *off,
- HOST_WIDE_INT *fldsize = nullptr)
-{
- HOST_WIDE_INT sizebuf;
- if (!fldsize)
- fldsize = &sizebuf;
-
- *fldsize = -1;
-
- *fldoff = *off = *fldsize = 0;
- tree orig = get_origin_and_offset_r (x, fldoff, fldsize, off);
- if (!orig)
- return NULL_TREE;
-
- if (!*fldoff && *off == *fldsize)
- {
- *fldoff = *off;
- *off = 0;
- }
-
- return orig;
-}
-
-/* If ARG refers to the same (sub)object or array element as described
- by DST and DST_FLD, return the byte offset into the struct member or
- array element referenced by ARG and set *ARG_SIZE to the size of
- the (sub)object. Otherwise return HOST_WIDE_INT_MIN to indicate
- that ARG and DST do not refer to the same object. */
-
-static HOST_WIDE_INT
-alias_offset (tree arg, HOST_WIDE_INT *arg_size,
- tree dst, HOST_WIDE_INT dst_fld)
-{
- /* See if the argument refers to the same base object as the destination
- of the formatted function call, and if so, try to determine if they
- can alias. */
- if (!arg || !dst || !ptr_derefs_may_alias_p (arg, dst))
- return HOST_WIDE_INT_MIN;
-
- /* The two arguments may refer to the same object. If they both refer
- to a struct member, see if the members are one and the same. */
- HOST_WIDE_INT arg_off = 0, arg_fld = 0;
-
- tree arg_orig = get_origin_and_offset (arg, &arg_fld, &arg_off, arg_size);
-
- if (arg_orig == dst && arg_fld == dst_fld)
- return arg_off;
-
- return HOST_WIDE_INT_MIN;
-}
-
-/* Return the minimum and maximum number of characters formatted
- by the '%s' format directive and its wide character form for
- the argument ARG. ARG can be null (for functions such as
- vsprinf). */
-
-static fmtresult
-format_string (const directive &dir, tree arg, range_query *query)
-{
- fmtresult res;
-
- /* The size of the (sub)object ARG refers to. Used to adjust
- the conservative get_string_length() result. */
- HOST_WIDE_INT arg_size = 0;
-
- if (warn_restrict)
- {
- /* See if ARG might alias the destination of the call with
- DST_ORIGIN and DST_FIELD. If so, store the starting offset
- so that the overlap can be determined for certain later,
- when the amount of output of the call (including subsequent
- directives) has been computed. Otherwise, store HWI_MIN. */
- res.dst_offset = alias_offset (arg, &arg_size, dir.info->dst_origin,
- dir.info->dst_field);
- if (res.dst_offset >= 0 && res.dst_offset <= arg_size)
- arg_size -= res.dst_offset;
- else
- arg_size = 0;
- }
-
- /* Compute the range the argument's length can be in. */
- int count_by = 1;
- if (dir.specifier == 'S' || dir.modifier == FMT_LEN_l)
- {
- /* Get a node for a C type that will be the same size
- as a wchar_t on the target. */
- tree node = get_typenode_from_name (MODIFIED_WCHAR_TYPE);
-
- /* Now that we have a suitable node, get the number of
- bytes it occupies. */
- count_by = int_size_in_bytes (node);
- gcc_checking_assert (count_by == 2 || count_by == 4);
- }
-
- fmtresult slen =
- get_string_length (arg, dir.info->callstmt, arg_size, count_by, query);
- if (slen.range.min == slen.range.max
- && slen.range.min < HOST_WIDE_INT_MAX)
- {
- /* The argument is either a string constant or it refers
- to one of a number of strings of the same length. */
-
- /* A '%s' directive with a string argument with constant length. */
- res.range = slen.range;
-
- if (dir.specifier == 'S'
- || dir.modifier == FMT_LEN_l)
- {
- /* In the worst case the length of output of a wide string S
- is bounded by MB_LEN_MAX * wcslen (S). */
- res.range.max *= target_mb_len_max ();
- res.range.unlikely = res.range.max;
- /* It's likely that the total length is not more that
- 2 * wcslen (S).*/
- res.range.likely = res.range.min * 2;
-
- if (dir.prec[1] >= 0
- && (unsigned HOST_WIDE_INT)dir.prec[1] < res.range.max)
- {
- res.range.max = dir.prec[1];
- res.range.likely = dir.prec[1];
- res.range.unlikely = dir.prec[1];
- }
-
- if (dir.prec[0] < 0 && dir.prec[1] > -1)
- res.range.min = 0;
- else if (dir.prec[0] >= 0)
- res.range.likely = dir.prec[0];
-
- /* Even a non-empty wide character string need not convert into
- any bytes. */
- res.range.min = 0;
-
- /* A non-empty wide character conversion may fail. */
- if (slen.range.max > 0)
- res.mayfail = true;
- }
- else
- {
- res.knownrange = true;
-
- if (dir.prec[0] < 0 && dir.prec[1] > -1)
- res.range.min = 0;
- else if ((unsigned HOST_WIDE_INT)dir.prec[0] < res.range.min)
- res.range.min = dir.prec[0];
-
- if ((unsigned HOST_WIDE_INT)dir.prec[1] < res.range.max)
- {
- res.range.max = dir.prec[1];
- res.range.likely = dir.prec[1];
- res.range.unlikely = dir.prec[1];
- }
- }
- }
- else if (arg && integer_zerop (arg))
- {
- /* Handle null pointer argument. */
-
- fmtresult res (0);
- res.nullp = true;
- return res;
- }
- else
- {
- /* For a '%s' and '%ls' directive with a non-constant string (either
- one of a number of strings of known length or an unknown string)
- the minimum number of characters is lesser of PRECISION[0] and
- the length of the shortest known string or zero, and the maximum
- is the lesser of the length of the longest known string or
- PTRDIFF_MAX and PRECISION[1]. The likely length is either
- the minimum at level 1 and the greater of the minimum and 1
- at level 2. This result is adjust upward for width (if it's
- specified). */
-
- if (dir.specifier == 'S'
- || dir.modifier == FMT_LEN_l)
- {
- /* A wide character converts to as few as zero bytes. */
- slen.range.min = 0;
- if (slen.range.max < target_int_max ())
- slen.range.max *= target_mb_len_max ();
-
- if (slen.range.likely < target_int_max ())
- slen.range.likely *= 2;
-
- if (slen.range.likely < target_int_max ())
- slen.range.unlikely *= target_mb_len_max ();
-
- /* A non-empty wide character conversion may fail. */
- if (slen.range.max > 0)
- res.mayfail = true;
- }
-
- res.range = slen.range;
-
- if (dir.prec[0] >= 0)
- {
- /* Adjust the minimum to zero if the string length is unknown,
- or at most the lower bound of the precision otherwise. */
- if (slen.range.min >= target_int_max ())
- res.range.min = 0;
- else if ((unsigned HOST_WIDE_INT)dir.prec[0] < slen.range.min)
- res.range.min = dir.prec[0];
-
- /* Make both maxima no greater than the upper bound of precision. */
- if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.max
- || slen.range.max >= target_int_max ())
- {
- res.range.max = dir.prec[1];
- res.range.unlikely = dir.prec[1];
- }
-
- /* If precision is constant, set the likely counter to the lesser
- of it and the maximum string length. Otherwise, if the lower
- bound of precision is greater than zero, set the likely counter
- to the minimum. Otherwise set it to zero or one based on
- the warning level. */
- if (dir.prec[0] == dir.prec[1])
- res.range.likely
- = ((unsigned HOST_WIDE_INT)dir.prec[0] < slen.range.max
- ? dir.prec[0] : slen.range.max);
- else if (dir.prec[0] > 0)
- res.range.likely = res.range.min;
- else
- res.range.likely = warn_level > 1;
- }
- else if (dir.prec[1] >= 0)
- {
- res.range.min = 0;
- if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.max)
- res.range.max = dir.prec[1];
- res.range.likely = dir.prec[1] ? warn_level > 1 : 0;
- if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.unlikely)
- res.range.unlikely = dir.prec[1];
- }
- else if (slen.range.min >= target_int_max ())
- {
- res.range.min = 0;
- res.range.max = HOST_WIDE_INT_MAX;
- /* At level 1 strings of unknown length are assumed to be
- empty, while at level 1 they are assumed to be one byte
- long. */
- res.range.likely = warn_level > 1;
- res.range.unlikely = HOST_WIDE_INT_MAX;
- }
- else
- {
- /* A string of unknown length unconstrained by precision is
- assumed to be empty at level 1 and just one character long
- at higher levels. */
- if (res.range.likely >= target_int_max ())
- res.range.likely = warn_level > 1;
- }
- }
-
- /* If the argument isn't a nul-terminated string and the number
- of bytes on output isn't bounded by precision, set NONSTR. */
- if (slen.nonstr && slen.range.min < (unsigned HOST_WIDE_INT)dir.prec[0])
- res.nonstr = slen.nonstr;
-
- /* Bump up the byte counters if WIDTH is greater. */
- return res.adjust_for_width_or_precision (dir.width);
-}
-
-/* Format plain string (part of the format string itself). */
-
-static fmtresult
-format_plain (const directive &dir, tree, range_query *)
-{
- fmtresult res (dir.len);
- return res;
-}
-
-/* Return true if the RESULT of a directive in a call describe by INFO
- should be diagnosed given the AVAILable space in the destination. */
-
-static bool
-should_warn_p (const call_info &info,
- const result_range &avail, const result_range &result)
-{
- if (result.max <= avail.min)
- {
- /* The least amount of space remaining in the destination is big
- enough for the longest output. */
- return false;
- }
-
- if (info.bounded)
- {
- if (warn_format_trunc == 1 && result.min <= avail.max
- && info.retval_used ())
- {
- /* The likely amount of space remaining in the destination is big
- enough for the least output and the return value is used. */
- return false;
- }
-
- if (warn_format_trunc == 1 && result.likely <= avail.likely
- && !info.retval_used ())
- {
- /* The likely amount of space remaining in the destination is big
- enough for the likely output and the return value is unused. */
- return false;
- }
-
- if (warn_format_trunc == 2
- && result.likely <= avail.min
- && (result.max <= avail.min
- || result.max > HOST_WIDE_INT_MAX))
- {
- /* The minimum amount of space remaining in the destination is big
- enough for the longest output. */
- return false;
- }
- }
- else
- {
- if (warn_level == 1 && result.likely <= avail.likely)
- {
- /* The likely amount of space remaining in the destination is big
- enough for the likely output. */
- return false;
- }
-
- if (warn_level == 2
- && result.likely <= avail.min
- && (result.max <= avail.min
- || result.max > HOST_WIDE_INT_MAX))
- {
- /* The minimum amount of space remaining in the destination is big
- enough for the longest output. */
- return false;
- }
- }
-
- return true;
-}
-
-/* At format string location describe by DIRLOC in a call described
- by INFO, issue a warning for a directive DIR whose output may be
- in excess of the available space AVAIL_RANGE in the destination
- given the formatting result FMTRES. This function does nothing
- except decide whether to issue a warning for a possible write
- past the end or truncation and, if so, format the warning.
- Return true if a warning has been issued. */
-
-static bool
-maybe_warn (substring_loc &dirloc, location_t argloc,
- const call_info &info,
- const result_range &avail_range, const result_range &res,
- const directive &dir)
-{
- if (!should_warn_p (info, avail_range, res))
- return false;
-
- /* A warning will definitely be issued below. */
-
- /* The maximum byte count to reference in the warning. Larger counts
- imply that the upper bound is unknown (and could be anywhere between
- RES.MIN + 1 and SIZE_MAX / 2) are printed as "N or more bytes" rather
- than "between N and X" where X is some huge number. */
- unsigned HOST_WIDE_INT maxbytes = target_dir_max ();
-
- /* True when there is enough room in the destination for the least
- amount of a directive's output but not enough for its likely or
- maximum output. */
- bool maybe = (res.min <= avail_range.max
- && (avail_range.min < res.likely
- || (res.max < HOST_WIDE_INT_MAX
- && avail_range.min < res.max)));
-
- /* Buffer for the directive in the host character set (used when
- the source character set is different). */
- char hostdir[32];
-
- if (avail_range.min == avail_range.max)
- {
- /* The size of the destination region is exact. */
- unsigned HOST_WIDE_INT navail = avail_range.max;
-
- if (target_to_host (*dir.beg) != '%')
- {
- /* For plain character directives (i.e., the format string itself)
- but not others, point the caret at the first character that's
- past the end of the destination. */
- if (navail < dir.len)
- dirloc.set_caret_index (dirloc.get_caret_idx () + navail);
- }
-
- if (*dir.beg == '\0')
- {
- /* This is the terminating nul. */
- gcc_assert (res.min == 1 && res.min == res.max);
-
- return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%qE output may be truncated before the "
- "last format character")
- : G_("%qE output truncated before the last "
- "format character"))
- : (maybe
- ? G_("%qE may write a terminating nul past the "
- "end of the destination")
- : G_("%qE writing a terminating nul past the "
- "end of the destination")),
- info.func);
- }
-
- if (res.min == res.max)
- {
- const char *d = target_to_host (hostdir, sizeof hostdir, dir.beg);
- if (!info.bounded)
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive writing %wu byte into a "
- "region of size %wu",
- "%<%.*s%> directive writing %wu bytes into a "
- "region of size %wu",
- (int) dir.len, d, res.min, navail);
- else if (maybe)
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive output may be truncated "
- "writing %wu byte into a region of size %wu",
- "%<%.*s%> directive output may be truncated "
- "writing %wu bytes into a region of size %wu",
- (int) dir.len, d, res.min, navail);
- else
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive output truncated writing "
- "%wu byte into a region of size %wu",
- "%<%.*s%> directive output truncated writing "
- "%wu bytes into a region of size %wu",
- (int) dir.len, d, res.min, navail);
- }
- if (res.min == 0 && res.max < maxbytes)
- return fmtwarn (dirloc, argloc, NULL,
- info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing up to %wu bytes into a region of "
- "size %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "up to %wu bytes into a region of size %wu"))
- : G_("%<%.*s%> directive writing up to %wu bytes "
- "into a region of size %wu"), (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.max, navail);
-
- if (res.min == 0 && maxbytes <= res.max)
- /* This is a special case to avoid issuing the potentially
- confusing warning:
- writing 0 or more bytes into a region of size 0. */
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing likely %wu or more bytes into a "
- "region of size %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "likely %wu or more bytes into a region of "
- "size %wu"))
- : G_("%<%.*s%> directive writing likely %wu or more "
- "bytes into a region of size %wu"), (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.likely, navail);
-
- if (res.max < maxbytes)
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing between %wu and %wu bytes into a "
- "region of size %wu")
- : G_("%<%.*s%> directive output truncated "
- "writing between %wu and %wu bytes into a "
- "region of size %wu"))
- : G_("%<%.*s%> directive writing between %wu and "
- "%wu bytes into a region of size %wu"),
- (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.min, res.max, navail);
-
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing %wu or more bytes into a region of "
- "size %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "%wu or more bytes into a region of size %wu"))
- : G_("%<%.*s%> directive writing %wu or more bytes "
- "into a region of size %wu"), (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.min, navail);
- }
-
- /* The size of the destination region is a range. */
-
- if (target_to_host (*dir.beg) != '%')
- {
- unsigned HOST_WIDE_INT navail = avail_range.max;
-
- /* For plain character directives (i.e., the format string itself)
- but not others, point the caret at the first character that's
- past the end of the destination. */
- if (navail < dir.len)
- dirloc.set_caret_index (dirloc.get_caret_idx () + navail);
- }
-
- if (*dir.beg == '\0')
- {
- gcc_assert (res.min == 1 && res.min == res.max);
-
- return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%qE output may be truncated before the last "
- "format character")
- : G_("%qE output truncated before the last format "
- "character"))
- : (maybe
- ? G_("%qE may write a terminating nul past the end "
- "of the destination")
- : G_("%qE writing a terminating nul past the end "
- "of the destination")), info.func);
- }
-
- if (res.min == res.max)
- {
- const char *d = target_to_host (hostdir, sizeof hostdir, dir.beg);
- if (!info.bounded)
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive writing %wu byte into a region "
- "of size between %wu and %wu",
- "%<%.*s%> directive writing %wu bytes into a region "
- "of size between %wu and %wu", (int) dir.len, d,
- res.min, avail_range.min, avail_range.max);
- else if (maybe)
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive output may be truncated writing "
- "%wu byte into a region of size between %wu and %wu",
- "%<%.*s%> directive output may be truncated writing "
- "%wu bytes into a region of size between %wu and "
- "%wu", (int) dir.len, d, res.min, avail_range.min,
- avail_range.max);
- else
- return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min,
- "%<%.*s%> directive output truncated writing %wu "
- "byte into a region of size between %wu and %wu",
- "%<%.*s%> directive output truncated writing %wu "
- "bytes into a region of size between %wu and %wu",
- (int) dir.len, d, res.min, avail_range.min,
- avail_range.max);
- }
-
- if (res.min == 0 && res.max < maxbytes)
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing up to %wu bytes into a region of size "
- "between %wu and %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "up to %wu bytes into a region of size between "
- "%wu and %wu"))
- : G_("%<%.*s%> directive writing up to %wu bytes "
- "into a region of size between %wu and %wu"),
- (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.max, avail_range.min, avail_range.max);
-
- if (res.min == 0 && maxbytes <= res.max)
- /* This is a special case to avoid issuing the potentially confusing
- warning:
- writing 0 or more bytes into a region of size between 0 and N. */
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing likely %wu or more bytes into a region "
- "of size between %wu and %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "likely %wu or more bytes into a region of size "
- "between %wu and %wu"))
- : G_("%<%.*s%> directive writing likely %wu or more bytes "
- "into a region of size between %wu and %wu"),
- (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.likely, avail_range.min, avail_range.max);
-
- if (res.max < maxbytes)
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated "
- "writing between %wu and %wu bytes into a region "
- "of size between %wu and %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "between %wu and %wu bytes into a region of size "
- "between %wu and %wu"))
- : G_("%<%.*s%> directive writing between %wu and "
- "%wu bytes into a region of size between %wu and "
- "%wu"), (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.min, res.max, avail_range.min, avail_range.max);
-
- return fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- info.bounded
- ? (maybe
- ? G_("%<%.*s%> directive output may be truncated writing "
- "%wu or more bytes into a region of size between "
- "%wu and %wu")
- : G_("%<%.*s%> directive output truncated writing "
- "%wu or more bytes into a region of size between "
- "%wu and %wu"))
- : G_("%<%.*s%> directive writing %wu or more bytes "
- "into a region of size between %wu and %wu"),
- (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- res.min, avail_range.min, avail_range.max);
-}
-
-/* Given the formatting result described by RES and NAVAIL, the number
- of available bytes in the destination, return the range of bytes
- remaining in the destination. */
-
-static inline result_range
-bytes_remaining (unsigned HOST_WIDE_INT navail, const format_result &res)
-{
- result_range range;
-
- if (HOST_WIDE_INT_MAX <= navail)
- {
- range.min = range.max = range.likely = range.unlikely = navail;
- return range;
- }
-
- /* The lower bound of the available range is the available size
- minus the maximum output size, and the upper bound is the size
- minus the minimum. */
- range.max = res.range.min < navail ? navail - res.range.min : 0;
-
- range.likely = res.range.likely < navail ? navail - res.range.likely : 0;
-
- if (res.range.max < HOST_WIDE_INT_MAX)
- range.min = res.range.max < navail ? navail - res.range.max : 0;
- else
- range.min = range.likely;
-
- range.unlikely = (res.range.unlikely < navail
- ? navail - res.range.unlikely : 0);
-
- return range;
-}
-
-/* Compute the length of the output resulting from the directive DIR
- in a call described by INFO and update the overall result of the call
- in *RES. Return true if the directive has been handled. */
-
-static bool
-format_directive (const call_info &info,
- format_result *res, const directive &dir,
- range_query *query)
-{
- /* Offset of the beginning of the directive from the beginning
- of the format string. */
- size_t offset = dir.beg - info.fmtstr;
- size_t start = offset;
- size_t length = offset + dir.len - !!dir.len;
-
- /* Create a location for the whole directive from the % to the format
- specifier. */
- substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
- offset, start, length);
-
- /* Also get the location of the argument if possible.
- This doesn't work for integer literals or function calls. */
- location_t argloc = UNKNOWN_LOCATION;
- if (dir.arg)
- argloc = EXPR_LOCATION (dir.arg);
-
- /* Bail when there is no function to compute the output length,
- or when minimum length checking has been disabled. */
- if (!dir.fmtfunc || res->range.min >= HOST_WIDE_INT_MAX)
- return false;
-
- /* Compute the range of lengths of the formatted output. */
- fmtresult fmtres = dir.fmtfunc (dir, dir.arg, query);
-
- /* Record whether the output of all directives is known to be
- bounded by some maximum, implying that their arguments are
- either known exactly or determined to be in a known range
- or, for strings, limited by the upper bounds of the arrays
- they refer to. */
- res->knownrange &= fmtres.knownrange;
-
- if (!fmtres.knownrange)
- {
- /* Only when the range is known, check it against the host value
- of INT_MAX + (the number of bytes of the "%.*Lf" directive with
- INT_MAX precision, which is the longest possible output of any
- single directive). That's the largest valid byte count (though
- not valid call to a printf-like function because it can never
- return such a count). Otherwise, the range doesn't correspond
- to known values of the argument. */
- if (fmtres.range.max > target_dir_max ())
- {
- /* Normalize the MAX counter to avoid having to deal with it
- later. The counter can be less than HOST_WIDE_INT_M1U
- when compiling for an ILP32 target on an LP64 host. */
- fmtres.range.max = HOST_WIDE_INT_M1U;
- /* Disable exact and maximum length checking after a failure
- to determine the maximum number of characters (for example
- for wide characters or wide character strings) but continue
- tracking the minimum number of characters. */
- res->range.max = HOST_WIDE_INT_M1U;
- }
-
- if (fmtres.range.min > target_dir_max ())
- {
- /* Disable exact length checking after a failure to determine
- even the minimum number of characters (it shouldn't happen
- except in an error) but keep tracking the minimum and maximum
- number of characters. */
- return true;
- }
- }
-
- /* Buffer for the directive in the host character set (used when
- the source character set is different). */
- char hostdir[32];
-
- int dirlen = dir.len;
-
- if (fmtres.nullp)
- {
- fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive argument is null",
- dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg));
-
- /* Don't bother processing the rest of the format string. */
- res->warned = true;
- res->range.min = HOST_WIDE_INT_M1U;
- res->range.max = HOST_WIDE_INT_M1U;
- return false;
- }
-
- /* Compute the number of available bytes in the destination. There
- must always be at least one byte of space for the terminating
- NUL that's appended after the format string has been processed. */
- result_range avail_range = bytes_remaining (info.objsize, *res);
-
- /* If the argument aliases a part of the destination of the formatted
- call at offset FMTRES.DST_OFFSET append the directive and its result
- to the set of aliases for later processing. */
- if (fmtres.dst_offset != HOST_WIDE_INT_MIN)
- res->append_alias (dir, fmtres.dst_offset, fmtres.range);
-
- bool warned = res->warned;
-
- if (!warned)
- warned = maybe_warn (dirloc, argloc, info, avail_range,
- fmtres.range, dir);
-
- /* Bump up the total maximum if it isn't too big. */
- if (res->range.max < HOST_WIDE_INT_MAX
- && fmtres.range.max < HOST_WIDE_INT_MAX)
- res->range.max += fmtres.range.max;
-
- /* Raise the total unlikely maximum by the larger of the maximum
- and the unlikely maximum. */
- unsigned HOST_WIDE_INT save = res->range.unlikely;
- if (fmtres.range.max < fmtres.range.unlikely)
- res->range.unlikely += fmtres.range.unlikely;
- else
- res->range.unlikely += fmtres.range.max;
-
- if (res->range.unlikely < save)
- res->range.unlikely = HOST_WIDE_INT_M1U;
-
- res->range.min += fmtres.range.min;
- res->range.likely += fmtres.range.likely;
-
- /* Has the minimum directive output length exceeded the maximum
- of 4095 bytes required to be supported? */
- bool minunder4k = fmtres.range.min < 4096;
- bool maxunder4k = fmtres.range.max < 4096;
- /* Clear POSUNDER4K in the overall result if the maximum has exceeded
- the 4k (this is necessary to avoid the return value optimization
- that may not be safe in the maximum case). */
- if (!maxunder4k)
- res->posunder4k = false;
- /* Also clear POSUNDER4K if the directive may fail. */
- if (fmtres.mayfail)
- res->posunder4k = false;
-
- if (!warned
- /* Only warn at level 2. */
- && warn_level > 1
- /* Only warn for string functions. */
- && info.is_string_func ()
- && (!minunder4k
- || (!maxunder4k && fmtres.range.max < HOST_WIDE_INT_MAX)))
- {
- /* The directive output may be longer than the maximum required
- to be handled by an implementation according to 7.21.6.1, p15
- of C11. Warn on this only at level 2 but remember this and
- prevent folding the return value when done. This allows for
- the possibility of the actual libc call failing due to ENOMEM
- (like Glibc does with very large precision or width).
- Issue the "may exceed" warning only for string functions and
- not for fprintf or printf. */
-
- if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output of %wu bytes exceeds "
- "minimum required size of 4095", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min);
- else if (!minunder4k)
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output between %wu and %wu "
- "bytes exceeds minimum required size of 4095",
- dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min, fmtres.range.max);
- else if (!info.retval_used () && info.is_string_func ())
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output between %wu and %wu "
- "bytes may exceed minimum required size of "
- "4095",
- dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min, fmtres.range.max);
- }
-
- /* Has the likely and maximum directive output exceeded INT_MAX? */
- bool likelyximax = *dir.beg && res->range.likely > target_int_max ();
- /* Don't consider the maximum to be in excess when it's the result
- of a string of unknown length (i.e., whose maximum has been set
- to be greater than or equal to HOST_WIDE_INT_MAX. */
- bool maxximax = (*dir.beg
- && res->range.max > target_int_max ()
- && res->range.max < HOST_WIDE_INT_MAX);
-
- if (!warned
- /* Warn for the likely output size at level 1. */
- && (likelyximax
- /* But only warn for the maximum at level 2. */
- || (warn_level > 1
- && maxximax
- && fmtres.range.max < HOST_WIDE_INT_MAX)))
- {
- if (fmtres.range.min > target_int_max ())
- {
- /* The directive output exceeds INT_MAX bytes. */
- if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output of %wu bytes exceeds "
- "%<INT_MAX%>", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min);
- else
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output between %wu and "
- "%wu bytes exceeds %<INT_MAX%>", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min, fmtres.range.max);
- }
- else if (res->range.min > target_int_max ())
- {
- /* The directive output is under INT_MAX but causes the result
- to exceed INT_MAX bytes. */
- if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output of %wu bytes causes "
- "result to exceed %<INT_MAX%>", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min);
- else
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output between %wu and "
- "%wu bytes causes result to exceed %<INT_MAX%>",
- dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min, fmtres.range.max);
- }
- else if ((!info.retval_used () || !info.bounded)
- && (info.is_string_func ()))
- /* Warn for calls to string functions that either aren't bounded
- (sprintf) or whose return value isn't used. */
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive output between %wu and "
- "%wu bytes may cause result to exceed "
- "%<INT_MAX%>", dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg),
- fmtres.range.min, fmtres.range.max);
- }
-
- if (!warned && fmtres.nonstr)
- {
- warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
- "%<%.*s%> directive argument is not a nul-terminated "
- "string",
- dirlen,
- target_to_host (hostdir, sizeof hostdir, dir.beg));
- if (warned && DECL_P (fmtres.nonstr))
- inform (DECL_SOURCE_LOCATION (fmtres.nonstr),
- "referenced argument declared here");
- return false;
- }
-
- if (warned && fmtres.range.min < fmtres.range.likely
- && fmtres.range.likely < fmtres.range.max)
- inform_n (info.fmtloc, fmtres.range.likely,
- "assuming directive output of %wu byte",
- "assuming directive output of %wu bytes",
- fmtres.range.likely);
-
- if (warned && fmtres.argmin)
- {
- if (fmtres.argmin == fmtres.argmax)
- inform (info.fmtloc, "directive argument %qE", fmtres.argmin);
- else if (fmtres.knownrange)
- inform (info.fmtloc, "directive argument in the range [%E, %E]",
- fmtres.argmin, fmtres.argmax);
- else
- inform (info.fmtloc,
- "using the range [%E, %E] for directive argument",
- fmtres.argmin, fmtres.argmax);
- }
-
- res->warned |= warned;
-
- if (!dir.beg[0] && res->warned)
- {
- location_t callloc = gimple_location (info.callstmt);
-
- unsigned HOST_WIDE_INT min = res->range.min;
- unsigned HOST_WIDE_INT max = res->range.max;
-
- if (info.objsize < HOST_WIDE_INT_MAX)
- {
- /* If a warning has been issued for buffer overflow or truncation
- help the user figure out how big a buffer they need. */
-
- if (min == max)
- inform_n (callloc, min,
- "%qE output %wu byte into a destination of size %wu",
- "%qE output %wu bytes into a destination of size %wu",
- info.func, min, info.objsize);
- else if (max < HOST_WIDE_INT_MAX)
- inform (callloc,
- "%qE output between %wu and %wu bytes into "
- "a destination of size %wu",
- info.func, min, max, info.objsize);
- else if (min < res->range.likely && res->range.likely < max)
- inform (callloc,
- "%qE output %wu or more bytes (assuming %wu) into "
- "a destination of size %wu",
- info.func, min, res->range.likely, info.objsize);
- else
- inform (callloc,
- "%qE output %wu or more bytes into a destination of size "
- "%wu",
- info.func, min, info.objsize);
- }
- else if (!info.is_string_func ())
- {
- /* If the warning is for a file function like fprintf
- of printf with no destination size just print the computed
- result. */
- if (min == max)
- inform_n (callloc, min,
- "%qE output %wu byte", "%qE output %wu bytes",
- info.func, min);
- else if (max < HOST_WIDE_INT_MAX)
- inform (callloc,
- "%qE output between %wu and %wu bytes",
- info.func, min, max);
- else if (min < res->range.likely && res->range.likely < max)
- inform (callloc,
- "%qE output %wu or more bytes (assuming %wu)",
- info.func, min, res->range.likely);
- else
- inform (callloc,
- "%qE output %wu or more bytes",
- info.func, min);
- }
- }
-
- if (dump_file && *dir.beg)
- {
- fprintf (dump_file,
- " Result: "
- HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ", "
- HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC " ("
- HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ", "
- HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ")\n",
- fmtres.range.min, fmtres.range.likely,
- fmtres.range.max, fmtres.range.unlikely,
- res->range.min, res->range.likely,
- res->range.max, res->range.unlikely);
- }
-
- return true;
-}
-
-/* Parse a format directive in function call described by INFO starting
- at STR and populate DIR structure. Bump up *ARGNO by the number of
- arguments extracted for the directive. Return the length of
- the directive. */
-
-static size_t
-parse_directive (call_info &info,
- directive &dir, format_result *res,
- const char *str, unsigned *argno,
- range_query *query)
-{
- const char *pcnt = strchr (str, target_percent);
- dir.beg = str;
-
- if (size_t len = pcnt ? pcnt - str : *str ? strlen (str) : 1)
- {
- /* This directive is either a plain string or the terminating nul
- (which isn't really a directive but it simplifies things to
- handle it as if it were). */
- dir.len = len;
- dir.fmtfunc = format_plain;
-
- if (dump_file)
- {
- fprintf (dump_file, " Directive %u at offset "
- HOST_WIDE_INT_PRINT_UNSIGNED ": \"%.*s\", "
- "length = " HOST_WIDE_INT_PRINT_UNSIGNED "\n",
- dir.dirno,
- (unsigned HOST_WIDE_INT)(size_t)(dir.beg - info.fmtstr),
- (int)dir.len, dir.beg, (unsigned HOST_WIDE_INT) dir.len);
- }
-
- return len - !*str;
- }
-
- /* Set the directive argument's number to correspond to its position
- in the formatted function call's argument list. */
- dir.argno = *argno;
-
- const char *pf = pcnt + 1;
-
- /* POSIX numbered argument index or zero when none. */
- HOST_WIDE_INT dollar = 0;
-
- /* With and precision. -1 when not specified, HOST_WIDE_INT_MIN
- when given by a va_list argument, and a non-negative value
- when specified in the format string itself. */
- HOST_WIDE_INT width = -1;
- HOST_WIDE_INT precision = -1;
-
- /* Pointers to the beginning of the width and precision decimal
- string (if any) within the directive. */
- const char *pwidth = 0;
- const char *pprec = 0;
-
- /* When the value of the decimal string that specifies width or
- precision is out of range, points to the digit that causes
- the value to exceed the limit. */
- const char *werange = NULL;
- const char *perange = NULL;
-
- /* Width specified via the asterisk. Need not be INTEGER_CST.
- For vararg functions set to void_node. */
- tree star_width = NULL_TREE;
-
- /* Width specified via the asterisk. Need not be INTEGER_CST.
- For vararg functions set to void_node. */
- tree star_precision = NULL_TREE;
-
- if (ISDIGIT (target_to_host (*pf)))
- {
- /* This could be either a POSIX positional argument, the '0'
- flag, or a width, depending on what follows. Store it as
- width and sort it out later after the next character has
- been seen. */
- pwidth = pf;
- width = target_strtowi (&pf, &werange);
- }
- else if (target_to_host (*pf) == '*')
- {
- /* Similarly to the block above, this could be either a POSIX
- positional argument or a width, depending on what follows. */
- if (*argno < gimple_call_num_args (info.callstmt))
- star_width = gimple_call_arg (info.callstmt, (*argno)++);
- else
- star_width = void_node;
- ++pf;
- }
-
- if (target_to_host (*pf) == '$')
- {
- /* Handle the POSIX dollar sign which references the 1-based
- positional argument number. */
- if (width != -1)
- dollar = width + info.argidx;
- else if (star_width
- && TREE_CODE (star_width) == INTEGER_CST
- && (TYPE_PRECISION (TREE_TYPE (star_width))
- <= TYPE_PRECISION (integer_type_node)))
- dollar = width + tree_to_shwi (star_width);
-
- /* Bail when the numbered argument is out of range (it will
- have already been diagnosed by -Wformat). */
- if (dollar == 0
- || dollar == (int)info.argidx
- || dollar > gimple_call_num_args (info.callstmt))
- return false;
-
- --dollar;
-
- star_width = NULL_TREE;
- width = -1;
- ++pf;
- }
-
- if (dollar || !star_width)
- {
- if (width != -1)
- {
- if (width == 0)
- {
- /* The '0' that has been interpreted as a width above is
- actually a flag. Reset HAVE_WIDTH, set the '0' flag,
- and continue processing other flags. */
- width = -1;
- dir.set_flag ('0');
- }
- else if (!dollar)
- {
- /* (Non-zero) width has been seen. The next character
- is either a period or a digit. */
- goto start_precision;
- }
- }
- /* When either '$' has been seen, or width has not been seen,
- the next field is the optional flags followed by an optional
- width. */
- for ( ; ; ) {
- switch (target_to_host (*pf))
- {
- case ' ':
- case '0':
- case '+':
- case '-':
- case '#':
- dir.set_flag (target_to_host (*pf++));
- break;
-
- default:
- goto start_width;
- }
- }
-
- start_width:
- if (ISDIGIT (target_to_host (*pf)))
- {
- werange = 0;
- pwidth = pf;
- width = target_strtowi (&pf, &werange);
- }
- else if (target_to_host (*pf) == '*')
- {
- if (*argno < gimple_call_num_args (info.callstmt))
- star_width = gimple_call_arg (info.callstmt, (*argno)++);
- else
- {
- /* This is (likely) a va_list. It could also be an invalid
- call with insufficient arguments. */
- star_width = void_node;
- }
- ++pf;
- }
- else if (target_to_host (*pf) == '\'')
- {
- /* The POSIX apostrophe indicating a numeric grouping
- in the current locale. Even though it's possible to
- estimate the upper bound on the size of the output
- based on the number of digits it probably isn't worth
- continuing. */
- return 0;
- }
- }
-
- start_precision:
- if (target_to_host (*pf) == '.')
- {
- ++pf;
-
- if (ISDIGIT (target_to_host (*pf)))
- {
- pprec = pf;
- precision = target_strtowi (&pf, &perange);
- }
- else if (target_to_host (*pf) == '*')
- {
- if (*argno < gimple_call_num_args (info.callstmt))
- star_precision = gimple_call_arg (info.callstmt, (*argno)++);
- else
- {
- /* This is (likely) a va_list. It could also be an invalid
- call with insufficient arguments. */
- star_precision = void_node;
- }
- ++pf;
- }
- else
- {
- /* The decimal precision or the asterisk are optional.
- When neither is specified it's taken to be zero. */
- precision = 0;
- }
- }
-
- switch (target_to_host (*pf))
- {
- case 'h':
- if (target_to_host (pf[1]) == 'h')
- {
- ++pf;
- dir.modifier = FMT_LEN_hh;
- }
- else
- dir.modifier = FMT_LEN_h;
- ++pf;
- break;
-
- case 'j':
- dir.modifier = FMT_LEN_j;
- ++pf;
- break;
-
- case 'L':
- dir.modifier = FMT_LEN_L;
- ++pf;
- break;
-
- case 'l':
- if (target_to_host (pf[1]) == 'l')
- {
- ++pf;
- dir.modifier = FMT_LEN_ll;
- }
- else
- dir.modifier = FMT_LEN_l;
- ++pf;
- break;
-
- case 't':
- dir.modifier = FMT_LEN_t;
- ++pf;
- break;
-
- case 'z':
- dir.modifier = FMT_LEN_z;
- ++pf;
- break;
- }
-
- switch (target_to_host (*pf))
- {
- /* Handle a sole '%' character the same as "%%" but since it's
- undefined prevent the result from being folded. */
- case '\0':
- --pf;
- res->range.min = res->range.max = HOST_WIDE_INT_M1U;
- /* FALLTHRU */
- case '%':
- dir.fmtfunc = format_percent;
- break;
-
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- res->floating = true;
- dir.fmtfunc = format_floating;
- break;
-
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- dir.fmtfunc = format_integer;
- break;
-
- case 'p':
- /* The %p output is implementation-defined. It's possible
- to determine this format but due to extensions (especially
- those of the Linux kernel -- see bug 78512) the first %p
- in the format string disables any further processing. */
- return false;
-
- case 'n':
- /* %n has side-effects even when nothing is actually printed to
- any buffer. */
- info.nowrite = false;
- dir.fmtfunc = format_none;
- break;
-
- case 'C':
- case 'c':
- /* POSIX wide character and C/POSIX narrow character. */
- dir.fmtfunc = format_character;
- break;
-
- case 'S':
- case 's':
- /* POSIX wide string and C/POSIX narrow character string. */
- dir.fmtfunc = format_string;
- break;
-
- default:
- /* Unknown conversion specification. */
- return 0;
- }
-
- dir.specifier = target_to_host (*pf++);
-
- /* Store the length of the format directive. */
- dir.len = pf - pcnt;
-
- /* Buffer for the directive in the host character set (used when
- the source character set is different). */
- char hostdir[32];
-
- if (star_width)
- {
- if (INTEGRAL_TYPE_P (TREE_TYPE (star_width)))
- dir.set_width (star_width, query);
- else
- {
- /* Width specified by a va_list takes on the range [0, -INT_MIN]
- (width is the absolute value of that specified). */
- dir.width[0] = 0;
- dir.width[1] = target_int_max () + 1;
- }
- }
- else
- {
- if (width == HOST_WIDE_INT_MAX && werange)
- {
- size_t begin = dir.beg - info.fmtstr + (pwidth - pcnt);
- size_t caret = begin + (werange - pcnt);
- size_t end = pf - info.fmtstr - 1;
-
- /* Create a location for the width part of the directive,
- pointing the caret at the first out-of-range digit. */
- substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
- caret, begin, end);
-
- fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (),
- "%<%.*s%> directive width out of range", (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg));
- }
-
- dir.set_width (width);
- }
-
- if (star_precision)
- {
- if (INTEGRAL_TYPE_P (TREE_TYPE (star_precision)))
- dir.set_precision (star_precision, query);
- else
- {
- /* Precision specified by a va_list takes on the range [-1, INT_MAX]
- (unlike width, negative precision is ignored). */
- dir.prec[0] = -1;
- dir.prec[1] = target_int_max ();
- }
- }
- else
- {
- if (precision == HOST_WIDE_INT_MAX && perange)
- {
- size_t begin = dir.beg - info.fmtstr + (pprec - pcnt) - 1;
- size_t caret = dir.beg - info.fmtstr + (perange - pcnt) - 1;
- size_t end = pf - info.fmtstr - 2;
-
- /* Create a location for the precision part of the directive,
- including the leading period, pointing the caret at the first
- out-of-range digit . */
- substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
- caret, begin, end);
-
- fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (),
- "%<%.*s%> directive precision out of range", (int) dir.len,
- target_to_host (hostdir, sizeof hostdir, dir.beg));
- }
-
- dir.set_precision (precision);
- }
-
- /* Extract the argument if the directive takes one and if it's
- available (e.g., the function doesn't take a va_list). Treat
- missing arguments the same as va_list, even though they will
- have likely already been diagnosed by -Wformat. */
- if (dir.specifier != '%'
- && *argno < gimple_call_num_args (info.callstmt))
- dir.arg = gimple_call_arg (info.callstmt, dollar ? dollar : (*argno)++);
-
- if (dump_file)
- {
- fprintf (dump_file,
- " Directive %u at offset " HOST_WIDE_INT_PRINT_UNSIGNED
- ": \"%.*s\"",
- dir.dirno,
- (unsigned HOST_WIDE_INT)(size_t)(dir.beg - info.fmtstr),
- (int)dir.len, dir.beg);
- if (star_width)
- {
- if (dir.width[0] == dir.width[1])
- fprintf (dump_file, ", width = " HOST_WIDE_INT_PRINT_DEC,
- dir.width[0]);
- else
- fprintf (dump_file,
- ", width in range [" HOST_WIDE_INT_PRINT_DEC
- ", " HOST_WIDE_INT_PRINT_DEC "]",
- dir.width[0], dir.width[1]);
- }
-
- if (star_precision)
- {
- if (dir.prec[0] == dir.prec[1])
- fprintf (dump_file, ", precision = " HOST_WIDE_INT_PRINT_DEC,
- dir.prec[0]);
- else
- fprintf (dump_file,
- ", precision in range [" HOST_WIDE_INT_PRINT_DEC
- HOST_WIDE_INT_PRINT_DEC "]",
- dir.prec[0], dir.prec[1]);
- }
- fputc ('\n', dump_file);
- }
-
- return dir.len;
-}
-
-/* Diagnose overlap between destination and %s directive arguments. */
-
-static void
-maybe_warn_overlap (call_info &info, format_result *res)
-{
- /* Two vectors of 1-based indices corresponding to either certainly
- or possibly aliasing arguments. */
- auto_vec<int, 16> aliasarg[2];
-
- /* Go through the array of potentially aliasing directives and collect
- argument numbers of those that do or may overlap the destination
- object given the full result. */
- for (unsigned i = 0; i != res->alias_count; ++i)
- {
- const format_result::alias_info &alias = res->aliases[i];
-
- enum { possible = -1, none = 0, certain = 1 } overlap = none;
-
- /* If the precision is zero there is no overlap. (This only
- considers %s directives and ignores %n.) */
- if (alias.dir.prec[0] == 0 && alias.dir.prec[1] == 0)
- continue;
-
- if (alias.offset == HOST_WIDE_INT_MAX
- || info.dst_offset == HOST_WIDE_INT_MAX)
- overlap = possible;
- else if (alias.offset == info.dst_offset)
- overlap = alias.dir.prec[0] == 0 ? possible : certain;
- else
- {
- /* Determine overlap from the range of output and offsets
- into the same destination as the source, and rule out
- impossible overlap. */
- unsigned HOST_WIDE_INT albeg = alias.offset;
- unsigned HOST_WIDE_INT dstbeg = info.dst_offset;
-
- unsigned HOST_WIDE_INT alend = albeg + alias.range.min;
- unsigned HOST_WIDE_INT dstend = dstbeg + res->range.min - 1;
-
- if ((albeg <= dstbeg && alend > dstbeg)
- || (albeg >= dstbeg && albeg < dstend))
- overlap = certain;
- else
- {
- alend = albeg + alias.range.max;
- if (alend < albeg)
- alend = HOST_WIDE_INT_M1U;
-
- dstend = dstbeg + res->range.max - 1;
- if (dstend < dstbeg)
- dstend = HOST_WIDE_INT_M1U;
-
- if ((albeg >= dstbeg && albeg <= dstend)
- || (alend >= dstbeg && alend <= dstend))
- overlap = possible;
- }
- }
-
- if (overlap == none)
- continue;
-
- /* Append the 1-based argument number. */
- aliasarg[overlap != certain].safe_push (alias.dir.argno + 1);
-
- /* Disable any kind of optimization. */
- res->range.unlikely = HOST_WIDE_INT_M1U;
- }
-
- tree arg0 = gimple_call_arg (info.callstmt, 0);
- location_t loc = gimple_location (info.callstmt);
-
- bool aliaswarn = false;
-
- unsigned ncertain = aliasarg[0].length ();
- unsigned npossible = aliasarg[1].length ();
- if (ncertain && npossible)
- {
- /* If there are multiple arguments that overlap, some certainly
- and some possibly, handle both sets in a single diagnostic. */
- aliaswarn
- = warning_at (loc, OPT_Wrestrict,
- "%qE arguments %Z and maybe %Z overlap destination "
- "object %qE",
- info.func, aliasarg[0].address (), ncertain,
- aliasarg[1].address (), npossible,
- info.dst_origin);
- }
- else if (ncertain)
- {
- /* There is only one set of two or more arguments and they all
- certainly overlap the destination. */
- aliaswarn
- = warning_n (loc, OPT_Wrestrict, ncertain,
- "%qE argument %Z overlaps destination object %qE",
- "%qE arguments %Z overlap destination object %qE",
- info.func, aliasarg[0].address (), ncertain,
- info.dst_origin);
- }
- else if (npossible)
- {
- /* There is only one set of two or more arguments and they all
- may overlap (but need not). */
- aliaswarn
- = warning_n (loc, OPT_Wrestrict, npossible,
- "%qE argument %Z may overlap destination object %qE",
- "%qE arguments %Z may overlap destination object %qE",
- info.func, aliasarg[1].address (), npossible,
- info.dst_origin);
- }
-
- if (aliaswarn)
- {
- res->warned = true;
-
- if (info.dst_origin != arg0)
- {
- /* If its location is different from the first argument of the call
- point either at the destination object itself or at the expression
- that was used to determine the overlap. */
- loc = (DECL_P (info.dst_origin)
- ? DECL_SOURCE_LOCATION (info.dst_origin)
- : EXPR_LOCATION (info.dst_origin));
- if (loc != UNKNOWN_LOCATION)
- inform (loc,
- "destination object referenced by %<restrict%>-qualified "
- "argument 1 was declared here");
- }
- }
-}
-
-/* Compute the length of the output resulting from the call to a formatted
- output function described by INFO and store the result of the call in
- *RES. Issue warnings for detected past the end writes. Return true
- if the complete format string has been processed and *RES can be relied
- on, false otherwise (e.g., when a unknown or unhandled directive was seen
- that caused the processing to be terminated early). */
-
-static bool
-compute_format_length (call_info &info, format_result *res, range_query *query)
-{
- if (dump_file)
- {
- location_t callloc = gimple_location (info.callstmt);
- fprintf (dump_file, "%s:%i: ",
- LOCATION_FILE (callloc), LOCATION_LINE (callloc));
- print_generic_expr (dump_file, info.func, dump_flags);
-
- fprintf (dump_file,
- ": objsize = " HOST_WIDE_INT_PRINT_UNSIGNED
- ", fmtstr = \"%s\"\n",
- info.objsize, info.fmtstr);
- }
-
- /* Reset the minimum and maximum byte counters. */
- res->range.min = res->range.max = 0;
-
- /* No directive has been seen yet so the length of output is bounded
- by the known range [0, 0] (with no conversion resulting in a failure
- or producing more than 4K bytes) until determined otherwise. */
- res->knownrange = true;
- res->floating = false;
- res->warned = false;
-
- /* 1-based directive counter. */
- unsigned dirno = 1;
-
- /* The variadic argument counter. */
- unsigned argno = info.argidx;
-
- bool success = true;
-
- for (const char *pf = info.fmtstr; ; ++dirno)
- {
- directive dir (&info, dirno);
-
- size_t n = parse_directive (info, dir, res, pf, &argno, query);
-
- /* Return failure if the format function fails. */
- if (!format_directive (info, res, dir, query))
- return false;
-
- /* Return success when the directive is zero bytes long and it's
- the last thing in the format string (i.e., it's the terminating
- nul, which isn't really a directive but handling it as one makes
- things simpler). */
- if (!n)
- {
- success = *pf == '\0';
- break;
- }
-
- pf += n;
- }
-
- maybe_warn_overlap (info, res);
-
- /* The complete format string was processed (with or without warnings). */
- return success;
-}
-
-/* Return the size of the object referenced by the expression DEST in
- statement STMT, if available, or the maximum possible size otherwise. */
-
-static unsigned HOST_WIDE_INT
-get_destination_size (tree dest, gimple *stmt, pointer_query &ptr_qry)
-{
- /* When there is no destination return the maximum. */
- if (!dest)
- return HOST_WIDE_INT_MAX;
-
- /* Use compute_objsize to determine the size of the destination object. */
- access_ref aref;
- if (!ptr_qry.get_ref (dest, stmt, &aref))
- return HOST_WIDE_INT_MAX;
-
- offset_int remsize = aref.size_remaining ();
- if (!wi::fits_uhwi_p (remsize))
- return HOST_WIDE_INT_MAX;
-
- return remsize.to_uhwi ();
-}
-
-/* Return true if the call described by INFO with result RES safe to
- optimize (i.e., no undefined behavior), and set RETVAL to the range
- of its return values. */
-
-static bool
-is_call_safe (const call_info &info,
- const format_result &res, bool under4k,
- unsigned HOST_WIDE_INT retval[2])
-{
- if (under4k && !res.posunder4k)
- return false;
-
- /* The minimum return value. */
- retval[0] = res.range.min;
-
- /* The maximum return value is in most cases bounded by RES.RANGE.MAX
- but in cases involving multibyte characters could be as large as
- RES.RANGE.UNLIKELY. */
- retval[1]
- = res.range.unlikely < res.range.max ? res.range.max : res.range.unlikely;
-
- /* Adjust the number of bytes which includes the terminating nul
- to reflect the return value of the function which does not.
- Because the valid range of the function is [INT_MIN, INT_MAX],
- a valid range before the adjustment below is [0, INT_MAX + 1]
- (the functions only return negative values on error or undefined
- behavior). */
- if (retval[0] <= target_int_max () + 1)
- --retval[0];
- if (retval[1] <= target_int_max () + 1)
- --retval[1];
-
- /* Avoid the return value optimization when the behavior of the call
- is undefined either because any directive may have produced 4K or
- more of output, or the return value exceeds INT_MAX, or because
- the output overflows the destination object (but leave it enabled
- when the function is bounded because then the behavior is well-
- defined). */
- if (retval[0] == retval[1]
- && (info.bounded || retval[0] < info.objsize)
- && retval[0] <= target_int_max ())
- return true;
-
- if ((info.bounded || retval[1] < info.objsize)
- && (retval[0] < target_int_max ()
- && retval[1] < target_int_max ()))
- return true;
-
- if (!under4k && (info.bounded || retval[0] < info.objsize))
- return true;
-
- return false;
-}
-
-/* Given a suitable result RES of a call to a formatted output function
- described by INFO, substitute the result for the return value of
- the call. The result is suitable if the number of bytes it represents
- is known and exact. A result that isn't suitable for substitution may
- have its range set to the range of return values, if that is known.
- Return true if the call is removed and gsi_next should not be performed
- in the caller. */
-
-static bool
-try_substitute_return_value (gimple_stmt_iterator *gsi,
- const call_info &info,
- const format_result &res)
-{
- tree lhs = gimple_get_lhs (info.callstmt);
-
- /* Set to true when the entire call has been removed. */
- bool removed = false;
-
- /* The minimum and maximum return value. */
- unsigned HOST_WIDE_INT retval[2] = {0};
- bool safe = is_call_safe (info, res, true, retval);
-
- if (safe
- && retval[0] == retval[1]
- /* Not prepared to handle possibly throwing calls here; they shouldn't
- appear in non-artificial testcases, except when the __*_chk routines
- are badly declared. */
- && !stmt_ends_bb_p (info.callstmt))
- {
- tree cst = build_int_cst (lhs ? TREE_TYPE (lhs) : integer_type_node,
- retval[0]);
-
- if (lhs == NULL_TREE && info.nowrite)
- {
- /* Remove the call to the bounded function with a zero size
- (e.g., snprintf(0, 0, "%i", 123)) if there is no lhs. */
- unlink_stmt_vdef (info.callstmt);
- gsi_remove (gsi, true);
- removed = true;
- }
- else if (info.nowrite)
- {
- /* Replace the call to the bounded function with a zero size
- (e.g., snprintf(0, 0, "%i", 123) with the constant result
- of the function. */
- gimplify_and_update_call_from_tree (gsi, cst);
- gimple *callstmt = gsi_stmt (*gsi);
- update_stmt (callstmt);
- }
- else if (lhs)
- {
- /* Replace the left-hand side of the call with the constant
- result of the formatted function. */
- gimple_call_set_lhs (info.callstmt, NULL_TREE);
- gimple *g = gimple_build_assign (lhs, cst);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
- update_stmt (info.callstmt);
- }
-
- if (dump_file)
- {
- if (removed)
- fprintf (dump_file, " Removing call statement.");
- else
- {
- fprintf (dump_file, " Substituting ");
- print_generic_expr (dump_file, cst, dump_flags);
- fprintf (dump_file, " for %s.\n",
- info.nowrite ? "statement" : "return value");
- }
- }
- }
- else if (lhs && types_compatible_p (TREE_TYPE (lhs), integer_type_node))
- {
- bool setrange = false;
-
- if (safe
- && (info.bounded || retval[1] < info.objsize)
- && (retval[0] < target_int_max ()
- && retval[1] < target_int_max ()))
- {
- /* If the result is in a valid range bounded by the size of
- the destination set it so that it can be used for subsequent
- optimizations. */
- int prec = TYPE_PRECISION (integer_type_node);
-
- wide_int min = wi::shwi (retval[0], prec);
- wide_int max = wi::shwi (retval[1], prec);
- set_range_info (lhs, VR_RANGE, min, max);
-
- setrange = true;
- }
-
- if (dump_file)
- {
- const char *inbounds
- = (retval[0] < info.objsize
- ? (retval[1] < info.objsize
- ? "in" : "potentially out-of")
- : "out-of");
-
- const char *what = setrange ? "Setting" : "Discarding";
- if (retval[0] != retval[1])
- fprintf (dump_file,
- " %s %s-bounds return value range ["
- HOST_WIDE_INT_PRINT_UNSIGNED ", "
- HOST_WIDE_INT_PRINT_UNSIGNED "].\n",
- what, inbounds, retval[0], retval[1]);
- else
- fprintf (dump_file, " %s %s-bounds return value "
- HOST_WIDE_INT_PRINT_UNSIGNED ".\n",
- what, inbounds, retval[0]);
- }
- }
-
- if (dump_file)
- fputc ('\n', dump_file);
-
- return removed;
-}
-
-/* Try to simplify a s{,n}printf call described by INFO with result
- RES by replacing it with a simpler and presumably more efficient
- call (such as strcpy). */
-
-static bool
-try_simplify_call (gimple_stmt_iterator *gsi,
- const call_info &info,
- const format_result &res)
-{
- unsigned HOST_WIDE_INT dummy[2];
- if (!is_call_safe (info, res, info.retval_used (), dummy))
- return false;
-
- switch (info.fncode)
- {
- case BUILT_IN_SNPRINTF:
- return gimple_fold_builtin_snprintf (gsi);
-
- case BUILT_IN_SPRINTF:
- return gimple_fold_builtin_sprintf (gsi);
-
- default:
- ;
- }
-
- return false;
-}
-
-/* Return the zero-based index of the format string argument of a printf
- like function and set *IDX_ARGS to the first format argument. When
- no such index exists return UINT_MAX. */
-
-static unsigned
-get_user_idx_format (tree fndecl, unsigned *idx_args)
-{
- tree attrs = lookup_attribute ("format", DECL_ATTRIBUTES (fndecl));
- if (!attrs)
- attrs = lookup_attribute ("format", TYPE_ATTRIBUTES (TREE_TYPE (fndecl)));
-
- if (!attrs)
- return UINT_MAX;
-
- attrs = TREE_VALUE (attrs);
-
- tree archetype = TREE_VALUE (attrs);
- if (strcmp ("printf", IDENTIFIER_POINTER (archetype)))
- return UINT_MAX;
-
- attrs = TREE_CHAIN (attrs);
- tree fmtarg = TREE_VALUE (attrs);
-
- attrs = TREE_CHAIN (attrs);
- tree elliparg = TREE_VALUE (attrs);
-
- /* Attribute argument indices are 1-based but we use zero-based. */
- *idx_args = tree_to_uhwi (elliparg) - 1;
- return tree_to_uhwi (fmtarg) - 1;
-}
-
-} /* Unnamed namespace. */
-
-/* Determine if a GIMPLE call at *GSI is to one of the sprintf-like built-in
- functions and if so, handle it. Return true if the call is removed and
- gsi_next should not be performed in the caller. */
-
-bool
-handle_printf_call (gimple_stmt_iterator *gsi, pointer_query &ptr_qry)
-{
- init_target_to_host_charmap ();
-
- call_info info = call_info ();
-
- info.callstmt = gsi_stmt (*gsi);
- info.func = gimple_call_fndecl (info.callstmt);
- if (!info.func)
- return false;
-
- /* Format string argument number (valid for all functions). */
- unsigned idx_format = UINT_MAX;
- if (gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL))
- info.fncode = DECL_FUNCTION_CODE (info.func);
- else
- {
- unsigned idx_args;
- idx_format = get_user_idx_format (info.func, &idx_args);
- if (idx_format == UINT_MAX
- || idx_format >= gimple_call_num_args (info.callstmt)
- || idx_args > gimple_call_num_args (info.callstmt)
- || !POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (info.callstmt,
- idx_format))))
- return false;
- info.fncode = BUILT_IN_NONE;
- info.argidx = idx_args;
- }
-
- /* The size of the destination as in snprintf(dest, size, ...). */
- unsigned HOST_WIDE_INT dstsize = HOST_WIDE_INT_M1U;
-
- /* The size of the destination determined by __builtin_object_size. */
- unsigned HOST_WIDE_INT objsize = HOST_WIDE_INT_M1U;
-
- /* Zero-based buffer size argument number (snprintf and vsnprintf). */
- unsigned idx_dstsize = UINT_MAX;
-
- /* Object size argument number (snprintf_chk and vsnprintf_chk). */
- unsigned idx_objsize = UINT_MAX;
-
- /* Destinaton argument number (valid for sprintf functions only). */
- unsigned idx_dstptr = 0;
-
- switch (info.fncode)
- {
- case BUILT_IN_NONE:
- // User-defined function with attribute format (printf).
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_FPRINTF:
- // Signature:
- // __builtin_fprintf (FILE*, format, ...)
- idx_format = 1;
- info.argidx = 2;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_FPRINTF_CHK:
- // Signature:
- // __builtin_fprintf_chk (FILE*, ost, format, ...)
- idx_format = 2;
- info.argidx = 3;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_FPRINTF_UNLOCKED:
- // Signature:
- // __builtin_fprintf_unnlocked (FILE*, format, ...)
- idx_format = 1;
- info.argidx = 2;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_PRINTF:
- // Signature:
- // __builtin_printf (format, ...)
- idx_format = 0;
- info.argidx = 1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_PRINTF_CHK:
- // Signature:
- // __builtin_printf_chk (ost, format, ...)
- idx_format = 1;
- info.argidx = 2;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_PRINTF_UNLOCKED:
- // Signature:
- // __builtin_printf (format, ...)
- idx_format = 0;
- info.argidx = 1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_SPRINTF:
- // Signature:
- // __builtin_sprintf (dst, format, ...)
- idx_format = 1;
- info.argidx = 2;
- break;
-
- case BUILT_IN_SPRINTF_CHK:
- // Signature:
- // __builtin___sprintf_chk (dst, ost, objsize, format, ...)
- idx_objsize = 2;
- idx_format = 3;
- info.argidx = 4;
- break;
-
- case BUILT_IN_SNPRINTF:
- // Signature:
- // __builtin_snprintf (dst, size, format, ...)
- idx_dstsize = 1;
- idx_format = 2;
- info.argidx = 3;
- info.bounded = true;
- break;
-
- case BUILT_IN_SNPRINTF_CHK:
- // Signature:
- // __builtin___snprintf_chk (dst, size, ost, objsize, format, ...)
- idx_dstsize = 1;
- idx_objsize = 3;
- idx_format = 4;
- info.argidx = 5;
- info.bounded = true;
- break;
-
- case BUILT_IN_VFPRINTF:
- // Signature:
- // __builtin_vprintf (FILE*, format, va_list)
- idx_format = 1;
- info.argidx = -1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_VFPRINTF_CHK:
- // Signature:
- // __builtin___vfprintf_chk (FILE*, ost, format, va_list)
- idx_format = 2;
- info.argidx = -1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_VPRINTF:
- // Signature:
- // __builtin_vprintf (format, va_list)
- idx_format = 0;
- info.argidx = -1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_VPRINTF_CHK:
- // Signature:
- // __builtin___vprintf_chk (ost, format, va_list)
- idx_format = 1;
- info.argidx = -1;
- idx_dstptr = -1;
- break;
-
- case BUILT_IN_VSNPRINTF:
- // Signature:
- // __builtin_vsprintf (dst, size, format, va)
- idx_dstsize = 1;
- idx_format = 2;
- info.argidx = -1;
- info.bounded = true;
- break;
-
- case BUILT_IN_VSNPRINTF_CHK:
- // Signature:
- // __builtin___vsnprintf_chk (dst, size, ost, objsize, format, va)
- idx_dstsize = 1;
- idx_objsize = 3;
- idx_format = 4;
- info.argidx = -1;
- info.bounded = true;
- break;
-
- case BUILT_IN_VSPRINTF:
- // Signature:
- // __builtin_vsprintf (dst, format, va)
- idx_format = 1;
- info.argidx = -1;
- break;
-
- case BUILT_IN_VSPRINTF_CHK:
- // Signature:
- // __builtin___vsprintf_chk (dst, ost, objsize, format, va)
- idx_format = 3;
- idx_objsize = 2;
- info.argidx = -1;
- break;
-
- default:
- return false;
- }
-
- /* Set the global warning level for this function. */
- warn_level = info.bounded ? warn_format_trunc : warn_format_overflow;
-
- /* For all string functions the first argument is a pointer to
- the destination. */
- tree dstptr = (idx_dstptr < gimple_call_num_args (info.callstmt)
- ? gimple_call_arg (info.callstmt, 0) : NULL_TREE);
-
- info.format = gimple_call_arg (info.callstmt, idx_format);
-
- /* True when the destination size is constant as opposed to the lower
- or upper bound of a range. */
- bool dstsize_cst_p = true;
- bool posunder4k = true;
-
- if (idx_dstsize == UINT_MAX)
- {
- /* For non-bounded functions like sprintf, determine the size
- of the destination from the object or pointer passed to it
- as the first argument. */
- dstsize = get_destination_size (dstptr, info.callstmt, ptr_qry);
- }
- else if (tree size = gimple_call_arg (info.callstmt, idx_dstsize))
- {
- /* For bounded functions try to get the size argument. */
-
- if (TREE_CODE (size) == INTEGER_CST)
- {
- dstsize = tree_to_uhwi (size);
- /* No object can be larger than SIZE_MAX bytes (half the address
- space) on the target.
- The functions are defined only for output of at most INT_MAX
- bytes. Specifying a bound in excess of that limit effectively
- defeats the bounds checking (and on some implementations such
- as Solaris cause the function to fail with EINVAL). */
- if (dstsize > target_size_max () / 2)
- {
- /* Avoid warning if -Wstringop-overflow is specified since
- it also warns for the same thing though only for the
- checking built-ins. */
- if ((idx_objsize == UINT_MAX
- || !warn_stringop_overflow))
- warning_at (gimple_location (info.callstmt), info.warnopt (),
- "specified bound %wu exceeds maximum object size "
- "%wu",
- dstsize, target_size_max () / 2);
- /* POSIX requires snprintf to fail if DSTSIZE is greater
- than INT_MAX. Even though not all POSIX implementations
- conform to the requirement, avoid folding in this case. */
- posunder4k = false;
- }
- else if (dstsize > target_int_max ())
- {
- warning_at (gimple_location (info.callstmt), info.warnopt (),
- "specified bound %wu exceeds %<INT_MAX%>",
- dstsize);
- /* POSIX requires snprintf to fail if DSTSIZE is greater
- than INT_MAX. Avoid folding in that case. */
- posunder4k = false;
- }
- }
- else if (TREE_CODE (size) == SSA_NAME)
- {
- /* Try to determine the range of values of the argument
- and use the greater of the two at level 1 and the smaller
- of them at level 2. */
- value_range vr;
- ptr_qry.rvals->range_of_expr (vr, size, info.callstmt);
-
- if (!vr.undefined_p ())
- {
- tree type = TREE_TYPE (size);
- tree tmin = wide_int_to_tree (type, vr.lower_bound ());
- tree tmax = wide_int_to_tree (type, vr.upper_bound ());
- unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (tmin);
- unsigned HOST_WIDE_INT maxsize = TREE_INT_CST_LOW (tmax);
- dstsize = warn_level < 2 ? maxsize : minsize;
-
- if (minsize > target_int_max ())
- warning_at (gimple_location (info.callstmt), info.warnopt (),
- "specified bound range [%wu, %wu] exceeds "
- "%<INT_MAX%>",
- minsize, maxsize);
-
- /* POSIX requires snprintf to fail if DSTSIZE is greater
- than INT_MAX. Avoid folding if that's possible. */
- if (maxsize > target_int_max ())
- posunder4k = false;
- }
-
- /* The destination size is not constant. If the function is
- bounded (e.g., snprintf) a lower bound of zero doesn't
- necessarily imply it can be eliminated. */
- dstsize_cst_p = false;
- }
- }
-
- if (idx_objsize != UINT_MAX)
- if (tree size = gimple_call_arg (info.callstmt, idx_objsize))
- if (tree_fits_uhwi_p (size))
- objsize = tree_to_uhwi (size);
-
- if (info.bounded && !dstsize)
- {
- /* As a special case, when the explicitly specified destination
- size argument (to a bounded function like snprintf) is zero
- it is a request to determine the number of bytes on output
- without actually producing any. Pretend the size is
- unlimited in this case. */
- info.objsize = HOST_WIDE_INT_MAX;
- info.nowrite = dstsize_cst_p;
- }
- else
- {
- /* For calls to non-bounded functions or to those of bounded
- functions with a non-zero size, warn if the destination
- pointer is null. */
- if (dstptr && integer_zerop (dstptr))
- {
- /* This is diagnosed with -Wformat only when the null is a constant
- pointer. The warning here diagnoses instances where the pointer
- is not constant. */
- location_t loc = gimple_location (info.callstmt);
- warning_at (EXPR_LOC_OR_LOC (dstptr, loc),
- info.warnopt (), "null destination pointer");
- return false;
- }
-
- /* Set the object size to the smaller of the two arguments
- of both have been specified and they're not equal. */
- info.objsize = dstsize < objsize ? dstsize : objsize;
-
- if (info.bounded
- && dstsize < target_size_max () / 2 && objsize < dstsize
- /* Avoid warning if -Wstringop-overflow is specified since
- it also warns for the same thing though only for the
- checking built-ins. */
- && (idx_objsize == UINT_MAX
- || !warn_stringop_overflow))
- {
- warning_at (gimple_location (info.callstmt), info.warnopt (),
- "specified bound %wu exceeds the size %wu "
- "of the destination object", dstsize, objsize);
- }
- }
-
- /* Determine if the format argument may be null and warn if not
- and if the argument is null. */
- if (integer_zerop (info.format)
- && gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL))
- {
- location_t loc = gimple_location (info.callstmt);
- warning_at (EXPR_LOC_OR_LOC (info.format, loc),
- info.warnopt (), "null format string");
- return false;
- }
-
- info.fmtstr = get_format_string (info.format, &info.fmtloc);
- if (!info.fmtstr)
- return false;
-
- if (warn_restrict)
- {
- /* Compute the origin of the destination pointer and its offset
- from the base object/pointer if possible. */
- info.dst_offset = 0;
- info.dst_origin = get_origin_and_offset (dstptr, &info.dst_field,
- &info.dst_offset);
- }
-
- /* The result is the number of bytes output by the formatted function,
- including the terminating NUL. */
- format_result res;
-
- /* I/O functions with no destination argument (i.e., all forms of fprintf
- and printf) may fail under any conditions. Others (i.e., all forms of
- sprintf) may only fail under specific conditions determined for each
- directive. Clear POSUNDER4K for the former set of functions and set
- it to true for the latter (it can only be cleared later, but it is
- never set to true again). */
- res.posunder4k = posunder4k && dstptr;
-
- bool success = compute_format_length (info, &res, ptr_qry.rvals);
- if (res.warned)
- suppress_warning (info.callstmt, info.warnopt ());
-
- /* When optimizing and the printf return value optimization is enabled,
- attempt to substitute the computed result for the return value of
- the call. Avoid this optimization when -frounding-math is in effect
- and the format string contains a floating point directive. */
- bool call_removed = false;
- if (success && optimize > 0)
- {
- /* Save a copy of the iterator pointing at the call. The iterator
- may change to point past the call in try_substitute_return_value
- but the original value is needed in try_simplify_call. */
- gimple_stmt_iterator gsi_call = *gsi;
-
- if (flag_printf_return_value
- && (!flag_rounding_math || !res.floating))
- call_removed = try_substitute_return_value (gsi, info, res);
-
- if (!call_removed)
- try_simplify_call (&gsi_call, info, res);
- }
-
- return call_removed;
-}